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/Log.h"
20 #include "lldb/Core/Module.h"
21 #include "lldb/Core/ModuleList.h"
22 #include "lldb/Core/ModuleSpec.h"
23 #include "lldb/Core/PluginManager.h"
24 #include "lldb/Core/StreamString.h"
25 #include "lldb/Host/FileSpec.h"
26 #include "lldb/Host/Host.h"
27 #include "lldb/Target/Process.h"
28 #include "lldb/Target/Target.h"
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 
33 PlatformRemoteiOS::SDKDirectoryInfo::SDKDirectoryInfo (const lldb_private::FileSpec &sdk_dir) :
34     directory(sdk_dir),
35     build(),
36     version_major(0),
37     version_minor(0),
38     version_update(0),
39     user_cached(false)
40 {
41     const char *dirname_cstr = sdk_dir.GetFilename().GetCString();
42     const char *pos = Args::StringToVersion (dirname_cstr,
43                                              version_major,
44                                              version_minor,
45                                              version_update);
46 
47     if (pos && pos[0] == ' ' && pos[1] == '(')
48     {
49         const char *build_start = pos + 2;
50         const char *end_paren = strchr (build_start, ')');
51         if (end_paren && build_start < end_paren)
52             build.SetCStringWithLength(build_start, end_paren - build_start);
53     }
54 }
55 
56 //------------------------------------------------------------------
57 // Static Variables
58 //------------------------------------------------------------------
59 static uint32_t g_initialize_count = 0;
60 
61 //------------------------------------------------------------------
62 // Static Functions
63 //------------------------------------------------------------------
64 void
65 PlatformRemoteiOS::Initialize ()
66 {
67     PlatformDarwin::Initialize ();
68 
69     if (g_initialize_count++ == 0)
70     {
71         PluginManager::RegisterPlugin (PlatformRemoteiOS::GetPluginNameStatic(),
72                                        PlatformRemoteiOS::GetDescriptionStatic(),
73                                        PlatformRemoteiOS::CreateInstance);
74     }
75 }
76 
77 void
78 PlatformRemoteiOS::Terminate ()
79 {
80     if (g_initialize_count > 0)
81     {
82         if (--g_initialize_count == 0)
83         {
84             PluginManager::UnregisterPlugin (PlatformRemoteiOS::CreateInstance);
85         }
86     }
87 
88     PlatformDarwin::Terminate ();
89 }
90 
91 PlatformSP
92 PlatformRemoteiOS::CreateInstance (bool force, const ArchSpec *arch)
93 {
94     bool create = force;
95     if (create == false && arch && arch->IsValid())
96     {
97         switch (arch->GetMachine())
98         {
99         case llvm::Triple::arm:
100         case llvm::Triple::aarch64:
101         case llvm::Triple::thumb:
102             {
103                 const llvm::Triple &triple = arch->GetTriple();
104                 llvm::Triple::VendorType vendor = triple.getVendor();
105                 switch (vendor)
106                 {
107                     case llvm::Triple::Apple:
108                         create = true;
109                         break;
110 
111 #if defined(__APPLE__)
112                     // Only accept "unknown" for the vendor if the host is Apple and
113                     // it "unknown" wasn't specified (it was just returned because it
114                     // was NOT specified)
115                     case llvm::Triple::UnknownArch:
116                         create = !arch->TripleVendorWasSpecified();
117                         break;
118 
119 #endif
120                     default:
121                         break;
122                 }
123                 if (create)
124                 {
125                     switch (triple.getOS())
126                     {
127                         case llvm::Triple::Darwin:  // Deprecated, but still support Darwin for historical reasons
128                         case llvm::Triple::IOS:     // This is the right triple value for iOS debugging
129                             break;
130 
131 #if defined(__APPLE__)
132                         // Only accept "unknown" for the OS if the host is Apple and
133                         // it "unknown" wasn't specified (it was just returned because it
134                         // was NOT specified)
135                         case llvm::Triple::UnknownOS:
136                             create = !arch->TripleOSWasSpecified();
137                             break;
138 #endif
139                         default:
140                             create = false;
141                             break;
142                     }
143                 }
144             }
145             break;
146         default:
147             break;
148         }
149     }
150 
151     if (create)
152         return lldb::PlatformSP(new PlatformRemoteiOS ());
153     return lldb::PlatformSP();
154 }
155 
156 
157 lldb_private::ConstString
158 PlatformRemoteiOS::GetPluginNameStatic ()
159 {
160     static ConstString g_name("remote-ios");
161     return g_name;
162 }
163 
164 const char *
165 PlatformRemoteiOS::GetDescriptionStatic()
166 {
167     return "Remote iOS platform plug-in.";
168 }
169 
170 
171 //------------------------------------------------------------------
172 /// Default Constructor
173 //------------------------------------------------------------------
174 PlatformRemoteiOS::PlatformRemoteiOS () :
175     PlatformDarwin (false),    // This is a remote platform
176     m_sdk_directory_infos(),
177     m_device_support_directory(),
178     m_device_support_directory_for_os_version (),
179     m_build_update(),
180     m_last_module_sdk_idx (UINT32_MAX),
181     m_connected_module_sdk_idx (UINT32_MAX)
182 {
183 }
184 
185 //------------------------------------------------------------------
186 /// Destructor.
187 ///
188 /// The destructor is virtual since this class is designed to be
189 /// inherited from by the plug-in instance.
190 //------------------------------------------------------------------
191 PlatformRemoteiOS::~PlatformRemoteiOS()
192 {
193 }
194 
195 
196 void
197 PlatformRemoteiOS::GetStatus (Stream &strm)
198 {
199     Platform::GetStatus (strm);
200     const char *sdk_directory = GetDeviceSupportDirectoryForOSVersion();
201     if (sdk_directory)
202         strm.Printf ("  SDK Path: \"%s\"\n", sdk_directory);
203     else
204         strm.PutCString ("  SDK Path: error: unable to locate SDK\n");
205 
206     const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
207     for (uint32_t i=0; i<num_sdk_infos; ++i)
208     {
209         const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
210         strm.Printf (" SDK Roots: [%2u] \"%s\"\n",
211                      i,
212                      sdk_dir_info.directory.GetPath().c_str());
213     }
214 }
215 
216 
217 Error
218 PlatformRemoteiOS::ResolveExecutable (const ModuleSpec &ms,
219                                       lldb::ModuleSP &exe_module_sp,
220                                       const FileSpecList *module_search_paths_ptr)
221 {
222     Error error;
223     // Nothing special to do here, just use the actual file and architecture
224 
225     ModuleSpec resolved_module_spec(ms);
226 
227     // Resolve any executable within a bundle on MacOSX
228     // TODO: verify that this handles shallow bundles, if not then implement one ourselves
229     Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec());
230 
231     if (resolved_module_spec.GetFileSpec().Exists())
232     {
233         if (resolved_module_spec.GetArchitecture().IsValid() || resolved_module_spec.GetUUID().IsValid())
234         {
235             error = ModuleList::GetSharedModule (resolved_module_spec,
236                                                  exe_module_sp,
237                                                  NULL,
238                                                  NULL,
239                                                  NULL);
240 
241             if (exe_module_sp && exe_module_sp->GetObjectFile())
242                 return error;
243             exe_module_sp.reset();
244         }
245         // No valid architecture was specified or the exact ARM slice wasn't
246         // found so ask the platform for the architectures that we should be
247         // using (in the correct order) and see if we can find a match that way
248         StreamString arch_names;
249         for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx)
250         {
251             error = ModuleList::GetSharedModule (resolved_module_spec,
252                                                  exe_module_sp,
253                                                  NULL,
254                                                  NULL,
255                                                  NULL);
256             // Did we find an executable using one of the
257             if (error.Success())
258             {
259                 if (exe_module_sp && exe_module_sp->GetObjectFile())
260                     break;
261                 else
262                     error.SetErrorToGenericError();
263             }
264 
265             if (idx > 0)
266                 arch_names.PutCString (", ");
267             arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName());
268         }
269 
270         if (error.Fail() || !exe_module_sp)
271         {
272             if (resolved_module_spec.GetFileSpec().Readable())
273             {
274                 error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
275                                                 resolved_module_spec.GetFileSpec().GetPath().c_str(),
276                                                 GetPluginName().GetCString(),
277                                                 arch_names.GetString().c_str());
278             }
279             else
280             {
281                 error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str());
282             }
283         }
284     }
285     else
286     {
287         error.SetErrorStringWithFormat ("'%s' does not exist",
288                                         resolved_module_spec.GetFileSpec().GetPath().c_str());
289     }
290 
291     return error;
292 }
293 
294 FileSpec::EnumerateDirectoryResult
295 PlatformRemoteiOS::GetContainedFilesIntoVectorOfStringsCallback (void *baton,
296                                                                  FileSpec::FileType file_type,
297                                                                  const FileSpec &file_spec)
298 {
299     ((PlatformRemoteiOS::SDKDirectoryInfoCollection *)baton)->push_back(PlatformRemoteiOS::SDKDirectoryInfo(file_spec));
300     return FileSpec::eEnumerateDirectoryResultNext;
301 }
302 
303 bool
304 PlatformRemoteiOS::UpdateSDKDirectoryInfosIfNeeded()
305 {
306     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
307     if (m_sdk_directory_infos.empty())
308     {
309         // A --sysroot option was supplied - add it to our list of SDKs to check
310         if (m_sdk_sysroot)
311         {
312             FileSpec sdk_sysroot_fspec(m_sdk_sysroot.GetCString(), true);
313             const SDKDirectoryInfo sdk_sysroot_directory_info(sdk_sysroot_fspec);
314             m_sdk_directory_infos.push_back(sdk_sysroot_directory_info);
315             if (log)
316             {
317                 log->Printf ("PlatformRemoteiOS::UpdateSDKDirectoryInfosIfNeeded added --sysroot SDK directory %s", m_sdk_sysroot.GetCString());
318             }
319             return true;
320         }
321         const char *device_support_dir = GetDeviceSupportDirectory();
322         if (log)
323         {
324             log->Printf ("PlatformRemoteiOS::UpdateSDKDirectoryInfosIfNeeded Got DeviceSupport directory %s", device_support_dir);
325         }
326         if (device_support_dir)
327         {
328             const bool find_directories = true;
329             const bool find_files = false;
330             const bool find_other = false;
331 
332             SDKDirectoryInfoCollection builtin_sdk_directory_infos;
333             FileSpec::EnumerateDirectory (m_device_support_directory.c_str(),
334                                           find_directories,
335                                           find_files,
336                                           find_other,
337                                           GetContainedFilesIntoVectorOfStringsCallback,
338                                           &builtin_sdk_directory_infos);
339 
340             // Only add SDK directories that have symbols in them, some SDKs only contain
341             // developer disk images and no symbols, so they aren't useful to us.
342             FileSpec sdk_symbols_symlink_fspec;
343             for (const auto &sdk_directory_info : builtin_sdk_directory_infos)
344             {
345                 sdk_symbols_symlink_fspec = sdk_directory_info.directory;
346                 sdk_symbols_symlink_fspec.AppendPathComponent("Symbols");
347                 if (sdk_symbols_symlink_fspec.Exists())
348                 {
349                     m_sdk_directory_infos.push_back(sdk_directory_info);
350                     if (log)
351                     {
352                         log->Printf ("PlatformRemoteiOS::UpdateSDKDirectoryInfosIfNeeded added builtin SDK directory %s", sdk_symbols_symlink_fspec.GetPath().c_str());
353                     }
354                 }
355             }
356 
357             const uint32_t num_installed = m_sdk_directory_infos.size();
358             FileSpec local_sdk_cache("~/Library/Developer/Xcode/iOS DeviceSupport", true);
359             if (local_sdk_cache.Exists())
360             {
361                 if (log)
362                 {
363                     log->Printf ("PlatformRemoteiOS::UpdateSDKDirectoryInfosIfNeeded searching %s for additional SDKs", local_sdk_cache.GetPath().c_str());
364                 }
365                 char path[PATH_MAX];
366                 if (local_sdk_cache.GetPath(path, sizeof(path)))
367                 {
368                     FileSpec::EnumerateDirectory (path,
369                                                   find_directories,
370                                                   find_files,
371                                                   find_other,
372                                                   GetContainedFilesIntoVectorOfStringsCallback,
373                                                   &m_sdk_directory_infos);
374                     const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
375                     // First try for an exact match of major, minor and update
376                     for (uint32_t i=num_installed; i<num_sdk_infos; ++i)
377                     {
378                         m_sdk_directory_infos[i].user_cached = true;
379                         if (log)
380                         {
381                             log->Printf ("PlatformRemoteiOS::UpdateSDKDirectoryInfosIfNeeded user SDK directory %s", m_sdk_directory_infos[i].directory.GetPath().c_str());
382                         }
383                     }
384                 }
385             }
386         }
387     }
388     return !m_sdk_directory_infos.empty();
389 }
390 
391 const PlatformRemoteiOS::SDKDirectoryInfo *
392 PlatformRemoteiOS::GetSDKDirectoryForCurrentOSVersion ()
393 {
394     uint32_t i;
395     if (UpdateSDKDirectoryInfosIfNeeded())
396     {
397         const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
398 
399         // Check to see if the user specified a build string. If they did, then
400         // be sure to match it.
401         std::vector<bool> check_sdk_info(num_sdk_infos, true);
402         ConstString build(m_sdk_build);
403         if (build)
404         {
405             for (i=0; i<num_sdk_infos; ++i)
406                 check_sdk_info[i] = m_sdk_directory_infos[i].build == build;
407         }
408 
409         // If we are connected we can find the version of the OS the platform
410         // us running on and select the right SDK
411         uint32_t major, minor, update;
412         if (GetOSVersion(major, minor, update))
413         {
414             if (UpdateSDKDirectoryInfosIfNeeded())
415             {
416                 // First try for an exact match of major, minor and update
417                 for (i=0; i<num_sdk_infos; ++i)
418                 {
419                     if (check_sdk_info[i])
420                     {
421                         if (m_sdk_directory_infos[i].version_major == major &&
422                             m_sdk_directory_infos[i].version_minor == minor &&
423                             m_sdk_directory_infos[i].version_update == update)
424                         {
425                             return &m_sdk_directory_infos[i];
426                         }
427                     }
428                 }
429                 // First try for an exact match of major and minor
430                 for (i=0; i<num_sdk_infos; ++i)
431                 {
432                     if (check_sdk_info[i])
433                     {
434                         if (m_sdk_directory_infos[i].version_major == major &&
435                             m_sdk_directory_infos[i].version_minor == minor)
436                         {
437                             return &m_sdk_directory_infos[i];
438                         }
439                     }
440                 }
441                 // Lastly try to match of major version only..
442                 for (i=0; i<num_sdk_infos; ++i)
443                 {
444                     if (check_sdk_info[i])
445                     {
446                         if (m_sdk_directory_infos[i].version_major == major)
447                         {
448                             return &m_sdk_directory_infos[i];
449                         }
450                     }
451                 }
452             }
453         }
454         else if (build)
455         {
456             // No version, just a build number, search for the first one that matches
457             for (i=0; i<num_sdk_infos; ++i)
458                 if (check_sdk_info[i])
459                     return &m_sdk_directory_infos[i];
460         }
461     }
462     return NULL;
463 }
464 
465 const PlatformRemoteiOS::SDKDirectoryInfo *
466 PlatformRemoteiOS::GetSDKDirectoryForLatestOSVersion ()
467 {
468     const PlatformRemoteiOS::SDKDirectoryInfo *result = NULL;
469     if (UpdateSDKDirectoryInfosIfNeeded())
470     {
471         const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
472         // First try for an exact match of major, minor and update
473         for (uint32_t i=0; i<num_sdk_infos; ++i)
474         {
475             const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
476             if (sdk_dir_info.version_major != UINT32_MAX)
477             {
478                 if (result == NULL || sdk_dir_info.version_major > result->version_major)
479                 {
480                     result = &sdk_dir_info;
481                 }
482                 else if (sdk_dir_info.version_major == result->version_major)
483                 {
484                     if (sdk_dir_info.version_minor > result->version_minor)
485                     {
486                         result = &sdk_dir_info;
487                     }
488                     else if (sdk_dir_info.version_minor == result->version_minor)
489                     {
490                         if (sdk_dir_info.version_update > result->version_update)
491                         {
492                             result = &sdk_dir_info;
493                         }
494                     }
495                 }
496             }
497         }
498     }
499     return result;
500 }
501 
502 
503 
504 const char *
505 PlatformRemoteiOS::GetDeviceSupportDirectory()
506 {
507     if (m_device_support_directory.empty())
508     {
509         const char *device_support_dir = GetDeveloperDirectory();
510         if (device_support_dir)
511         {
512             m_device_support_directory.assign (device_support_dir);
513             m_device_support_directory.append ("/Platforms/iPhoneOS.platform/DeviceSupport");
514         }
515         else
516         {
517             // Assign a single NULL character so we know we tried to find the device
518             // support directory and we don't keep trying to find it over and over.
519             m_device_support_directory.assign (1, '\0');
520         }
521     }
522     // We should have put a single NULL character into m_device_support_directory
523     // or it should have a valid path if the code gets here
524     assert (m_device_support_directory.empty() == false);
525     if (m_device_support_directory[0])
526         return m_device_support_directory.c_str();
527     return NULL;
528 }
529 
530 
531 const char *
532 PlatformRemoteiOS::GetDeviceSupportDirectoryForOSVersion()
533 {
534     if (m_sdk_sysroot)
535         return m_sdk_sysroot.GetCString();
536 
537     if (m_device_support_directory_for_os_version.empty())
538     {
539         const PlatformRemoteiOS::SDKDirectoryInfo *sdk_dir_info = GetSDKDirectoryForCurrentOSVersion ();
540         if (sdk_dir_info == NULL)
541             sdk_dir_info = GetSDKDirectoryForLatestOSVersion ();
542         if (sdk_dir_info)
543         {
544             char path[PATH_MAX];
545             if (sdk_dir_info->directory.GetPath(path, sizeof(path)))
546             {
547                 m_device_support_directory_for_os_version = path;
548                 return m_device_support_directory_for_os_version.c_str();
549             }
550         }
551         else
552         {
553             // Assign a single NULL character so we know we tried to find the device
554             // support directory and we don't keep trying to find it over and over.
555             m_device_support_directory_for_os_version.assign (1, '\0');
556         }
557     }
558     // We should have put a single NULL character into m_device_support_directory_for_os_version
559     // or it should have a valid path if the code gets here
560     assert (m_device_support_directory_for_os_version.empty() == false);
561     if (m_device_support_directory_for_os_version[0])
562         return m_device_support_directory_for_os_version.c_str();
563     return NULL;
564 }
565 
566 uint32_t
567 PlatformRemoteiOS::FindFileInAllSDKs (const char *platform_file_path,
568                                       FileSpecList &file_list)
569 {
570     if (platform_file_path && platform_file_path[0] && UpdateSDKDirectoryInfosIfNeeded())
571     {
572         const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
573         lldb_private::FileSpec local_file;
574         // First try for an exact match of major, minor and update
575         for (uint32_t sdk_idx=0; sdk_idx<num_sdk_infos; ++sdk_idx)
576         {
577             if (GetFileInSDK (platform_file_path,
578                               sdk_idx,
579                               local_file))
580             {
581                 file_list.Append(local_file);
582             }
583         }
584     }
585     return file_list.GetSize();
586 }
587 
588 bool
589 PlatformRemoteiOS::GetFileInSDK (const char *platform_file_path,
590                                  uint32_t sdk_idx,
591                                  lldb_private::FileSpec &local_file)
592 {
593     if (sdk_idx < m_sdk_directory_infos.size())
594     {
595         char sdkroot_path[PATH_MAX];
596         const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[sdk_idx];
597         if (sdk_dir_info.directory.GetPath(sdkroot_path, sizeof(sdkroot_path)))
598         {
599             const bool symbols_dirs_only = true;
600 
601             return GetFileInSDKRoot (platform_file_path,
602                                      sdkroot_path,
603                                      symbols_dirs_only,
604                                      local_file);
605         }
606     }
607     return false;
608 }
609 
610 
611 bool
612 PlatformRemoteiOS::GetFileInSDKRoot (const char *platform_file_path,
613                                      const char *sdkroot_path,
614                                      bool symbols_dirs_only,
615                                      lldb_private::FileSpec &local_file)
616 {
617     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
618     if (sdkroot_path && sdkroot_path[0] && platform_file_path && platform_file_path[0])
619     {
620         char resolved_path[PATH_MAX];
621 
622         if (!symbols_dirs_only)
623         {
624             ::snprintf (resolved_path,
625                         sizeof(resolved_path),
626                         "%s%s",
627                         sdkroot_path,
628                         platform_file_path);
629 
630             local_file.SetFile(resolved_path, true);
631             if (local_file.Exists())
632             {
633                 if (log)
634                 {
635                     log->Printf ("Found a copy of %s in the SDK dir %s", platform_file_path, sdkroot_path);
636                 }
637                 return true;
638             }
639         }
640 
641         ::snprintf (resolved_path,
642                     sizeof(resolved_path),
643                     "%s/Symbols.Internal%s",
644                     sdkroot_path,
645                     platform_file_path);
646 
647         local_file.SetFile(resolved_path, true);
648         if (local_file.Exists())
649         {
650             if (log)
651             {
652                 log->Printf ("Found a copy of %s in the SDK dir %s/Symbols.Internal", platform_file_path, sdkroot_path);
653             }
654             return true;
655         }
656         ::snprintf (resolved_path,
657                     sizeof(resolved_path),
658                     "%s/Symbols%s",
659                     sdkroot_path,
660                     platform_file_path);
661 
662         local_file.SetFile(resolved_path, true);
663         if (local_file.Exists())
664         {
665             if (log)
666             {
667                 log->Printf ("Found a copy of %s in the SDK dir %s/Symbols", platform_file_path, sdkroot_path);
668             }
669             return true;
670         }
671     }
672     return false;
673 }
674 
675 
676 Error
677 PlatformRemoteiOS::GetSymbolFile (const FileSpec &platform_file,
678                                   const UUID *uuid_ptr,
679                                   FileSpec &local_file)
680 {
681     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
682     Error error;
683     char platform_file_path[PATH_MAX];
684     if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path)))
685     {
686         char resolved_path[PATH_MAX];
687 
688         const char * os_version_dir = GetDeviceSupportDirectoryForOSVersion();
689         if (os_version_dir)
690         {
691             ::snprintf (resolved_path,
692                         sizeof(resolved_path),
693                         "%s/%s",
694                         os_version_dir,
695                         platform_file_path);
696 
697             local_file.SetFile(resolved_path, true);
698             if (local_file.Exists())
699             {
700                 if (log)
701                 {
702                     log->Printf ("Found a copy of %s in the DeviceSupport dir %s", platform_file_path, os_version_dir);
703                 }
704                 return error;
705             }
706 
707             ::snprintf (resolved_path,
708                         sizeof(resolved_path),
709                         "%s/Symbols.Internal/%s",
710                         os_version_dir,
711                         platform_file_path);
712 
713             local_file.SetFile(resolved_path, true);
714             if (local_file.Exists())
715             {
716                 if (log)
717                 {
718                     log->Printf ("Found a copy of %s in the DeviceSupport dir %s/Symbols.Internal", platform_file_path, os_version_dir);
719                 }
720                 return error;
721             }
722             ::snprintf (resolved_path,
723                         sizeof(resolved_path),
724                         "%s/Symbols/%s",
725                         os_version_dir,
726                         platform_file_path);
727 
728             local_file.SetFile(resolved_path, true);
729             if (local_file.Exists())
730             {
731                 if (log)
732                 {
733                     log->Printf ("Found a copy of %s in the DeviceSupport dir %s/Symbols", platform_file_path, os_version_dir);
734                 }
735                 return error;
736             }
737 
738         }
739         local_file = platform_file;
740         if (local_file.Exists())
741             return error;
742 
743         error.SetErrorStringWithFormat ("unable to locate a platform file for '%s' in platform '%s'",
744                                         platform_file_path,
745                                         GetPluginName().GetCString());
746     }
747     else
748     {
749         error.SetErrorString ("invalid platform file argument");
750     }
751     return error;
752 }
753 
754 Error
755 PlatformRemoteiOS::GetSharedModule (const ModuleSpec &module_spec,
756                                     Process* process,
757                                     ModuleSP &module_sp,
758                                     const FileSpecList *module_search_paths_ptr,
759                                     ModuleSP *old_module_sp_ptr,
760                                     bool *did_create_ptr)
761 {
762     // For iOS, the SDK files are all cached locally on the host
763     // system. So first we ask for the file in the cached SDK,
764     // then we attempt to get a shared module for the right architecture
765     // with the right UUID.
766     const FileSpec &platform_file = module_spec.GetFileSpec();
767 
768     Error error;
769     char platform_file_path[PATH_MAX];
770 
771     if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path)))
772     {
773         ModuleSpec platform_module_spec(module_spec);
774 
775         UpdateSDKDirectoryInfosIfNeeded();
776 
777         const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
778 
779         // If we are connected we migth be able to correctly deduce the SDK directory
780         // using the OS build.
781         const uint32_t connected_sdk_idx = GetConnectedSDKIndex ();
782         if (connected_sdk_idx < num_sdk_infos)
783         {
784             if (GetFileInSDK (platform_file_path, connected_sdk_idx, platform_module_spec.GetFileSpec()))
785             {
786                 module_sp.reset();
787                 error = ResolveExecutable (platform_module_spec,
788                                            module_sp,
789                                            NULL);
790                 if (module_sp)
791                 {
792                     m_last_module_sdk_idx = connected_sdk_idx;
793                     error.Clear();
794                     return error;
795                 }
796             }
797         }
798 
799         // Try the last SDK index if it is set as most files from an SDK
800         // will tend to be valid in that same SDK.
801         if (m_last_module_sdk_idx < num_sdk_infos)
802         {
803             if (GetFileInSDK (platform_file_path, m_last_module_sdk_idx, platform_module_spec.GetFileSpec()))
804             {
805                 module_sp.reset();
806                 error = ResolveExecutable (platform_module_spec,
807                                            module_sp,
808                                            NULL);
809                 if (module_sp)
810                 {
811                     error.Clear();
812                     return error;
813                 }
814             }
815         }
816 
817         // First try for an exact match of major, minor and update:
818         // If a particalar SDK version was specified via --version or --build, look for a match on disk.
819         const SDKDirectoryInfo *current_sdk_info = GetSDKDirectoryForCurrentOSVersion();
820         const uint32_t current_sdk_idx = GetSDKIndexBySDKDirectoryInfo(current_sdk_info);
821         if (current_sdk_idx < num_sdk_infos && current_sdk_idx != m_last_module_sdk_idx)
822         {
823             if (GetFileInSDK (platform_file_path, current_sdk_idx, platform_module_spec.GetFileSpec()))
824             {
825                 module_sp.reset();
826                 error = ResolveExecutable (platform_module_spec,
827                                            module_sp,
828                                            NULL);
829                 if (module_sp)
830                 {
831                     m_last_module_sdk_idx = current_sdk_idx;
832                     error.Clear();
833                     return error;
834                 }
835             }
836         }
837 
838         // Second try all SDKs that were found.
839         for (uint32_t sdk_idx=0; sdk_idx<num_sdk_infos; ++sdk_idx)
840         {
841             if (m_last_module_sdk_idx == sdk_idx)
842             {
843                 // Skip the last module SDK index if we already searched
844                 // it above
845                 continue;
846             }
847             if (GetFileInSDK (platform_file_path, sdk_idx, platform_module_spec.GetFileSpec()))
848             {
849                 //printf ("sdk[%u]: '%s'\n", sdk_idx, local_file.GetPath().c_str());
850 
851                 error = ResolveExecutable (platform_module_spec, module_sp, NULL);
852                 if (module_sp)
853                 {
854                     // Remember the index of the last SDK that we found a file
855                     // in in case the wrong SDK was selected.
856                     m_last_module_sdk_idx = sdk_idx;
857                     error.Clear();
858                     return error;
859                 }
860             }
861         }
862     }
863     // Not the module we are looking for... Nothing to see here...
864     module_sp.reset();
865 
866     // This may not be an SDK-related module.  Try whether we can bring in the thing to our local cache.
867     error = GetSharedModuleWithLocalCache(module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr);
868     if (error.Success())
869         return error;
870 
871     const bool always_create = false;
872     error = ModuleList::GetSharedModule (module_spec,
873                                          module_sp,
874                                          module_search_paths_ptr,
875                                          old_module_sp_ptr,
876                                          did_create_ptr,
877                                          always_create);
878 
879     if (module_sp)
880         module_sp->SetPlatformFileSpec(platform_file);
881 
882     return error;
883 }
884 
885 bool
886 PlatformRemoteiOS::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
887 {
888     return ARMGetSupportedArchitectureAtIndex (idx, arch);
889 }
890 
891 uint32_t
892 PlatformRemoteiOS::GetConnectedSDKIndex ()
893 {
894     if (IsConnected())
895     {
896         if (m_connected_module_sdk_idx == UINT32_MAX)
897         {
898             std::string build;
899             if (GetRemoteOSBuildString(build))
900             {
901                 const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
902                 for (uint32_t i=0; i<num_sdk_infos; ++i)
903                 {
904                     const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
905                     if (strstr(sdk_dir_info.directory.GetFilename().AsCString(""), build.c_str()))
906                     {
907                         m_connected_module_sdk_idx = i;
908                     }
909                 }
910             }
911         }
912     }
913     else
914     {
915         m_connected_module_sdk_idx = UINT32_MAX;
916     }
917     return m_connected_module_sdk_idx;
918 }
919 
920 uint32_t
921 PlatformRemoteiOS::GetSDKIndexBySDKDirectoryInfo (const SDKDirectoryInfo *sdk_info)
922 {
923     if (sdk_info == NULL)
924     {
925         return UINT32_MAX;
926     }
927 
928     return sdk_info - &m_sdk_directory_infos[0];
929 }
930