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