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