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