1 //===-- PlatformRemoteiOS.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 "PlatformRemoteiOS.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/PluginManager.h"
22 #include "lldb/Core/StreamString.h"
23 #include "lldb/Host/FileSpec.h"
24 #include "lldb/Host/Host.h"
25 #include "lldb/Target/Process.h"
26 #include "lldb/Target/Target.h"
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 //------------------------------------------------------------------
32 // Static Variables
33 //------------------------------------------------------------------
34 static uint32_t g_initialize_count = 0;
35 
36 //------------------------------------------------------------------
37 // Static Functions
38 //------------------------------------------------------------------
39 void
40 PlatformRemoteiOS::Initialize ()
41 {
42     if (g_initialize_count++ == 0)
43     {
44         PluginManager::RegisterPlugin (PlatformRemoteiOS::GetShortPluginNameStatic(),
45                                        PlatformRemoteiOS::GetDescriptionStatic(),
46                                        PlatformRemoteiOS::CreateInstance);
47     }
48 }
49 
50 void
51 PlatformRemoteiOS::Terminate ()
52 {
53     if (g_initialize_count > 0)
54     {
55         if (--g_initialize_count == 0)
56         {
57             PluginManager::UnregisterPlugin (PlatformRemoteiOS::CreateInstance);
58         }
59     }
60 }
61 
62 Platform*
63 PlatformRemoteiOS::CreateInstance (bool force, const ArchSpec *arch)
64 {
65     bool create = force;
66     if (create == false && arch && arch->IsValid())
67     {
68         switch (arch->GetMachine())
69         {
70         case llvm::Triple::arm:
71         case llvm::Triple::thumb:
72             {
73                 const llvm::Triple &triple = arch->GetTriple();
74                 const llvm::Triple::OSType os = triple.getOS();
75                 const llvm::Triple::VendorType vendor = triple.getVendor();
76                 if (os == llvm::Triple::Darwin && vendor == llvm::Triple::Apple)
77                     create = true;
78             }
79             break;
80         default:
81             break;
82         }
83     }
84 
85     if (create)
86         return new PlatformRemoteiOS ();
87     return NULL;
88 }
89 
90 
91 const char *
92 PlatformRemoteiOS::GetPluginNameStatic ()
93 {
94     return "PlatformRemoteiOS";
95 }
96 
97 const char *
98 PlatformRemoteiOS::GetShortPluginNameStatic()
99 {
100     return "remote-ios";
101 }
102 
103 const char *
104 PlatformRemoteiOS::GetDescriptionStatic()
105 {
106     return "Remote iOS platform plug-in.";
107 }
108 
109 
110 //------------------------------------------------------------------
111 /// Default Constructor
112 //------------------------------------------------------------------
113 PlatformRemoteiOS::PlatformRemoteiOS () :
114     PlatformDarwin (false),    // This is a remote platform
115     m_device_support_directory_for_os_version ()
116 {
117 }
118 
119 //------------------------------------------------------------------
120 /// Destructor.
121 ///
122 /// The destructor is virtual since this class is designed to be
123 /// inherited from by the plug-in instance.
124 //------------------------------------------------------------------
125 PlatformRemoteiOS::~PlatformRemoteiOS()
126 {
127 }
128 
129 
130 void
131 PlatformRemoteiOS::GetStatus (Stream &strm)
132 {
133     Platform::GetStatus (strm);
134     const char *sdk_directory = GetDeviceSupportDirectoryForOSVersion();
135     if (sdk_directory)
136         strm.Printf ("  SDK Path: \"%s\"\n", sdk_directory);
137     else
138         strm.PutCString ("  SDK Path: error: unable to locate SDK\n");
139 }
140 
141 
142 Error
143 PlatformRemoteiOS::ResolveExecutable (const FileSpec &exe_file,
144                                       const ArchSpec &exe_arch,
145                                       lldb::ModuleSP &exe_module_sp,
146                                       const FileSpecList *module_search_paths_ptr)
147 {
148     Error error;
149     // Nothing special to do here, just use the actual file and architecture
150 
151     FileSpec resolved_exe_file (exe_file);
152 
153     // If we have "ls" as the exe_file, resolve the executable loation based on
154     // the current path variables
155     // TODO: resolve bare executables in the Platform SDK
156 //    if (!resolved_exe_file.Exists())
157 //        resolved_exe_file.ResolveExecutableLocation ();
158 
159     // Resolve any executable within a bundle on MacOSX
160     // TODO: verify that this handles shallow bundles, if not then implement one ourselves
161     Host::ResolveExecutableInBundle (resolved_exe_file);
162 
163     if (resolved_exe_file.Exists())
164     {
165         if (exe_arch.IsValid())
166         {
167             ModuleSpec module_spec (resolved_exe_file, exe_arch);
168             error = ModuleList::GetSharedModule (module_spec,
169                                                  exe_module_sp,
170                                                  NULL,
171                                                  NULL,
172                                                  NULL);
173 
174             if (exe_module_sp && exe_module_sp->GetObjectFile())
175                 return error;
176             exe_module_sp.reset();
177         }
178         // No valid architecture was specified or the exact ARM slice wasn't
179         // found so ask the platform for the architectures that we should be
180         // using (in the correct order) and see if we can find a match that way
181         StreamString arch_names;
182         ArchSpec platform_arch;
183         for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, platform_arch); ++idx)
184         {
185             ModuleSpec module_spec (resolved_exe_file, platform_arch);
186             error = ModuleList::GetSharedModule (module_spec,
187                                                  exe_module_sp,
188                                                  NULL,
189                                                  NULL,
190                                                  NULL);
191             // Did we find an executable using one of the
192             if (error.Success())
193             {
194                 if (exe_module_sp && exe_module_sp->GetObjectFile())
195                     break;
196                 else
197                     error.SetErrorToGenericError();
198             }
199 
200             if (idx > 0)
201                 arch_names.PutCString (", ");
202             arch_names.PutCString (platform_arch.GetArchitectureName());
203         }
204 
205         if (error.Fail() || !exe_module_sp)
206         {
207             error.SetErrorStringWithFormat ("'%s%s%s' doesn't contain any '%s' platform architectures: %s",
208                                             exe_file.GetDirectory().AsCString(""),
209                                             exe_file.GetDirectory() ? "/" : "",
210                                             exe_file.GetFilename().AsCString(""),
211                                             GetShortPluginName(),
212                                             arch_names.GetString().c_str());
213         }
214     }
215     else
216     {
217         error.SetErrorStringWithFormat ("'%s%s%s' does not exist",
218                                         exe_file.GetDirectory().AsCString(""),
219                                         exe_file.GetDirectory() ? "/" : "",
220                                         exe_file.GetFilename().AsCString(""));
221     }
222 
223     return error;
224 }
225 
226 const char *
227 PlatformRemoteiOS::GetDeviceSupportDirectoryForOSVersion()
228 {
229     if (m_sdk_sysroot)
230         return m_sdk_sysroot.GetCString();
231 
232     if (m_device_support_directory_for_os_version.empty())
233     {
234         const char *device_support_dir = GetDeveloperDirectory();
235         const bool resolve_path = true;
236         if (device_support_dir)
237         {
238             m_device_support_directory_for_os_version.assign (device_support_dir);
239             m_device_support_directory_for_os_version.append ("/Platforms/iPhoneOS.platform/DeviceSupport");
240 
241             uint32_t major = 0;
242             uint32_t minor = 0;
243             uint32_t update = 0;
244             FileSpec file_spec;
245             char resolved_path[PATH_MAX];
246             if (GetOSVersion(major, minor, update))
247             {
248                 if (major != UINT32_MAX && minor != UINT32_MAX && update != UINT32_MAX)
249                 {
250                     ::snprintf (resolved_path,
251                                 sizeof(resolved_path),
252                                 "%s/%i.%i.%i",
253                                 m_device_support_directory_for_os_version.c_str(),
254                                 major,
255                                 minor,
256                                 update);
257 
258                     file_spec.SetFile(resolved_path, resolve_path);
259                     if (file_spec.Exists() && file_spec.GetPath(resolved_path, sizeof(resolved_path)))
260                     {
261                         m_device_support_directory_for_os_version.assign (resolved_path);
262                         return m_device_support_directory_for_os_version.c_str();
263                     }
264                 }
265 
266                 if (major != UINT32_MAX && minor != UINT32_MAX)
267                 {
268                     ::snprintf (resolved_path,
269                                 sizeof(resolved_path),
270                                 "%s/%i.%i",
271                                 m_device_support_directory_for_os_version.c_str(),
272                                 major,
273                                 minor);
274 
275                     file_spec.SetFile(resolved_path, resolve_path);
276                     if (file_spec.Exists() && file_spec.GetPath(resolved_path, sizeof(resolved_path)))
277                     {
278                         m_device_support_directory_for_os_version.assign (resolved_path);
279                         return m_device_support_directory_for_os_version.c_str();
280                     }
281                 }
282             }
283             else
284             {
285                 // Use the default as we have no OS version selected
286                 m_device_support_directory_for_os_version.append ("/Latest");
287                 file_spec.SetFile(m_device_support_directory_for_os_version.c_str(), resolve_path);
288 
289                 if (file_spec.Exists() && file_spec.GetPath(resolved_path, sizeof(resolved_path)))
290                 {
291                     if (m_major_os_version == UINT32_MAX)
292                     {
293                         const char *resolved_latest_dirname = file_spec.GetFilename().GetCString();
294                         const char *pos = Args::StringToVersion (resolved_latest_dirname,
295                                                                  m_major_os_version,
296                                                                  m_minor_os_version,
297                                                                  m_update_os_version);
298 
299                         if (m_build_update.empty() && pos[0] == ' ' && pos[1] == '(')
300                         {
301                             const char *end_paren = strchr (pos + 2, ')');
302                             m_build_update.assign (pos + 2, end_paren);
303                         }
304                     }
305                     m_device_support_directory_for_os_version.assign (resolved_path);
306                     return m_device_support_directory_for_os_version.c_str();
307                 }
308             }
309         }
310         // Assign a single NULL character so we know we tried to find the device
311         // support directory and we don't keep trying to find it over and over.
312         m_device_support_directory_for_os_version.assign (1, '\0');
313     }
314     // We should have put a single NULL character into m_device_support_directory_for_os_version
315     // or it should have a valid path if the code gets here
316     assert (m_device_support_directory_for_os_version.empty() == false);
317     if (m_device_support_directory_for_os_version[0])
318         return m_device_support_directory_for_os_version.c_str();
319     return NULL;
320 }
321 
322 Error
323 PlatformRemoteiOS::GetFile (const FileSpec &platform_file,
324                             const UUID *uuid_ptr,
325                             FileSpec &local_file)
326 {
327     Error error;
328     char platform_file_path[PATH_MAX];
329     if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path)))
330     {
331         char resolved_path[PATH_MAX];
332 
333         const char * os_version_dir = GetDeviceSupportDirectoryForOSVersion();
334         if (os_version_dir)
335         {
336             ::snprintf (resolved_path,
337                         sizeof(resolved_path),
338                         "%s/%s",
339                         os_version_dir,
340                         platform_file_path);
341 
342             local_file.SetFile(resolved_path, true);
343             if (local_file.Exists())
344                 return error;
345 
346             ::snprintf (resolved_path,
347                         sizeof(resolved_path),
348                         "%s/Symbols.Internal/%s",
349                         os_version_dir,
350                         platform_file_path);
351 
352             local_file.SetFile(resolved_path, true);
353             if (local_file.Exists())
354                 return error;
355             ::snprintf (resolved_path,
356                         sizeof(resolved_path),
357                         "%s/Symbols/%s",
358                         os_version_dir,
359                         platform_file_path);
360 
361             local_file.SetFile(resolved_path, true);
362             if (local_file.Exists())
363                 return error;
364 
365         }
366         local_file = platform_file;
367         if (local_file.Exists())
368             return error;
369 
370         error.SetErrorStringWithFormat ("unable to locate a platform file for '%s' in platform '%s'",
371                                         platform_file_path,
372                                         GetPluginName());
373     }
374     else
375     {
376         error.SetErrorString ("invalid platform file argument");
377     }
378     return error;
379 }
380 
381 Error
382 PlatformRemoteiOS::GetSharedModule (const ModuleSpec &module_spec,
383                                     ModuleSP &module_sp,
384                                     const FileSpecList *module_search_paths_ptr,
385                                     ModuleSP *old_module_sp_ptr,
386                                     bool *did_create_ptr)
387 {
388     // For iOS, the SDK files are all cached locally on the host
389     // system. So first we ask for the file in the cached SDK,
390     // then we attempt to get a shared module for the right architecture
391     // with the right UUID.
392     const FileSpec &platform_file = module_spec.GetFileSpec();
393 
394     FileSpec local_file;
395     Error error (GetFile (platform_file, module_spec.GetUUIDPtr(), local_file));
396     if (error.Success())
397     {
398         error = ResolveExecutable (local_file, module_spec.GetArchitecture(), module_sp, module_search_paths_ptr);
399     }
400     else
401     {
402         const bool always_create = false;
403         error = ModuleList::GetSharedModule (module_spec,
404                                              module_sp,
405                                              module_search_paths_ptr,
406                                              old_module_sp_ptr,
407                                              did_create_ptr,
408                                              always_create);
409 
410     }
411     if (module_sp)
412         module_sp->SetPlatformFileSpec(platform_file);
413 
414     return error;
415 }
416 
417 
418 uint32_t
419 PlatformRemoteiOS::FindProcesses (const ProcessInstanceInfoMatch &match_info,
420                                   ProcessInstanceInfoList &process_infos)
421 {
422     // TODO: if connected, send a packet to get the remote process infos by name
423     process_infos.Clear();
424     return 0;
425 }
426 
427 bool
428 PlatformRemoteiOS::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
429 {
430     // TODO: if connected, send a packet to get the remote process info
431     process_info.Clear();
432     return false;
433 }
434 
435 bool
436 PlatformRemoteiOS::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
437 {
438     return ARMGetSupportedArchitectureAtIndex (idx, arch);
439 }
440