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