LLDB mainline
PlatformDarwinDevice.cpp
Go to the documentation of this file.
1//===-- PlatformDarwinDevice.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
10#include "lldb/Core/Module.h"
13#include "lldb/Host/HostInfo.h"
16#include "lldb/Utility/Log.h"
17#include <optional>
18
19using namespace lldb;
20using namespace lldb_private;
21
23
26 void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) {
30}
31
33 Log *log = GetLog(LLDBLog::Host);
34 std::lock_guard<std::mutex> guard(m_sdk_dir_mutex);
35 if (m_sdk_directory_infos.empty()) {
36 // A --sysroot option was supplied - add it to our list of SDKs to check
37 if (!m_sdk_sysroot.empty()) {
38 FileSpec sdk_sysroot_fspec(m_sdk_sysroot.c_str());
39 FileSystem::Instance().Resolve(sdk_sysroot_fspec);
40 const SDKDirectoryInfo sdk_sysroot_directory_info(sdk_sysroot_fspec);
41 m_sdk_directory_infos.push_back(sdk_sysroot_directory_info);
42 if (log) {
43 LLDB_LOGF(log,
44 "PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded added "
45 "--sysroot SDK directory %s",
46 m_sdk_sysroot.c_str());
47 }
48 return true;
49 }
50 const char *device_support_dir = GetDeviceSupportDirectory();
51 if (log) {
52 LLDB_LOGF(log,
53 "PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded Got "
54 "DeviceSupport directory %s",
55 device_support_dir);
56 }
57 if (device_support_dir) {
58 const bool find_directories = true;
59 const bool find_files = false;
60 const bool find_other = false;
61
62 SDKDirectoryInfoCollection builtin_sdk_directory_infos;
64 m_device_support_directory, find_directories, find_files, find_other,
66 &builtin_sdk_directory_infos);
67
68 // Only add SDK directories that have symbols in them, some SDKs only
69 // contain developer disk images and no symbols, so they aren't useful to
70 // us.
71 FileSpec sdk_symbols_symlink_fspec;
72 for (const auto &sdk_directory_info : builtin_sdk_directory_infos) {
73 sdk_symbols_symlink_fspec = sdk_directory_info.directory;
74 sdk_symbols_symlink_fspec.AppendPathComponent("Symbols");
75 if (FileSystem::Instance().Exists(sdk_symbols_symlink_fspec)) {
76 m_sdk_directory_infos.push_back(sdk_directory_info);
77 if (log) {
78 LLDB_LOGF(log,
79 "PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded "
80 "added builtin SDK directory %s",
81 sdk_symbols_symlink_fspec.GetPath().c_str());
82 }
83 }
84 }
85
86 const uint32_t num_installed = m_sdk_directory_infos.size();
87 llvm::StringRef dirname = GetDeviceSupportDirectoryName();
88 std::string local_sdk_cache_str = "~/Library/Developer/Xcode/";
89 local_sdk_cache_str += std::string(dirname);
90 FileSpec local_sdk_cache(local_sdk_cache_str.c_str());
91 FileSystem::Instance().Resolve(local_sdk_cache);
92 if (FileSystem::Instance().Exists(local_sdk_cache)) {
93 if (log) {
94 LLDB_LOGF(log,
95 "PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded "
96 "searching %s for additional SDKs",
97 local_sdk_cache.GetPath().c_str());
98 }
99 char path[PATH_MAX];
100 if (local_sdk_cache.GetPath(path, sizeof(path))) {
102 path, find_directories, find_files, find_other,
105 const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
106 // First try for an exact match of major, minor and update
107 for (uint32_t i = num_installed; i < num_sdk_infos; ++i) {
108 m_sdk_directory_infos[i].user_cached = true;
109 if (log) {
110 LLDB_LOGF(log,
111 "PlatformDarwinDevice::"
112 "UpdateSDKDirectoryInfosIfNeeded "
113 "user SDK directory %s",
114 m_sdk_directory_infos[i].directory.GetPath().c_str());
115 }
116 }
117 }
118 }
119
120 const char *addtional_platform_dirs = getenv("PLATFORM_SDK_DIRECTORY");
121 if (addtional_platform_dirs) {
122 SDKDirectoryInfoCollection env_var_sdk_directory_infos;
124 addtional_platform_dirs, find_directories, find_files, find_other,
126 &env_var_sdk_directory_infos);
127 FileSpec sdk_symbols_symlink_fspec;
128 for (const auto &sdk_directory_info : env_var_sdk_directory_infos) {
129 sdk_symbols_symlink_fspec = sdk_directory_info.directory;
130 sdk_symbols_symlink_fspec.AppendPathComponent("Symbols");
131 if (FileSystem::Instance().Exists(sdk_symbols_symlink_fspec)) {
132 m_sdk_directory_infos.push_back(sdk_directory_info);
133 if (log) {
134 LLDB_LOGF(log,
135 "PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded "
136 "added env var SDK directory %s",
137 sdk_symbols_symlink_fspec.GetPath().c_str());
138 }
139 }
140 }
141 }
142 }
143 }
144 return !m_sdk_directory_infos.empty();
145}
146
149 uint32_t i;
151 const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
152 std::vector<bool> check_sdk_info(num_sdk_infos, true);
153
154 // Prefer the user SDK build string.
155 std::string build = GetSDKBuild();
156
157 // Fall back to the platform's build string.
158 if (build.empty()) {
159 if (std::optional<std::string> os_build_str = GetOSBuildString())
160 build.assign(*os_build_str);
161 }
162
163 // If we have a build string, only check platforms for which the build
164 // string matches.
165 if (!build.empty()) {
166 for (i = 0; i < num_sdk_infos; ++i)
167 check_sdk_info[i] = m_sdk_directory_infos[i].build.GetStringRef() ==
168 llvm::StringRef(build);
169 }
170
171 // If we are connected we can find the version of the OS the platform us
172 // running on and select the right SDK
173 llvm::VersionTuple version = GetOSVersion();
174 if (!version.empty()) {
176 // First try for an exact match of major, minor and update.
177 for (i = 0; i < num_sdk_infos; ++i) {
178 if (check_sdk_info[i]) {
179 if (m_sdk_directory_infos[i].version == version)
180 return &m_sdk_directory_infos[i];
181 }
182 }
183 // Try for an exact match of major and minor.
184 for (i = 0; i < num_sdk_infos; ++i) {
185 if (check_sdk_info[i]) {
186 if (m_sdk_directory_infos[i].version.getMajor() ==
187 version.getMajor() &&
188 m_sdk_directory_infos[i].version.getMinor() ==
189 version.getMinor()) {
190 return &m_sdk_directory_infos[i];
191 }
192 }
193 }
194 // Lastly try to match of major version only.
195 for (i = 0; i < num_sdk_infos; ++i) {
196 if (check_sdk_info[i]) {
197 if (m_sdk_directory_infos[i].version.getMajor() ==
198 version.getMajor()) {
199 return &m_sdk_directory_infos[i];
200 }
201 }
202 }
203 }
204 } else if (!build.empty()) {
205 // No version, just a build number, return the first one that matches.
206 for (i = 0; i < num_sdk_infos; ++i)
207 if (check_sdk_info[i])
208 return &m_sdk_directory_infos[i];
209 }
210 }
211 return nullptr;
212}
213
216 const PlatformDarwinDevice::SDKDirectoryInfo *result = nullptr;
218 auto max = std::max_element(
220 [](const SDKDirectoryInfo &a, const SDKDirectoryInfo &b) {
221 return a.version < b.version;
222 });
223 if (max != m_sdk_directory_infos.end())
224 result = &*max;
225 }
226 return result;
227}
228
230 std::string platform_dir =
231 ("/Platforms/" + GetPlatformName() + "/DeviceSupport").str();
232 if (m_device_support_directory.empty()) {
233 if (FileSpec fspec = HostInfo::GetXcodeDeveloperDirectory()) {
234 m_device_support_directory = fspec.GetPath();
235 m_device_support_directory.append(platform_dir.c_str());
236 } else {
237 // Assign a single NULL character so we know we tried to find the device
238 // support directory and we don't keep trying to find it over and over.
239 m_device_support_directory.assign(1, '\0');
240 }
241 }
242 // We should have put a single NULL character into m_device_support_directory
243 // or it should have a valid path if the code gets here
244 assert(m_device_support_directory.empty() == false);
246 return m_device_support_directory.c_str();
247 return nullptr;
248}
249
251 if (!m_sdk_sysroot.empty())
252 return m_sdk_sysroot.c_str();
253
255 const PlatformDarwinDevice::SDKDirectoryInfo *sdk_dir_info =
257 if (sdk_dir_info == nullptr)
258 sdk_dir_info = GetSDKDirectoryForLatestOSVersion();
259 if (sdk_dir_info) {
260 char path[PATH_MAX];
261 if (sdk_dir_info->directory.GetPath(path, sizeof(path))) {
264 }
265 } else {
266 // Assign a single NULL character so we know we tried to find the device
267 // support directory and we don't keep trying to find it over and over.
269 }
270 }
271 // We should have put a single NULL character into
272 // m_device_support_directory_for_os_version or it should have a valid path
273 // if the code gets here
274 assert(m_device_support_directory_for_os_version.empty() == false);
277 return nullptr;
278}
279
281MakeCacheFolderForFile(const FileSpec &module_cache_spec) {
282 FileSpec module_cache_folder =
283 module_cache_spec.CopyByRemovingLastPathComponent();
284 return llvm::sys::fs::create_directory(module_cache_folder.GetPath());
285}
286
289 const lldb_private::ModuleSpec &module_spec,
290 const FileSpec &module_cache_spec) {
291 MakeCacheFolderForFile(module_cache_spec);
292 Status err = platform->GetFile(module_spec.GetFileSpec(), module_cache_spec);
293 return err;
294}
295
297 const lldb_private::ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
298 const lldb_private::FileSpecList *module_search_paths_ptr,
299 llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr) {
300
302 LLDB_LOGF(log,
303 "[%s] Trying to find module %s/%s - platform path %s/%s symbol "
304 "path %s/%s",
305 (IsHost() ? "host" : "remote"),
306 module_spec.GetFileSpec().GetDirectory().AsCString(),
307 module_spec.GetFileSpec().GetFilename().AsCString(),
309 module_spec.GetPlatformFileSpec().GetFilename().AsCString(),
310 module_spec.GetSymbolFileSpec().GetDirectory().AsCString(),
311 module_spec.GetSymbolFileSpec().GetFilename().AsCString());
312
313 Status err;
314
315 if (CheckLocalSharedCache()) {
316 // When debugging on the host, we are most likely using the same shared
317 // cache as our inferior. The dylibs from the shared cache might not
318 // exist on the filesystem, so let's use the images in our own memory
319 // to create the modules.
320
321 // Check if the requested image is in our shared cache.
322 SharedCacheImageInfo image_info =
323 HostInfo::GetSharedCacheImageInfo(module_spec.GetFileSpec().GetPath());
324
325 // If we found it and it has the correct UUID, let's proceed with
326 // creating a module from the memory contents.
327 if (image_info.uuid &&
328 (!module_spec.GetUUID() || module_spec.GetUUID() == image_info.uuid)) {
329 ModuleSpec shared_cache_spec(module_spec.GetFileSpec(), image_info.uuid,
330 image_info.data_sp);
331 err = ModuleList::GetSharedModule(shared_cache_spec, module_sp,
332 module_search_paths_ptr, old_modules,
333 did_create_ptr);
334 if (module_sp) {
335 LLDB_LOGF(log, "[%s] module %s was found in the in-memory shared cache",
336 (IsHost() ? "host" : "remote"),
337 module_spec.GetFileSpec().GetPath().c_str());
338 return err;
339 }
340 }
341
342 // We failed to find the module in our shared cache. Let's see if we have a
343 // copy in our device support directory.
344 FileSpec device_support_spec(GetDeviceSupportDirectoryForOSVersion());
345 device_support_spec.AppendPathComponent("Symbols");
346 device_support_spec.AppendPathComponent(
347 module_spec.GetFileSpec().GetPath());
348 FileSystem::Instance().Resolve(device_support_spec);
349 if (FileSystem::Instance().Exists(device_support_spec)) {
350 ModuleSpec local_spec(device_support_spec, module_spec.GetUUID());
351 err = ModuleList::GetSharedModule(local_spec, module_sp,
352 module_search_paths_ptr, old_modules,
353 did_create_ptr);
354 if (module_sp) {
355 LLDB_LOGF(log,
356 "[%s] module %s was found in Device Support "
357 "directory: %s",
358 (IsHost() ? "host" : "remote"),
359 module_spec.GetFileSpec().GetPath().c_str(),
360 local_spec.GetFileSpec().GetPath().c_str());
361 return err;
362 }
363 }
364 }
365
366 err = ModuleList::GetSharedModule(module_spec, module_sp,
367 module_search_paths_ptr, old_modules,
368 did_create_ptr);
369 if (module_sp)
370 return err;
371
372 if (!IsHost()) {
373 std::string cache_path(GetLocalCacheDirectory());
374 // Only search for a locally cached file if we have a valid cache path
375 if (!cache_path.empty()) {
376 std::string module_path(module_spec.GetFileSpec().GetPath());
377 cache_path.append(module_path);
378 FileSpec module_cache_spec(cache_path);
379
380 // if rsync is supported, always bring in the file - rsync will be very
381 // efficient when files are the same on the local and remote end of the
382 // connection
383 if (this->GetSupportsRSync()) {
384 err = BringInRemoteFile(this, module_spec, module_cache_spec);
385 if (err.Fail())
386 return err;
387 if (FileSystem::Instance().Exists(module_cache_spec)) {
389 LLDB_LOGF(log, "[%s] module %s/%s was rsynced and is now there",
390 (IsHost() ? "host" : "remote"),
391 module_spec.GetFileSpec().GetDirectory().AsCString(),
392 module_spec.GetFileSpec().GetFilename().AsCString());
393 ModuleSpec local_spec(module_cache_spec,
394 module_spec.GetArchitecture());
395 module_sp = std::make_shared<Module>(local_spec);
396 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
397 return Status();
398 }
399 }
400
401 // try to find the module in the cache
402 if (FileSystem::Instance().Exists(module_cache_spec)) {
403 // get the local and remote MD5 and compare
405 // when going over the *slow* GDB remote transfer mechanism we first
406 // check the hashes of the files - and only do the actual transfer if
407 // they differ
408 auto MD5 = llvm::sys::fs::md5_contents(module_cache_spec.GetPath());
409 if (!MD5)
410 return Status(MD5.getError());
411
413 bool requires_transfer = true;
414 llvm::ErrorOr<llvm::MD5::MD5Result> remote_md5 =
415 m_remote_platform_sp->CalculateMD5(module_spec.GetFileSpec());
416 if (std::error_code ec = remote_md5.getError())
417 LLDB_LOG(log, "couldn't get md5 sum from remote: {0}",
418 ec.message());
419 else
420 requires_transfer = *MD5 != *remote_md5;
421 if (requires_transfer) {
422 // bring in the remote file
423 LLDB_LOGF(log,
424 "[%s] module %s/%s needs to be replaced from remote copy",
425 (IsHost() ? "host" : "remote"),
426 module_spec.GetFileSpec().GetDirectory().AsCString(),
427 module_spec.GetFileSpec().GetFilename().AsCString());
428 Status err =
429 BringInRemoteFile(this, module_spec, module_cache_spec);
430 if (err.Fail())
431 return err;
432 }
433 }
434
435 ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
436 module_sp = std::make_shared<Module>(local_spec);
437 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
439 LLDB_LOGF(log, "[%s] module %s/%s was found in the cache",
440 (IsHost() ? "host" : "remote"),
441 module_spec.GetFileSpec().GetDirectory().AsCString(),
442 module_spec.GetFileSpec().GetFilename().AsCString());
443 return Status();
444 }
445
446 // bring in the remote module file
447 LLDB_LOGF(log, "[%s] module %s/%s needs to come in remotely",
448 (IsHost() ? "host" : "remote"),
449 module_spec.GetFileSpec().GetDirectory().AsCString(),
450 module_spec.GetFileSpec().GetFilename().AsCString());
451 Status err = BringInRemoteFile(this, module_spec, module_cache_spec);
452 if (err.Fail())
453 return err;
454 if (FileSystem::Instance().Exists(module_cache_spec)) {
456 LLDB_LOGF(log, "[%s] module %s/%s is now cached and fine",
457 (IsHost() ? "host" : "remote"),
458 module_spec.GetFileSpec().GetDirectory().AsCString(),
459 module_spec.GetFileSpec().GetFilename().AsCString());
460 ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
461 module_sp = std::make_shared<Module>(local_spec);
462 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
463 return Status();
464 } else
465 return Status("unable to obtain valid module file");
466 } else
467 return Status("no cache path");
468 } else
469 return Status("unable to resolve module");
470}
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:359
#define LLDB_LOGF(log,...)
Definition: Log.h:366
static lldb_private::Status BringInRemoteFile(Platform *platform, const lldb_private::ModuleSpec &module_spec, const FileSpec &module_cache_spec)
static lldb_private::Status MakeCacheFolderForFile(const FileSpec &module_cache_spec)
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
Definition: ConstString.h:188
A file collection class.
Definition: FileSpecList.h:85
A file utility class.
Definition: FileSpec.h:56
void AppendPathComponent(llvm::StringRef component)
Definition: FileSpec.cpp:447
const ConstString & GetFilename() const
Filename string const get accessor.
Definition: FileSpec.h:240
const ConstString & GetDirectory() const
Directory string const get accessor.
Definition: FileSpec.h:223
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:367
FileSpec CopyByRemovingLastPathComponent() const
Definition: FileSpec.cpp:424
void Resolve(llvm::SmallVectorImpl< char > &path)
Resolve path to make it canonical.
void EnumerateDirectory(llvm::Twine path, bool find_directories, bool find_files, bool find_other, EnumerateDirectoryCallbackType callback, void *callback_baton)
@ eEnumerateDirectoryResultNext
Enumerate next entry in the current directory.
Definition: FileSystem.h:178
static FileSystem & Instance()
static Status GetSharedModule(const ModuleSpec &module_spec, lldb::ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, llvm::SmallVectorImpl< lldb::ModuleSP > *old_modules, bool *did_create_ptr, bool always_create=false)
Definition: ModuleList.cpp:789
FileSpec & GetPlatformFileSpec()
Definition: ModuleSpec.h:65
FileSpec & GetFileSpec()
Definition: ModuleSpec.h:53
ArchSpec & GetArchitecture()
Definition: ModuleSpec.h:89
FileSpec & GetSymbolFileSpec()
Definition: ModuleSpec.h:77
virtual llvm::StringRef GetDeviceSupportDirectoryName()=0
virtual llvm::StringRef GetPlatformName()=0
static FileSystem::EnumerateDirectoryResult GetContainedFilesIntoVectorOfStringsCallback(void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path)
std::vector< SDKDirectoryInfo > SDKDirectoryInfoCollection
const SDKDirectoryInfo * GetSDKDirectoryForCurrentOSVersion()
SDKDirectoryInfoCollection m_sdk_directory_infos
const SDKDirectoryInfo * GetSDKDirectoryForLatestOSVersion()
virtual Status GetSharedModuleWithLocalCache(const ModuleSpec &module_spec, lldb::ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, llvm::SmallVectorImpl< lldb::ModuleSP > *old_modules, bool *did_create_ptr)
llvm::VersionTuple GetOSVersion(Process *process=nullptr) override
Get the OS version from a connected platform.
virtual bool CheckLocalSharedCache() const
A plug-in interface definition class for debug platform that includes many platform abilities such as...
Definition: Platform.h:76
const std::string & GetSDKBuild() const
Definition: Platform.h:512
virtual const char * GetLocalCacheDirectory()
Definition: Platform.cpp:1283
std::optional< std::string > GetOSBuildString()
Definition: Platform.cpp:339
virtual Status GetFile(const FileSpec &source, const FileSpec &destination)
Definition: Platform.cpp:1200
virtual bool GetSupportsRSync()
Definition: Platform.h:613
bool IsHost() const
Definition: Platform.h:478
std::string m_sdk_sysroot
Definition: Platform.h:976
An error handling class.
Definition: Status.h:44
bool Fail() const
Test for error condition.
Definition: Status.cpp:180
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:331
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::Module > ModuleSP
Definition: lldb-forward.h:370
#define PATH_MAX