1 //===-- PlatformRemoteDarwinDevice.cpp ------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "PlatformRemoteDarwinDevice.h"
10 
11 #include "lldb/Breakpoint/BreakpointLocation.h"
12 #include "lldb/Core/Module.h"
13 #include "lldb/Core/ModuleList.h"
14 #include "lldb/Core/ModuleSpec.h"
15 #include "lldb/Core/PluginManager.h"
16 #include "lldb/Host/FileSystem.h"
17 #include "lldb/Host/Host.h"
18 #include "lldb/Host/HostInfo.h"
19 #include "lldb/Target/Process.h"
20 #include "lldb/Target/Target.h"
21 #include "lldb/Utility/FileSpec.h"
22 #include "lldb/Utility/LLDBLog.h"
23 #include "lldb/Utility/Log.h"
24 #include "lldb/Utility/Status.h"
25 #include "lldb/Utility/StreamString.h"
26 #include <optional>
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
SDKDirectoryInfo(const lldb_private::FileSpec & sdk_dir)31 PlatformRemoteDarwinDevice::SDKDirectoryInfo::SDKDirectoryInfo(
32     const lldb_private::FileSpec &sdk_dir)
33     : directory(sdk_dir), build(), user_cached(false) {
34   llvm::StringRef dirname_str = sdk_dir.GetFilename().GetStringRef();
35   llvm::StringRef build_str;
36   std::tie(version, build_str) = ParseVersionBuildDir(dirname_str);
37   build.SetString(build_str);
38 }
39 
40 /// Default Constructor
PlatformRemoteDarwinDevice()41 PlatformRemoteDarwinDevice::PlatformRemoteDarwinDevice()
42     : PlatformDarwinDevice(false) {} // This is a remote platform
43 
44 /// Destructor.
45 ///
46 /// The destructor is virtual since this class is designed to be
47 /// inherited from by the plug-in instance.
48 PlatformRemoteDarwinDevice::~PlatformRemoteDarwinDevice() = default;
49 
GetStatus(Stream & strm)50 void PlatformRemoteDarwinDevice::GetStatus(Stream &strm) {
51   Platform::GetStatus(strm);
52   const char *sdk_directory = GetDeviceSupportDirectoryForOSVersion();
53   if (sdk_directory)
54     strm.Printf("  SDK Path: \"%s\"\n", sdk_directory);
55   else
56     strm.PutCString("  SDK Path: error: unable to locate SDK\n");
57 
58   const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
59   for (uint32_t i = 0; i < num_sdk_infos; ++i) {
60     const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
61     strm.Printf(" SDK Roots: [%2u] \"%s\"\n", i,
62                 sdk_dir_info.directory.GetPath().c_str());
63   }
64 }
65 
ResolveExecutable(const ModuleSpec & ms,lldb::ModuleSP & exe_module_sp,const FileSpecList * module_search_paths_ptr)66 Status PlatformRemoteDarwinDevice::ResolveExecutable(
67     const ModuleSpec &ms, lldb::ModuleSP &exe_module_sp,
68     const FileSpecList *module_search_paths_ptr) {
69   Status error;
70   // Nothing special to do here, just use the actual file and architecture
71 
72   ModuleSpec resolved_module_spec(ms);
73 
74   // Resolve any executable within a bundle on MacOSX
75   // TODO: verify that this handles shallow bundles, if not then implement one
76   // ourselves
77   Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
78 
79   if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) {
80     if (resolved_module_spec.GetArchitecture().IsValid() ||
81         resolved_module_spec.GetUUID().IsValid()) {
82       error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
83                                           nullptr, nullptr, nullptr);
84 
85       if (exe_module_sp && exe_module_sp->GetObjectFile())
86         return error;
87       exe_module_sp.reset();
88     }
89     // No valid architecture was specified or the exact ARM slice wasn't found
90     // so ask the platform for the architectures that we should be using (in
91     // the correct order) and see if we can find a match that way
92     StreamString arch_names;
93     llvm::ListSeparator LS;
94     ArchSpec process_host_arch;
95     for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch)) {
96       resolved_module_spec.GetArchitecture() = arch;
97       error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
98                                           nullptr, nullptr, nullptr);
99       // Did we find an executable using one of the
100       if (error.Success()) {
101         if (exe_module_sp && exe_module_sp->GetObjectFile())
102           break;
103         else
104           error.SetErrorToGenericError();
105       }
106 
107       arch_names << LS << arch.GetArchitectureName();
108     }
109 
110     if (error.Fail() || !exe_module_sp) {
111       if (FileSystem::Instance().Readable(resolved_module_spec.GetFileSpec())) {
112         error.SetErrorStringWithFormatv(
113             "'{0}' doesn't contain any '{1}' platform architectures: {2}",
114             resolved_module_spec.GetFileSpec(), GetPluginName(),
115             arch_names.GetData());
116       } else {
117         error.SetErrorStringWithFormat(
118             "'%s' is not readable",
119             resolved_module_spec.GetFileSpec().GetPath().c_str());
120       }
121     }
122   } else {
123     error.SetErrorStringWithFormat(
124         "'%s' does not exist",
125         resolved_module_spec.GetFileSpec().GetPath().c_str());
126   }
127 
128   return error;
129 }
130 
GetFileInSDK(const char * platform_file_path,uint32_t sdk_idx,lldb_private::FileSpec & local_file)131 bool PlatformRemoteDarwinDevice::GetFileInSDK(const char *platform_file_path,
132                                      uint32_t sdk_idx,
133                                      lldb_private::FileSpec &local_file) {
134   Log *log = GetLog(LLDBLog::Host);
135   if (sdk_idx < m_sdk_directory_infos.size()) {
136     std::string sdkroot_path =
137         m_sdk_directory_infos[sdk_idx].directory.GetPath();
138     local_file.Clear();
139 
140     if (!sdkroot_path.empty() && platform_file_path && platform_file_path[0]) {
141       // We may need to interpose "/Symbols/" or "/Symbols.Internal/" between
142       // the
143       // SDK root directory and the file path.
144 
145       const char *paths_to_try[] = {"Symbols", "", "Symbols.Internal", nullptr};
146       for (size_t i = 0; paths_to_try[i] != nullptr; i++) {
147         local_file.SetFile(sdkroot_path, FileSpec::Style::native);
148         if (paths_to_try[i][0] != '\0')
149           local_file.AppendPathComponent(paths_to_try[i]);
150         local_file.AppendPathComponent(platform_file_path);
151         FileSystem::Instance().Resolve(local_file);
152         if (FileSystem::Instance().Exists(local_file)) {
153           LLDB_LOGF(log, "Found a copy of %s in the SDK dir %s/%s",
154                     platform_file_path, sdkroot_path.c_str(), paths_to_try[i]);
155           return true;
156         }
157         local_file.Clear();
158       }
159     }
160   }
161   return false;
162 }
163 
GetSymbolFile(const FileSpec & platform_file,const UUID * uuid_ptr,FileSpec & local_file)164 Status PlatformRemoteDarwinDevice::GetSymbolFile(const FileSpec &platform_file,
165                                                  const UUID *uuid_ptr,
166                                                  FileSpec &local_file) {
167   Log *log = GetLog(LLDBLog::Host);
168   Status error;
169   char platform_file_path[PATH_MAX];
170   if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path))) {
171     const char *os_version_dir = GetDeviceSupportDirectoryForOSVersion();
172     if (os_version_dir) {
173       std::string resolved_path =
174           (llvm::Twine(os_version_dir) + "/" + platform_file_path).str();
175 
176       local_file.SetFile(resolved_path, FileSpec::Style::native);
177       FileSystem::Instance().Resolve(local_file);
178       if (FileSystem::Instance().Exists(local_file)) {
179         if (log) {
180           LLDB_LOGF(log, "Found a copy of %s in the DeviceSupport dir %s",
181                     platform_file_path, os_version_dir);
182         }
183         return error;
184       }
185 
186       resolved_path = (llvm::Twine(os_version_dir) + "/Symbols.Internal/" +
187                        platform_file_path)
188                           .str();
189 
190       local_file.SetFile(resolved_path, FileSpec::Style::native);
191       FileSystem::Instance().Resolve(local_file);
192       if (FileSystem::Instance().Exists(local_file)) {
193         LLDB_LOGF(
194             log,
195             "Found a copy of %s in the DeviceSupport dir %s/Symbols.Internal",
196             platform_file_path, os_version_dir);
197         return error;
198       }
199       resolved_path =
200           (llvm::Twine(os_version_dir) + "/Symbols/" + platform_file_path)
201               .str();
202 
203       local_file.SetFile(resolved_path, FileSpec::Style::native);
204       FileSystem::Instance().Resolve(local_file);
205       if (FileSystem::Instance().Exists(local_file)) {
206         LLDB_LOGF(log, "Found a copy of %s in the DeviceSupport dir %s/Symbols",
207                   platform_file_path, os_version_dir);
208         return error;
209       }
210     }
211     local_file = platform_file;
212     if (FileSystem::Instance().Exists(local_file))
213       return error;
214 
215     error.SetErrorStringWithFormatv(
216         "unable to locate a platform file for '{0}' in platform '{1}'",
217         platform_file_path, GetPluginName());
218   } else {
219     error.SetErrorString("invalid platform file argument");
220   }
221   return error;
222 }
223 
GetSharedModule(const ModuleSpec & module_spec,Process * process,ModuleSP & module_sp,const FileSpecList * module_search_paths_ptr,llvm::SmallVectorImpl<ModuleSP> * old_modules,bool * did_create_ptr)224 Status PlatformRemoteDarwinDevice::GetSharedModule(
225     const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
226     const FileSpecList *module_search_paths_ptr,
227     llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
228   // For iOS, the SDK files are all cached locally on the host system. So first
229   // we ask for the file in the cached SDK, then we attempt to get a shared
230   // module for the right architecture with the right UUID.
231   const FileSpec &platform_file = module_spec.GetFileSpec();
232   Log *log = GetLog(LLDBLog::Host);
233 
234   Status error;
235   char platform_file_path[PATH_MAX];
236 
237   if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path))) {
238     ModuleSpec platform_module_spec(module_spec);
239 
240     UpdateSDKDirectoryInfosIfNeeded();
241 
242     const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
243 
244     // If we are connected we migth be able to correctly deduce the SDK
245     // directory using the OS build.
246     const uint32_t connected_sdk_idx = GetConnectedSDKIndex();
247     if (connected_sdk_idx < num_sdk_infos) {
248       LLDB_LOGV(log, "Searching for {0} in sdk path {1}", platform_file,
249                 m_sdk_directory_infos[connected_sdk_idx].directory);
250       if (GetFileInSDK(platform_file_path, connected_sdk_idx,
251                        platform_module_spec.GetFileSpec())) {
252         module_sp.reset();
253         error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
254         if (module_sp) {
255           m_last_module_sdk_idx = connected_sdk_idx;
256           error.Clear();
257           return error;
258         }
259       }
260     }
261 
262     // Try the last SDK index if it is set as most files from an SDK will tend
263     // to be valid in that same SDK.
264     if (m_last_module_sdk_idx < num_sdk_infos) {
265       LLDB_LOGV(log, "Searching for {0} in sdk path {1}", platform_file,
266                 m_sdk_directory_infos[m_last_module_sdk_idx].directory);
267       if (GetFileInSDK(platform_file_path, m_last_module_sdk_idx,
268                        platform_module_spec.GetFileSpec())) {
269         module_sp.reset();
270         error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
271         if (module_sp) {
272           error.Clear();
273           return error;
274         }
275       }
276     }
277 
278     // First try for an exact match of major, minor and update: If a particalar
279     // SDK version was specified via --version or --build, look for a match on
280     // disk.
281     const SDKDirectoryInfo *current_sdk_info =
282         GetSDKDirectoryForCurrentOSVersion();
283     const uint32_t current_sdk_idx =
284         GetSDKIndexBySDKDirectoryInfo(current_sdk_info);
285     if (current_sdk_idx < num_sdk_infos &&
286         current_sdk_idx != m_last_module_sdk_idx) {
287       LLDB_LOGV(log, "Searching for {0} in sdk path {1}", platform_file,
288                 m_sdk_directory_infos[current_sdk_idx].directory);
289       if (GetFileInSDK(platform_file_path, current_sdk_idx,
290                        platform_module_spec.GetFileSpec())) {
291         module_sp.reset();
292         error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
293         if (module_sp) {
294           m_last_module_sdk_idx = current_sdk_idx;
295           error.Clear();
296           return error;
297         }
298       }
299     }
300 
301     // Second try all SDKs that were found.
302     for (uint32_t sdk_idx = 0; sdk_idx < num_sdk_infos; ++sdk_idx) {
303       if (m_last_module_sdk_idx == sdk_idx) {
304         // Skip the last module SDK index if we already searched it above
305         continue;
306       }
307       LLDB_LOGV(log, "Searching for {0} in sdk path {1}", platform_file,
308                 m_sdk_directory_infos[sdk_idx].directory);
309       if (GetFileInSDK(platform_file_path, sdk_idx,
310                        platform_module_spec.GetFileSpec())) {
311         // printf ("sdk[%u]: '%s'\n", sdk_idx, local_file.GetPath().c_str());
312 
313         error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
314         if (module_sp) {
315           // Remember the index of the last SDK that we found a file in in case
316           // the wrong SDK was selected.
317           m_last_module_sdk_idx = sdk_idx;
318           error.Clear();
319           return error;
320         }
321       }
322     }
323   }
324   // Not the module we are looking for... Nothing to see here...
325   module_sp.reset();
326 
327   // This may not be an SDK-related module.  Try whether we can bring in the
328   // thing to our local cache.
329   error = GetSharedModuleWithLocalCache(module_spec, module_sp,
330                                         module_search_paths_ptr, old_modules,
331                                         did_create_ptr);
332   if (error.Success())
333     return error;
334 
335   // See if the file is present in any of the module_search_paths_ptr
336   // directories.
337   if (!module_sp)
338     error = PlatformDarwin::FindBundleBinaryInExecSearchPaths(
339         module_spec, process, module_sp, module_search_paths_ptr, old_modules,
340         did_create_ptr);
341 
342   if (error.Success())
343     return error;
344 
345   const bool always_create = false;
346   error = ModuleList::GetSharedModule(module_spec, module_sp,
347                                       module_search_paths_ptr, old_modules,
348                                       did_create_ptr, always_create);
349 
350   if (module_sp)
351     module_sp->SetPlatformFileSpec(platform_file);
352 
353   return error;
354 }
355 
GetConnectedSDKIndex()356 uint32_t PlatformRemoteDarwinDevice::GetConnectedSDKIndex() {
357   if (IsConnected()) {
358     if (m_connected_module_sdk_idx == UINT32_MAX) {
359       if (std::optional<std::string> build = GetRemoteOSBuildString()) {
360         const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
361         for (uint32_t i = 0; i < num_sdk_infos; ++i) {
362           const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
363           if (strstr(sdk_dir_info.directory.GetFilename().AsCString(""),
364                      build->c_str())) {
365             m_connected_module_sdk_idx = i;
366           }
367         }
368       }
369     }
370   } else {
371     m_connected_module_sdk_idx = UINT32_MAX;
372   }
373   return m_connected_module_sdk_idx;
374 }
375 
GetSDKIndexBySDKDirectoryInfo(const SDKDirectoryInfo * sdk_info)376 uint32_t PlatformRemoteDarwinDevice::GetSDKIndexBySDKDirectoryInfo(
377     const SDKDirectoryInfo *sdk_info) {
378   if (sdk_info == nullptr) {
379     return UINT32_MAX;
380   }
381 
382   return sdk_info - &m_sdk_directory_infos[0];
383 }
384