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   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.GetString().c_str());
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, FileSpec::FileType file_type, 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   if (m_sdk_directory_infos.empty()) {
272     const char *device_support_dir = GetDeviceSupportDirectory();
273     if (log) {
274       log->Printf("PlatformRemoteAppleWatch::UpdateSDKDirectoryInfosIfNeeded "
275                   "Got DeviceSupport directory %s",
276                   device_support_dir);
277     }
278     if (device_support_dir) {
279       const bool find_directories = true;
280       const bool find_files = false;
281       const bool find_other = false;
282 
283       SDKDirectoryInfoCollection builtin_sdk_directory_infos;
284       FileSpec::EnumerateDirectory(m_device_support_directory.c_str(),
285                                    find_directories, find_files, find_other,
286                                    GetContainedFilesIntoVectorOfStringsCallback,
287                                    &builtin_sdk_directory_infos);
288 
289       // Only add SDK directories that have symbols in them, some SDKs only
290       // contain
291       // developer disk images and no symbols, so they aren't useful to us.
292       FileSpec sdk_symbols_symlink_fspec;
293       for (const auto &sdk_directory_info : builtin_sdk_directory_infos) {
294         sdk_symbols_symlink_fspec = sdk_directory_info.directory;
295         sdk_symbols_symlink_fspec.AppendPathComponent("Symbols.Internal");
296         if (sdk_symbols_symlink_fspec.Exists()) {
297           m_sdk_directory_infos.push_back(sdk_directory_info);
298           if (log) {
299             log->Printf("PlatformRemoteAppleWatch::"
300                         "UpdateSDKDirectoryInfosIfNeeded added builtin SDK "
301                         "directory %s",
302                         sdk_symbols_symlink_fspec.GetPath().c_str());
303           }
304         } else {
305           sdk_symbols_symlink_fspec.GetFilename().SetCString("Symbols");
306           if (sdk_symbols_symlink_fspec.Exists())
307             m_sdk_directory_infos.push_back(sdk_directory_info);
308           if (log) {
309             log->Printf("PlatformRemoteAppleWatch::"
310                         "UpdateSDKDirectoryInfosIfNeeded added builtin SDK "
311                         "directory %s",
312                         sdk_symbols_symlink_fspec.GetPath().c_str());
313           }
314         }
315       }
316 
317       const uint32_t num_installed = m_sdk_directory_infos.size();
318       FileSpec local_sdk_cache(
319           "~/Library/Developer/Xcode/watchOS DeviceSupport", true);
320       if (!local_sdk_cache.Exists()) {
321         local_sdk_cache =
322             FileSpec("~/Library/Developer/Xcode/watch OS DeviceSupport", true);
323       }
324       if (!local_sdk_cache.Exists()) {
325         local_sdk_cache =
326             FileSpec("~/Library/Developer/Xcode/WatchOS DeviceSupport", true);
327       }
328       if (!local_sdk_cache.Exists()) {
329         local_sdk_cache =
330             FileSpec("~/Library/Developer/Xcode/Watch OS DeviceSupport", true);
331       }
332       if (local_sdk_cache.Exists()) {
333         if (log) {
334           log->Printf("PlatformRemoteAppleWatch::"
335                       "UpdateSDKDirectoryInfosIfNeeded searching %s for "
336                       "additional SDKs",
337                       local_sdk_cache.GetPath().c_str());
338         }
339         char path[PATH_MAX];
340         if (local_sdk_cache.GetPath(path, sizeof(path))) {
341           FileSpec::EnumerateDirectory(
342               path, find_directories, find_files, find_other,
343               GetContainedFilesIntoVectorOfStringsCallback,
344               &m_sdk_directory_infos);
345           const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
346           // First try for an exact match of major, minor and update
347           for (uint32_t i = num_installed; i < num_sdk_infos; ++i) {
348             m_sdk_directory_infos[i].user_cached = true;
349             if (log) {
350               log->Printf("PlatformRemoteAppleWatch::"
351                           "UpdateSDKDirectoryInfosIfNeeded user SDK directory "
352                           "%s",
353                           m_sdk_directory_infos[i].directory.GetPath().c_str());
354             }
355           }
356         }
357       }
358     }
359   }
360   return !m_sdk_directory_infos.empty();
361 }
362 
363 const PlatformRemoteAppleWatch::SDKDirectoryInfo *
364 PlatformRemoteAppleWatch::GetSDKDirectoryForCurrentOSVersion() {
365   uint32_t i;
366   if (UpdateSDKDirectoryInfosIfNeeded()) {
367     const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
368 
369     // Check to see if the user specified a build string. If they did, then
370     // be sure to match it.
371     std::vector<bool> check_sdk_info(num_sdk_infos, true);
372     ConstString build(m_sdk_build);
373     if (build) {
374       for (i = 0; i < num_sdk_infos; ++i)
375         check_sdk_info[i] = m_sdk_directory_infos[i].build == build;
376     }
377 
378     // If we are connected we can find the version of the OS the platform
379     // us running on and select the right SDK
380     uint32_t major, minor, update;
381     if (GetOSVersion(major, minor, update)) {
382       if (UpdateSDKDirectoryInfosIfNeeded()) {
383         // First try for an exact match of major, minor and update
384         for (i = 0; i < num_sdk_infos; ++i) {
385           if (check_sdk_info[i]) {
386             if (m_sdk_directory_infos[i].version_major == major &&
387                 m_sdk_directory_infos[i].version_minor == minor &&
388                 m_sdk_directory_infos[i].version_update == update) {
389               return &m_sdk_directory_infos[i];
390             }
391           }
392         }
393         // First try for an exact match of major and minor
394         for (i = 0; i < num_sdk_infos; ++i) {
395           if (check_sdk_info[i]) {
396             if (m_sdk_directory_infos[i].version_major == major &&
397                 m_sdk_directory_infos[i].version_minor == minor) {
398               return &m_sdk_directory_infos[i];
399             }
400           }
401         }
402         // Lastly try to match of major version only..
403         for (i = 0; i < num_sdk_infos; ++i) {
404           if (check_sdk_info[i]) {
405             if (m_sdk_directory_infos[i].version_major == major) {
406               return &m_sdk_directory_infos[i];
407             }
408           }
409         }
410       }
411     } else if (build) {
412       // No version, just a build number, search for the first one that matches
413       for (i = 0; i < num_sdk_infos; ++i)
414         if (check_sdk_info[i])
415           return &m_sdk_directory_infos[i];
416     }
417   }
418   return nullptr;
419 }
420 
421 const PlatformRemoteAppleWatch::SDKDirectoryInfo *
422 PlatformRemoteAppleWatch::GetSDKDirectoryForLatestOSVersion() {
423   const PlatformRemoteAppleWatch::SDKDirectoryInfo *result = nullptr;
424   if (UpdateSDKDirectoryInfosIfNeeded()) {
425     const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
426     // First try for an exact match of major, minor and update
427     for (uint32_t i = 0; i < num_sdk_infos; ++i) {
428       const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
429       if (sdk_dir_info.version_major != UINT32_MAX) {
430         if (result == nullptr ||
431             sdk_dir_info.version_major > result->version_major) {
432           result = &sdk_dir_info;
433         } else if (sdk_dir_info.version_major == result->version_major) {
434           if (sdk_dir_info.version_minor > result->version_minor) {
435             result = &sdk_dir_info;
436           } else if (sdk_dir_info.version_minor == result->version_minor) {
437             if (sdk_dir_info.version_update > result->version_update) {
438               result = &sdk_dir_info;
439             }
440           }
441         }
442       }
443     }
444   }
445   return result;
446 }
447 
448 const char *PlatformRemoteAppleWatch::GetDeviceSupportDirectory() {
449   if (m_device_support_directory.empty()) {
450     const char *device_support_dir = GetDeveloperDirectory();
451     if (device_support_dir) {
452       m_device_support_directory.assign(device_support_dir);
453       m_device_support_directory.append(
454           "/Platforms/watchOS.platform/DeviceSupport");
455       FileSpec platform_device_support_dir(m_device_support_directory.c_str(),
456                                            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(
462             m_device_support_directory.c_str(), 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                                                     LIBLLDB_LOG_VERBOSE);
516   if (platform_file_path && platform_file_path[0] &&
517       UpdateSDKDirectoryInfosIfNeeded()) {
518     const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
519     lldb_private::FileSpec local_file;
520     // First try for an exact match of major, minor and update
521     for (uint32_t sdk_idx = 0; sdk_idx < num_sdk_infos; ++sdk_idx) {
522       if (log) {
523         log->Printf("Searching for %s in sdk path %s", platform_file_path,
524                     m_sdk_directory_infos[sdk_idx].directory.GetPath().c_str());
525       }
526       if (GetFileInSDK(platform_file_path, sdk_idx, local_file)) {
527         file_list.Append(local_file);
528       }
529     }
530   }
531   return file_list.GetSize();
532 }
533 
534 bool PlatformRemoteAppleWatch::GetFileInSDK(
535     const char *platform_file_path, uint32_t sdk_idx,
536     lldb_private::FileSpec &local_file) {
537   Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
538   if (sdk_idx < m_sdk_directory_infos.size()) {
539     std::string sdkroot_path =
540         m_sdk_directory_infos[sdk_idx].directory.GetPath();
541     if (!sdkroot_path.empty() && platform_file_path && platform_file_path[0]) {
542       // We may need to interpose "/Symbols/" or "/Symbols.Internal/" between
543       // the
544       // SDK root directory and the file path.
545 
546       const char *paths_to_try[] = {"Symbols", "", "Symbols.Internal", nullptr};
547       for (size_t i = 0; paths_to_try[i] != nullptr; i++) {
548         local_file.SetFile(sdkroot_path.c_str(), false);
549         if (paths_to_try[i][0] != '\0')
550           local_file.AppendPathComponent(paths_to_try[i]);
551         local_file.AppendPathComponent(platform_file_path);
552         local_file.ResolvePath();
553         if (local_file.Exists()) {
554           if (log)
555             log->Printf("Found a copy of %s in the SDK dir %s/%s",
556                         platform_file_path, sdkroot_path.c_str(),
557                         paths_to_try[i]);
558           return true;
559         }
560         local_file.Clear();
561       }
562     }
563   }
564   return false;
565 }
566 
567 Error PlatformRemoteAppleWatch::GetSymbolFile(const FileSpec &platform_file,
568                                               const UUID *uuid_ptr,
569                                               FileSpec &local_file) {
570   Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
571   Error error;
572   char platform_file_path[PATH_MAX];
573   if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path))) {
574     char resolved_path[PATH_MAX];
575 
576     const char *os_version_dir = GetDeviceSupportDirectoryForOSVersion();
577     if (os_version_dir) {
578       ::snprintf(resolved_path, sizeof(resolved_path), "%s/%s", os_version_dir,
579                  platform_file_path);
580 
581       local_file.SetFile(resolved_path, true);
582       if (local_file.Exists()) {
583         if (log) {
584           log->Printf("Found a copy of %s in the DeviceSupport dir %s",
585                       platform_file_path, os_version_dir);
586         }
587         return error;
588       }
589 
590       ::snprintf(resolved_path, sizeof(resolved_path), "%s/Symbols.Internal/%s",
591                  os_version_dir, platform_file_path);
592 
593       local_file.SetFile(resolved_path, true);
594       if (local_file.Exists()) {
595         if (log) {
596           log->Printf(
597               "Found a copy of %s in the DeviceSupport dir %s/Symbols.Internal",
598               platform_file_path, os_version_dir);
599         }
600         return error;
601       }
602       ::snprintf(resolved_path, sizeof(resolved_path), "%s/Symbols/%s",
603                  os_version_dir, platform_file_path);
604 
605       local_file.SetFile(resolved_path, true);
606       if (local_file.Exists()) {
607         if (log) {
608           log->Printf("Found a copy of %s in the DeviceSupport dir %s/Symbols",
609                       platform_file_path, os_version_dir);
610         }
611         return error;
612       }
613     }
614     local_file = platform_file;
615     if (local_file.Exists())
616       return error;
617 
618     error.SetErrorStringWithFormat(
619         "unable to locate a platform file for '%s' in platform '%s'",
620         platform_file_path, GetPluginName().GetCString());
621   } else {
622     error.SetErrorString("invalid platform file argument");
623   }
624   return error;
625 }
626 
627 Error PlatformRemoteAppleWatch::GetSharedModule(
628     const ModuleSpec &module_spec, lldb_private::Process *process,
629     ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr,
630     ModuleSP *old_module_sp_ptr, bool *did_create_ptr) {
631   // For Apple Watch, the SDK files are all cached locally on the host
632   // system. So first we ask for the file in the cached SDK,
633   // then we attempt to get a shared module for the right architecture
634   // with the right UUID.
635   const FileSpec &platform_file = module_spec.GetFileSpec();
636   Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST |
637                                                     LIBLLDB_LOG_VERBOSE);
638 
639   Error error;
640   char platform_file_path[PATH_MAX];
641 
642   if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path))) {
643     ModuleSpec platform_module_spec(module_spec);
644 
645     UpdateSDKDirectoryInfosIfNeeded();
646 
647     const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
648 
649     // If we are connected we migth be able to correctly deduce the SDK
650     // directory
651     // using the OS build.
652     const uint32_t connected_sdk_idx = GetConnectedSDKIndex();
653     if (connected_sdk_idx < num_sdk_infos) {
654       if (log) {
655         log->Printf("Searching for %s in sdk path %s", platform_file_path,
656                     m_sdk_directory_infos[connected_sdk_idx]
657                         .directory.GetPath()
658                         .c_str());
659       }
660       if (GetFileInSDK(platform_file_path, connected_sdk_idx,
661                        platform_module_spec.GetFileSpec())) {
662         module_sp.reset();
663         error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
664         if (module_sp) {
665           m_last_module_sdk_idx = connected_sdk_idx;
666           error.Clear();
667           return error;
668         }
669       }
670     }
671 
672     // Try the last SDK index if it is set as most files from an SDK
673     // will tend to be valid in that same SDK.
674     if (m_last_module_sdk_idx < num_sdk_infos) {
675       if (log) {
676         log->Printf("Searching for %s in sdk path %s", platform_file_path,
677                     m_sdk_directory_infos[m_last_module_sdk_idx]
678                         .directory.GetPath()
679                         .c_str());
680       }
681       if (GetFileInSDK(platform_file_path, m_last_module_sdk_idx,
682                        platform_module_spec.GetFileSpec())) {
683         module_sp.reset();
684         error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
685         if (module_sp) {
686           error.Clear();
687           return error;
688         }
689       }
690     }
691 
692     // First try for an exact match of major, minor and update
693     for (uint32_t sdk_idx = 0; sdk_idx < num_sdk_infos; ++sdk_idx) {
694       if (m_last_module_sdk_idx == sdk_idx) {
695         // Skip the last module SDK index if we already searched
696         // it above
697         continue;
698       }
699       if (log) {
700         log->Printf("Searching for %s in sdk path %s", platform_file_path,
701                     m_sdk_directory_infos[sdk_idx].directory.GetPath().c_str());
702       }
703       if (GetFileInSDK(platform_file_path, sdk_idx,
704                        platform_module_spec.GetFileSpec())) {
705         // printf ("sdk[%u]: '%s'\n", sdk_idx, local_file.GetPath().c_str());
706 
707         error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
708         if (module_sp) {
709           // Remember the index of the last SDK that we found a file
710           // in in case the wrong SDK was selected.
711           m_last_module_sdk_idx = sdk_idx;
712           error.Clear();
713           return error;
714         }
715       }
716     }
717   }
718   // Not the module we are looking for... Nothing to see here...
719   module_sp.reset();
720 
721   // This may not be an SDK-related module.  Try whether we can bring in the
722   // thing to our local cache.
723   error = GetSharedModuleWithLocalCache(module_spec, module_sp,
724                                         module_search_paths_ptr,
725                                         old_module_sp_ptr, did_create_ptr);
726   if (error.Success())
727     return error;
728 
729   // See if the file is present in any of the module_search_paths_ptr
730   // directories.
731   if (!module_sp && module_search_paths_ptr && platform_file) {
732     // create a vector of all the file / directory names in platform_file
733     // e.g. this might be
734     // /System/Library/PrivateFrameworks/UIFoundation.framework/UIFoundation
735     //
736     // We'll need to look in the module_search_paths_ptr directories for
737     // both "UIFoundation" and "UIFoundation.framework" -- most likely the
738     // latter will be the one we find there.
739 
740     FileSpec platform_pull_apart(platform_file);
741     std::vector<std::string> path_parts;
742     ConstString unix_root_dir("/");
743     while (true) {
744       ConstString part = platform_pull_apart.GetLastPathComponent();
745       platform_pull_apart.RemoveLastPathComponent();
746       if (part.IsEmpty() || part == unix_root_dir)
747         break;
748       path_parts.push_back(part.AsCString());
749     }
750     const size_t path_parts_size = path_parts.size();
751 
752     size_t num_module_search_paths = module_search_paths_ptr->GetSize();
753     for (size_t i = 0; i < num_module_search_paths; ++i) {
754       // Create a new FileSpec with this module_search_paths_ptr
755       // plus just the filename ("UIFoundation"), then the parent
756       // dir plus filename ("UIFoundation.framework/UIFoundation")
757       // etc - up to four names (to handle "Foo.framework/Contents/MacOS/Foo")
758 
759       for (size_t j = 0; j < 4 && j < path_parts_size - 1; ++j) {
760         FileSpec path_to_try(module_search_paths_ptr->GetFileSpecAtIndex(i));
761 
762         // Add the components backwards.  For
763         // .../PrivateFrameworks/UIFoundation.framework/UIFoundation
764         // path_parts is
765         //   [0] UIFoundation
766         //   [1] UIFoundation.framework
767         //   [2] PrivateFrameworks
768         //
769         // and if 'j' is 2, we want to append path_parts[1] and then
770         // path_parts[0], aka
771         // 'UIFoundation.framework/UIFoundation', to the module_search_paths_ptr
772         // path.
773 
774         for (int k = j; k >= 0; --k) {
775           path_to_try.AppendPathComponent(path_parts[k]);
776         }
777 
778         if (path_to_try.Exists()) {
779           ModuleSpec new_module_spec(module_spec);
780           new_module_spec.GetFileSpec() = path_to_try;
781           Error new_error(Platform::GetSharedModule(
782               new_module_spec, process, module_sp, NULL, old_module_sp_ptr,
783               did_create_ptr));
784 
785           if (module_sp) {
786             module_sp->SetPlatformFileSpec(path_to_try);
787             return new_error;
788           }
789         }
790       }
791     }
792   }
793 
794   const bool always_create = false;
795   error = ModuleList::GetSharedModule(
796       module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr,
797       did_create_ptr, always_create);
798 
799   if (module_sp)
800     module_sp->SetPlatformFileSpec(platform_file);
801 
802   return error;
803 }
804 
805 bool PlatformRemoteAppleWatch::GetSupportedArchitectureAtIndex(uint32_t idx,
806                                                                ArchSpec &arch) {
807   ArchSpec system_arch(GetSystemArchitecture());
808 
809   const ArchSpec::Core system_core = system_arch.GetCore();
810   switch (system_core) {
811   default:
812     switch (idx) {
813     case 0:
814       arch.SetTriple("arm64-apple-watchos");
815       return true;
816     case 1:
817       arch.SetTriple("armv7k-apple-watchos");
818       return true;
819     case 2:
820       arch.SetTriple("armv7s-apple-watchos");
821       return true;
822     case 3:
823       arch.SetTriple("armv7-apple-watchos");
824       return true;
825     case 4:
826       arch.SetTriple("thumbv7k-apple-watchos");
827       return true;
828     case 5:
829       arch.SetTriple("thumbv7-apple-watchos");
830       return true;
831     case 6:
832       arch.SetTriple("thumbv7s-apple-watchos");
833       return true;
834     default:
835       break;
836     }
837     break;
838 
839   case ArchSpec::eCore_arm_arm64:
840     switch (idx) {
841     case 0:
842       arch.SetTriple("arm64-apple-watchos");
843       return true;
844     case 1:
845       arch.SetTriple("armv7k-apple-watchos");
846       return true;
847     case 2:
848       arch.SetTriple("armv7s-apple-watchos");
849       return true;
850     case 3:
851       arch.SetTriple("armv7-apple-watchos");
852       return true;
853     case 4:
854       arch.SetTriple("thumbv7k-apple-watchos");
855       return true;
856     case 5:
857       arch.SetTriple("thumbv7-apple-watchos");
858       return true;
859     case 6:
860       arch.SetTriple("thumbv7s-apple-watchos");
861       return true;
862     default:
863       break;
864     }
865     break;
866 
867   case ArchSpec::eCore_arm_armv7k:
868     switch (idx) {
869     case 0:
870       arch.SetTriple("armv7k-apple-watchos");
871       return true;
872     case 1:
873       arch.SetTriple("armv7s-apple-watchos");
874       return true;
875     case 2:
876       arch.SetTriple("armv7-apple-watchos");
877       return true;
878     case 3:
879       arch.SetTriple("thumbv7k-apple-watchos");
880       return true;
881     case 4:
882       arch.SetTriple("thumbv7-apple-watchos");
883       return true;
884     case 5:
885       arch.SetTriple("thumbv7s-apple-watchos");
886       return true;
887     default:
888       break;
889     }
890     break;
891 
892   case ArchSpec::eCore_arm_armv7s:
893     switch (idx) {
894     case 0:
895       arch.SetTriple("armv7s-apple-watchos");
896       return true;
897     case 1:
898       arch.SetTriple("armv7k-apple-watchos");
899       return true;
900     case 2:
901       arch.SetTriple("armv7-apple-watchos");
902       return true;
903     case 3:
904       arch.SetTriple("thumbv7k-apple-watchos");
905       return true;
906     case 4:
907       arch.SetTriple("thumbv7-apple-watchos");
908       return true;
909     case 5:
910       arch.SetTriple("thumbv7s-apple-watchos");
911       return true;
912     default:
913       break;
914     }
915     break;
916 
917   case ArchSpec::eCore_arm_armv7:
918     switch (idx) {
919     case 0:
920       arch.SetTriple("armv7-apple-watchos");
921       return true;
922     case 1:
923       arch.SetTriple("armv7k-apple-watchos");
924       return true;
925     case 2:
926       arch.SetTriple("thumbv7k-apple-watchos");
927       return true;
928     case 3:
929       arch.SetTriple("thumbv7-apple-watchos");
930       return true;
931     default:
932       break;
933     }
934     break;
935   }
936   arch.Clear();
937   return false;
938 }
939 
940 uint32_t PlatformRemoteAppleWatch::GetConnectedSDKIndex() {
941   if (IsConnected()) {
942     if (m_connected_module_sdk_idx == UINT32_MAX) {
943       std::string build;
944       if (GetRemoteOSBuildString(build)) {
945         const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
946         for (uint32_t i = 0; i < num_sdk_infos; ++i) {
947           const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
948           if (strstr(sdk_dir_info.directory.GetFilename().AsCString(""),
949                      build.c_str())) {
950             m_connected_module_sdk_idx = i;
951           }
952         }
953       }
954     }
955   } else {
956     m_connected_module_sdk_idx = UINT32_MAX;
957   }
958   return m_connected_module_sdk_idx;
959 }
960