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