1 //===-- PlatformiOSSimulator.cpp -----------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "PlatformiOSSimulator.h"
11
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Breakpoint/BreakpointLocation.h"
17 #include "lldb/Core/ArchSpec.h"
18 #include "lldb/Core/Error.h"
19 #include "lldb/Core/Module.h"
20 #include "lldb/Core/ModuleList.h"
21 #include "lldb/Core/ModuleSpec.h"
22 #include "lldb/Core/PluginManager.h"
23 #include "lldb/Core/StreamString.h"
24 #include "lldb/Host/FileSpec.h"
25 #include "lldb/Host/Host.h"
26 #include "lldb/Target/Process.h"
27 #include "lldb/Target/Target.h"
28
29 using namespace lldb;
30 using namespace lldb_private;
31
32 //------------------------------------------------------------------
33 // Static Variables
34 //------------------------------------------------------------------
35 static uint32_t g_initialize_count = 0;
36
37 //------------------------------------------------------------------
38 // Static Functions
39 //------------------------------------------------------------------
40 void
Initialize()41 PlatformiOSSimulator::Initialize ()
42 {
43 if (g_initialize_count++ == 0)
44 {
45 PluginManager::RegisterPlugin (PlatformiOSSimulator::GetPluginNameStatic(),
46 PlatformiOSSimulator::GetDescriptionStatic(),
47 PlatformiOSSimulator::CreateInstance);
48 }
49 }
50
51 void
Terminate()52 PlatformiOSSimulator::Terminate ()
53 {
54 if (g_initialize_count > 0)
55 {
56 if (--g_initialize_count == 0)
57 {
58 PluginManager::UnregisterPlugin (PlatformiOSSimulator::CreateInstance);
59 }
60 }
61 }
62
63 Platform*
CreateInstance(bool force,const ArchSpec * arch)64 PlatformiOSSimulator::CreateInstance (bool force, const ArchSpec *arch)
65 {
66 bool create = force;
67 if (create == false && arch && arch->IsValid())
68 {
69 switch (arch->GetMachine())
70 {
71 // Currently simulator is i386 only...
72 case llvm::Triple::x86:
73 {
74 const llvm::Triple &triple = arch->GetTriple();
75 switch (triple.getVendor())
76 {
77 case llvm::Triple::Apple:
78 create = true;
79 break;
80
81 #if defined(__APPLE__)
82 // Only accept "unknown" for the vendor if the host is Apple and
83 // it "unknown" wasn't specified (it was just returned becasue it
84 // was NOT specified)
85 case llvm::Triple::UnknownArch:
86 create = !arch->TripleVendorWasSpecified();
87 break;
88 #endif
89 default:
90 break;
91 }
92
93 if (create)
94 {
95 switch (triple.getOS())
96 {
97 case llvm::Triple::Darwin: // Deprecated, but still support Darwin for historical reasons
98 case llvm::Triple::MacOSX:
99 case llvm::Triple::IOS: // IOS is not used for simulator triples, but accept it just in case
100 break;
101
102 #if defined(__APPLE__)
103 // Only accept "unknown" for the OS if the host is Apple and
104 // it "unknown" wasn't specified (it was just returned becasue it
105 // was NOT specified)
106 case llvm::Triple::UnknownOS:
107 create = !arch->TripleOSWasSpecified();
108 break;
109 #endif
110 default:
111 create = false;
112 break;
113 }
114 }
115 }
116 break;
117 default:
118 break;
119 }
120 }
121 if (create)
122 return new PlatformiOSSimulator ();
123 return NULL;
124 }
125
126
127 lldb_private::ConstString
GetPluginNameStatic()128 PlatformiOSSimulator::GetPluginNameStatic ()
129 {
130 static ConstString g_name("ios-simulator");
131 return g_name;
132 }
133
134 const char *
GetDescriptionStatic()135 PlatformiOSSimulator::GetDescriptionStatic()
136 {
137 return "iOS simulator platform plug-in.";
138 }
139
140
141 //------------------------------------------------------------------
142 /// Default Constructor
143 //------------------------------------------------------------------
PlatformiOSSimulator()144 PlatformiOSSimulator::PlatformiOSSimulator () :
145 PlatformDarwin (true),
146 m_sdk_directory ()
147 {
148 }
149
150 //------------------------------------------------------------------
151 /// Destructor.
152 ///
153 /// The destructor is virtual since this class is designed to be
154 /// inherited from by the plug-in instance.
155 //------------------------------------------------------------------
~PlatformiOSSimulator()156 PlatformiOSSimulator::~PlatformiOSSimulator()
157 {
158 }
159
160
161 void
GetStatus(Stream & strm)162 PlatformiOSSimulator::GetStatus (Stream &strm)
163 {
164 Platform::GetStatus (strm);
165 const char *sdk_directory = GetSDKDirectory();
166 if (sdk_directory)
167 strm.Printf (" SDK Path: \"%s\"\n", sdk_directory);
168 else
169 strm.PutCString (" SDK Path: error: unable to locate SDK\n");
170 }
171
172
173 Error
ResolveExecutable(const FileSpec & exe_file,const ArchSpec & exe_arch,lldb::ModuleSP & exe_module_sp,const FileSpecList * module_search_paths_ptr)174 PlatformiOSSimulator::ResolveExecutable (const FileSpec &exe_file,
175 const ArchSpec &exe_arch,
176 lldb::ModuleSP &exe_module_sp,
177 const FileSpecList *module_search_paths_ptr)
178 {
179 Error error;
180 // Nothing special to do here, just use the actual file and architecture
181
182 FileSpec resolved_exe_file (exe_file);
183
184 // If we have "ls" as the exe_file, resolve the executable loation based on
185 // the current path variables
186 // TODO: resolve bare executables in the Platform SDK
187 // if (!resolved_exe_file.Exists())
188 // resolved_exe_file.ResolveExecutableLocation ();
189
190 // Resolve any executable within a bundle on MacOSX
191 // TODO: verify that this handles shallow bundles, if not then implement one ourselves
192 Host::ResolveExecutableInBundle (resolved_exe_file);
193
194 if (resolved_exe_file.Exists())
195 {
196 ModuleSpec module_spec(resolved_exe_file, exe_arch);
197 if (exe_arch.IsValid())
198 {
199 error = ModuleList::GetSharedModule (module_spec,
200 exe_module_sp,
201 NULL,
202 NULL,
203 NULL);
204
205 if (exe_module_sp && exe_module_sp->GetObjectFile())
206 return error;
207 exe_module_sp.reset();
208 }
209 // No valid architecture was specified or the exact ARM slice wasn't
210 // found so ask the platform for the architectures that we should be
211 // using (in the correct order) and see if we can find a match that way
212 StreamString arch_names;
213 ArchSpec platform_arch;
214 for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, module_spec.GetArchitecture()); ++idx)
215 {
216
217 error = ModuleList::GetSharedModule (module_spec,
218 exe_module_sp,
219 NULL,
220 NULL,
221 NULL);
222 // Did we find an executable using one of the
223 if (error.Success())
224 {
225 if (exe_module_sp && exe_module_sp->GetObjectFile())
226 break;
227 else
228 error.SetErrorToGenericError();
229 }
230
231 if (idx > 0)
232 arch_names.PutCString (", ");
233 arch_names.PutCString (platform_arch.GetArchitectureName());
234 }
235
236 if (error.Fail() || !exe_module_sp)
237 {
238 error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
239 exe_file.GetPath().c_str(),
240 GetPluginName().GetCString(),
241 arch_names.GetString().c_str());
242 }
243 }
244 else
245 {
246 error.SetErrorStringWithFormat ("'%s' does not exist",
247 exe_file.GetPath().c_str());
248 }
249
250 return error;
251 }
252
253 static FileSpec::EnumerateDirectoryResult
EnumerateDirectoryCallback(void * baton,FileSpec::FileType file_type,const FileSpec & file_spec)254 EnumerateDirectoryCallback (void *baton, FileSpec::FileType file_type, const FileSpec &file_spec)
255 {
256 if (file_type == FileSpec::eFileTypeDirectory)
257 {
258 const char *filename = file_spec.GetFilename().GetCString();
259 if (filename && strncmp(filename, "iPhoneSimulator", strlen ("iPhoneSimulator")) == 0)
260 {
261 ::snprintf ((char *)baton, PATH_MAX, "%s", filename);
262 return FileSpec::eEnumerateDirectoryResultQuit;
263 }
264 }
265 return FileSpec::eEnumerateDirectoryResultNext;
266 }
267
268
269
270 const char *
GetSDKDirectory()271 PlatformiOSSimulator::GetSDKDirectory()
272 {
273 if (m_sdk_directory.empty())
274 {
275 const char *developer_dir = GetDeveloperDirectory();
276 if (developer_dir)
277 {
278 char sdks_directory[PATH_MAX];
279 char sdk_dirname[PATH_MAX];
280 sdk_dirname[0] = '\0';
281 snprintf (sdks_directory,
282 sizeof(sdks_directory),
283 "%s/Platforms/iPhoneSimulator.platform/Developer/SDKs",
284 developer_dir);
285 FileSpec simulator_sdk_spec;
286 bool find_directories = true;
287 bool find_files = false;
288 bool find_other = false;
289 FileSpec::EnumerateDirectory (sdks_directory,
290 find_directories,
291 find_files,
292 find_other,
293 EnumerateDirectoryCallback,
294 sdk_dirname);
295
296 if (sdk_dirname[0])
297 {
298 m_sdk_directory = sdks_directory;
299 m_sdk_directory.append (1, '/');
300 m_sdk_directory.append (sdk_dirname);
301 return m_sdk_directory.c_str();
302 }
303 }
304 // Assign a single NULL character so we know we tried to find the device
305 // support directory and we don't keep trying to find it over and over.
306 m_sdk_directory.assign (1, '\0');
307 }
308
309 // We should have put a single NULL character into m_sdk_directory
310 // or it should have a valid path if the code gets here
311 assert (m_sdk_directory.empty() == false);
312 if (m_sdk_directory[0])
313 return m_sdk_directory.c_str();
314 return NULL;
315 }
316
317 Error
GetFile(const FileSpec & platform_file,const UUID * uuid_ptr,FileSpec & local_file)318 PlatformiOSSimulator::GetFile (const FileSpec &platform_file,
319 const UUID *uuid_ptr,
320 FileSpec &local_file)
321 {
322 Error error;
323 char platform_file_path[PATH_MAX];
324 if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path)))
325 {
326 char resolved_path[PATH_MAX];
327
328 const char * sdk_dir = GetSDKDirectory();
329 if (sdk_dir)
330 {
331 ::snprintf (resolved_path,
332 sizeof(resolved_path),
333 "%s/%s",
334 sdk_dir,
335 platform_file_path);
336
337 // First try in the SDK and see if the file is in there
338 local_file.SetFile(resolved_path, true);
339 if (local_file.Exists())
340 return error;
341
342 // Else fall back to the actual path itself
343 local_file.SetFile(platform_file_path, true);
344 if (local_file.Exists())
345 return error;
346
347 }
348 error.SetErrorStringWithFormat ("unable to locate a platform file for '%s' in platform '%s'",
349 platform_file_path,
350 GetPluginName().GetCString());
351 }
352 else
353 {
354 error.SetErrorString ("invalid platform file argument");
355 }
356 return error;
357 }
358
359 Error
GetSharedModule(const ModuleSpec & module_spec,ModuleSP & module_sp,const FileSpecList * module_search_paths_ptr,ModuleSP * old_module_sp_ptr,bool * did_create_ptr)360 PlatformiOSSimulator::GetSharedModule (const ModuleSpec &module_spec,
361 ModuleSP &module_sp,
362 const FileSpecList *module_search_paths_ptr,
363 ModuleSP *old_module_sp_ptr,
364 bool *did_create_ptr)
365 {
366 // For iOS, the SDK files are all cached locally on the host
367 // system. So first we ask for the file in the cached SDK,
368 // then we attempt to get a shared module for the right architecture
369 // with the right UUID.
370 Error error;
371 FileSpec local_file;
372 const FileSpec &platform_file = module_spec.GetFileSpec();
373 error = GetFile (platform_file, module_spec.GetUUIDPtr(), local_file);
374 if (error.Success())
375 {
376 error = ResolveExecutable (local_file, module_spec.GetArchitecture(), module_sp, module_search_paths_ptr);
377 }
378 else
379 {
380 const bool always_create = false;
381 error = ModuleList::GetSharedModule (module_spec,
382 module_sp,
383 module_search_paths_ptr,
384 old_module_sp_ptr,
385 did_create_ptr,
386 always_create);
387
388 }
389 if (module_sp)
390 module_sp->SetPlatformFileSpec(platform_file);
391
392 return error;
393 }
394
395
396 uint32_t
FindProcesses(const ProcessInstanceInfoMatch & match_info,ProcessInstanceInfoList & process_infos)397 PlatformiOSSimulator::FindProcesses (const ProcessInstanceInfoMatch &match_info,
398 ProcessInstanceInfoList &process_infos)
399 {
400 // TODO: if connected, send a packet to get the remote process infos by name
401 process_infos.Clear();
402 return 0;
403 }
404
405 bool
GetSupportedArchitectureAtIndex(uint32_t idx,ArchSpec & arch)406 PlatformiOSSimulator::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
407 {
408 if (idx == 0)
409 {
410 // All iOS simulator binaries are currently i386
411 arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture32);
412 return arch.IsValid();
413 }
414 return false;
415 }
416