xref: /llvm-project/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp (revision 0642cd768b80665585c8500bed2933a3b99123dc)
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 
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
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 
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 
66 bool PlatformRemoteDarwinDevice::GetFileInSDK(const char *platform_file_path,
67                                      uint32_t sdk_idx,
68                                      lldb_private::FileSpec &local_file) {
69   Log *log = GetLog(LLDBLog::Host);
70   if (sdk_idx < m_sdk_directory_infos.size()) {
71     std::string sdkroot_path =
72         m_sdk_directory_infos[sdk_idx].directory.GetPath();
73     local_file.Clear();
74 
75     if (!sdkroot_path.empty() && platform_file_path && platform_file_path[0]) {
76       // We may need to interpose "/Symbols/" or "/Symbols.Internal/" between
77       // the
78       // SDK root directory and the file path.
79 
80       const char *paths_to_try[] = {"Symbols", "", "Symbols.Internal", nullptr};
81       for (size_t i = 0; paths_to_try[i] != nullptr; i++) {
82         local_file.SetFile(sdkroot_path, FileSpec::Style::native);
83         if (paths_to_try[i][0] != '\0')
84           local_file.AppendPathComponent(paths_to_try[i]);
85         local_file.AppendPathComponent(platform_file_path);
86         FileSystem::Instance().Resolve(local_file);
87         if (FileSystem::Instance().Exists(local_file)) {
88           LLDB_LOGF(log, "Found a copy of %s in the SDK dir %s/%s",
89                     platform_file_path, sdkroot_path.c_str(), paths_to_try[i]);
90           return true;
91         }
92         local_file.Clear();
93       }
94     }
95   }
96   return false;
97 }
98 
99 Status PlatformRemoteDarwinDevice::GetSymbolFile(const FileSpec &platform_file,
100                                                  const UUID *uuid_ptr,
101                                                  FileSpec &local_file) {
102   Log *log = GetLog(LLDBLog::Host);
103   Status error;
104   char platform_file_path[PATH_MAX];
105   if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path))) {
106     const char *os_version_dir = GetDeviceSupportDirectoryForOSVersion();
107     if (os_version_dir) {
108       std::string resolved_path =
109           (llvm::Twine(os_version_dir) + "/" + platform_file_path).str();
110 
111       local_file.SetFile(resolved_path, FileSpec::Style::native);
112       FileSystem::Instance().Resolve(local_file);
113       if (FileSystem::Instance().Exists(local_file)) {
114         if (log) {
115           LLDB_LOGF(log, "Found a copy of %s in the DeviceSupport dir %s",
116                     platform_file_path, os_version_dir);
117         }
118         return error;
119       }
120 
121       resolved_path = (llvm::Twine(os_version_dir) + "/Symbols.Internal/" +
122                        platform_file_path)
123                           .str();
124 
125       local_file.SetFile(resolved_path, FileSpec::Style::native);
126       FileSystem::Instance().Resolve(local_file);
127       if (FileSystem::Instance().Exists(local_file)) {
128         LLDB_LOGF(
129             log,
130             "Found a copy of %s in the DeviceSupport dir %s/Symbols.Internal",
131             platform_file_path, os_version_dir);
132         return error;
133       }
134       resolved_path =
135           (llvm::Twine(os_version_dir) + "/Symbols/" + platform_file_path)
136               .str();
137 
138       local_file.SetFile(resolved_path, FileSpec::Style::native);
139       FileSystem::Instance().Resolve(local_file);
140       if (FileSystem::Instance().Exists(local_file)) {
141         LLDB_LOGF(log, "Found a copy of %s in the DeviceSupport dir %s/Symbols",
142                   platform_file_path, os_version_dir);
143         return error;
144       }
145     }
146     local_file = platform_file;
147     if (FileSystem::Instance().Exists(local_file))
148       return error;
149 
150     error = Status::FromErrorStringWithFormatv(
151         "unable to locate a platform file for '{0}' in platform '{1}'",
152         platform_file_path, GetPluginName());
153   } else {
154     error = Status::FromErrorString("invalid platform file argument");
155   }
156   return error;
157 }
158 
159 Status PlatformRemoteDarwinDevice::GetSharedModule(
160     const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
161     const FileSpecList *module_search_paths_ptr,
162     llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
163   // For iOS, the SDK files are all cached locally on the host system. So first
164   // we ask for the file in the cached SDK, then we attempt to get a shared
165   // module for the right architecture with the right UUID.
166   const FileSpec &platform_file = module_spec.GetFileSpec();
167   Log *log = GetLog(LLDBLog::Host);
168 
169   Status error;
170   char platform_file_path[PATH_MAX];
171 
172   if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path))) {
173     ModuleSpec platform_module_spec(module_spec);
174 
175     UpdateSDKDirectoryInfosIfNeeded();
176 
177     const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
178 
179     // If we are connected we migth be able to correctly deduce the SDK
180     // directory using the OS build.
181     const uint32_t connected_sdk_idx = GetConnectedSDKIndex();
182     if (connected_sdk_idx < num_sdk_infos) {
183       LLDB_LOGV(log, "Searching for {0} in sdk path {1}", platform_file,
184                 m_sdk_directory_infos[connected_sdk_idx].directory);
185       if (GetFileInSDK(platform_file_path, connected_sdk_idx,
186                        platform_module_spec.GetFileSpec())) {
187         module_sp.reset();
188         error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
189         if (module_sp) {
190           m_last_module_sdk_idx = connected_sdk_idx;
191           error.Clear();
192           return error;
193         }
194       }
195     }
196 
197     // Try the last SDK index if it is set as most files from an SDK will tend
198     // to be valid in that same SDK.
199     if (m_last_module_sdk_idx < num_sdk_infos) {
200       LLDB_LOGV(log, "Searching for {0} in sdk path {1}", platform_file,
201                 m_sdk_directory_infos[m_last_module_sdk_idx].directory);
202       if (GetFileInSDK(platform_file_path, m_last_module_sdk_idx,
203                        platform_module_spec.GetFileSpec())) {
204         module_sp.reset();
205         error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
206         if (module_sp) {
207           error.Clear();
208           return error;
209         }
210       }
211     }
212 
213     // First try for an exact match of major, minor and update: If a particalar
214     // SDK version was specified via --version or --build, look for a match on
215     // disk.
216     const SDKDirectoryInfo *current_sdk_info =
217         GetSDKDirectoryForCurrentOSVersion();
218     const uint32_t current_sdk_idx =
219         GetSDKIndexBySDKDirectoryInfo(current_sdk_info);
220     if (current_sdk_idx < num_sdk_infos &&
221         current_sdk_idx != m_last_module_sdk_idx) {
222       LLDB_LOGV(log, "Searching for {0} in sdk path {1}", platform_file,
223                 m_sdk_directory_infos[current_sdk_idx].directory);
224       if (GetFileInSDK(platform_file_path, current_sdk_idx,
225                        platform_module_spec.GetFileSpec())) {
226         module_sp.reset();
227         error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
228         if (module_sp) {
229           m_last_module_sdk_idx = current_sdk_idx;
230           error.Clear();
231           return error;
232         }
233       }
234     }
235 
236     // Second try all SDKs that were found.
237     for (uint32_t sdk_idx = 0; sdk_idx < num_sdk_infos; ++sdk_idx) {
238       if (m_last_module_sdk_idx == sdk_idx) {
239         // Skip the last module SDK index if we already searched it above
240         continue;
241       }
242       LLDB_LOGV(log, "Searching for {0} in sdk path {1}", platform_file,
243                 m_sdk_directory_infos[sdk_idx].directory);
244       if (GetFileInSDK(platform_file_path, sdk_idx,
245                        platform_module_spec.GetFileSpec())) {
246         // printf ("sdk[%u]: '%s'\n", sdk_idx, local_file.GetPath().c_str());
247 
248         error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
249         if (module_sp) {
250           // Remember the index of the last SDK that we found a file in in case
251           // the wrong SDK was selected.
252           m_last_module_sdk_idx = sdk_idx;
253           error.Clear();
254           return error;
255         }
256       }
257     }
258   }
259   // Not the module we are looking for... Nothing to see here...
260   module_sp.reset();
261 
262   // This may not be an SDK-related module.  Try whether we can bring in the
263   // thing to our local cache.
264   error = GetSharedModuleWithLocalCache(module_spec, module_sp,
265                                         module_search_paths_ptr, old_modules,
266                                         did_create_ptr);
267   if (error.Success())
268     return error;
269 
270   // See if the file is present in any of the module_search_paths_ptr
271   // directories.
272   if (!module_sp)
273     error = PlatformDarwin::FindBundleBinaryInExecSearchPaths(
274         module_spec, process, module_sp, module_search_paths_ptr, old_modules,
275         did_create_ptr);
276 
277   if (error.Success())
278     return error;
279 
280   const bool always_create = false;
281   error = ModuleList::GetSharedModule(module_spec, module_sp,
282                                       module_search_paths_ptr, old_modules,
283                                       did_create_ptr, always_create);
284 
285   if (module_sp)
286     module_sp->SetPlatformFileSpec(platform_file);
287 
288   return error;
289 }
290 
291 uint32_t PlatformRemoteDarwinDevice::GetConnectedSDKIndex() {
292   if (IsConnected()) {
293     if (m_connected_module_sdk_idx == UINT32_MAX) {
294       if (std::optional<std::string> build = GetRemoteOSBuildString()) {
295         const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
296         for (uint32_t i = 0; i < num_sdk_infos; ++i) {
297           const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i];
298           if (strstr(sdk_dir_info.directory.GetFilename().AsCString(""),
299                      build->c_str())) {
300             m_connected_module_sdk_idx = i;
301           }
302         }
303       }
304     }
305   } else {
306     m_connected_module_sdk_idx = UINT32_MAX;
307   }
308   return m_connected_module_sdk_idx;
309 }
310 
311 uint32_t PlatformRemoteDarwinDevice::GetSDKIndexBySDKDirectoryInfo(
312     const SDKDirectoryInfo *sdk_info) {
313   if (sdk_info == nullptr) {
314     return UINT32_MAX;
315   }
316 
317   return sdk_info - &m_sdk_directory_infos[0];
318 }
319