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