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