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