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"
17#include "lldb/Utility/Log.h"
18#include <optional>
19
20using namespace lldb;
21using namespace lldb_private;
22
24
27 void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) {
28 ((std::vector<FileSpec> *)baton)->push_back(FileSpec(path));
30}
31
33 llvm::StringRef dir, llvm::StringRef log_msg_descriptor) {
34 Log *log = GetLog(LLDBLog::Host);
35 const bool find_directories = true;
36 const bool find_files = false;
37 const bool find_other = false;
38 std::vector<FileSpec> shared_cache_expanded_directories;
40 dir, find_directories, find_files, find_other,
42 &shared_cache_expanded_directories);
43
44 /// shared_cache_expanded_directories will have the directories under \a dir.
45 /// Those that have a /Symbols/ subdir are shared cache dirs.
46 /// Those that have /<arch>/Symbols/ subdirs are shared cache dirs.
47
48 for (const FileSpec &sc_directory : shared_cache_expanded_directories) {
49 FileSpec sc_directory_symbols = sc_directory;
50 sc_directory_symbols.AppendPathComponent("Symbols");
51 if (FileSystem::Instance().Exists(sc_directory_symbols)) {
52 SDKDirectoryInfo thisdir(sc_directory,
53 sc_directory.GetFilename().GetStringRef());
54 m_sdk_directory_infos.push_back(thisdir);
55 LLDB_LOGF(log,
56 "PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded "
57 "added %s %s",
58 log_msg_descriptor.str().c_str(),
59 sc_directory.GetPath().c_str());
60 }
61
62 // See if we have arch subdirs under sc_directory, and if there is
63 // a Symbols subdir under those.
64 std::vector<FileSpec> subdirs;
66 sc_directory.GetPath().c_str(), find_directories, find_files,
68 for (const FileSpec &subdir : subdirs) {
69 FileSpec subdir_directory_symbols = subdir;
70 subdir_directory_symbols.AppendPathComponent("Symbols");
71 if (FileSystem::Instance().Exists(subdir_directory_symbols)) {
72 SDKDirectoryInfo thisdir(subdir,
73 sc_directory.GetFilename().GetStringRef());
74 m_sdk_directory_infos.push_back(thisdir);
75 LLDB_LOGF(log,
76 "PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded "
77 "added %s %s",
78 log_msg_descriptor.str().c_str(), subdir.GetPath().c_str());
79 }
80 }
81 }
82}
83
85 Log *log = GetLog(LLDBLog::Host);
86 std::lock_guard<std::mutex> guard(m_sdk_dir_mutex);
87 if (m_sdk_directory_infos.empty()) {
88
89 // A --sysroot option was supplied - add it to our list of SDKs to check
90 if (!m_sdk_sysroot.empty())
91 AddSharedCacheDirectory(m_sdk_sysroot.c_str(), "--sysroot SDK directory");
92
93 const char *device_support_dir = GetDeviceSupportDirectory();
94 LLDB_LOGF(log,
95 "PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded Got "
96 "DeviceSupport directory %s",
97 device_support_dir);
98 if (device_support_dir) {
99 AddSharedCacheDirectory(device_support_dir, "builtin SDK directory");
100
101 // "macOS DeviceSupport", "iOS DeviceSupport", etc.
102 llvm::StringRef dirname = GetDeviceSupportDirectoryName();
103 std::string local_sdk_cache_str = "~/Library/Developer/Xcode/";
104 local_sdk_cache_str += std::string(dirname);
105 FileSpec local_sdk_cache(local_sdk_cache_str.c_str());
106 FileSystem::Instance().Resolve(local_sdk_cache);
107 if (FileSystem::Instance().Exists(local_sdk_cache)) {
108 LLDB_LOGF(log,
109 "PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded "
110 "searching %s for additional SDKs",
111 local_sdk_cache.GetPath().c_str());
112 AddSharedCacheDirectory(local_sdk_cache.GetPath().c_str(),
113 "system developer dir directory");
114 }
115
116 const char *addtional_platform_dirs = getenv("PLATFORM_SDK_DIRECTORY");
117 if (addtional_platform_dirs)
118 AddSharedCacheDirectory(addtional_platform_dirs,
119 "env var SDK directory");
120 }
121 }
122 return !m_sdk_directory_infos.empty();
123}
124
127 uint32_t i;
129 const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
130 std::vector<bool> check_sdk_info(num_sdk_infos, true);
131
132 // Prefer the user SDK build string.
133 std::string build = GetSDKBuild();
134
135 // Fall back to the platform's build string.
136 if (build.empty()) {
137 if (std::optional<std::string> os_build_str = GetOSBuildString())
138 build.assign(*os_build_str);
139 }
140
141 // If we have a build string, only check platforms for which the build
142 // string matches.
143 if (!build.empty()) {
144 for (i = 0; i < num_sdk_infos; ++i)
145 check_sdk_info[i] = m_sdk_directory_infos[i].build.GetStringRef() ==
146 llvm::StringRef(build);
147 }
148
149 // If we are connected we can find the version of the OS the platform us
150 // running on and select the right SDK
151 llvm::VersionTuple version = GetOSVersion();
152 if (!version.empty()) {
154 // First try for an exact match of major, minor and update.
155 for (i = 0; i < num_sdk_infos; ++i) {
156 if (check_sdk_info[i]) {
157 if (m_sdk_directory_infos[i].version == version)
158 return &m_sdk_directory_infos[i];
159 }
160 }
161 // Try for an exact match of major and minor.
162 for (i = 0; i < num_sdk_infos; ++i) {
163 if (check_sdk_info[i]) {
164 if (m_sdk_directory_infos[i].version.getMajor() ==
165 version.getMajor() &&
166 m_sdk_directory_infos[i].version.getMinor() ==
167 version.getMinor()) {
168 return &m_sdk_directory_infos[i];
169 }
170 }
171 }
172 // Lastly try to match of major version only.
173 for (i = 0; i < num_sdk_infos; ++i) {
174 if (check_sdk_info[i]) {
175 if (m_sdk_directory_infos[i].version.getMajor() ==
176 version.getMajor()) {
177 return &m_sdk_directory_infos[i];
178 }
179 }
180 }
181 }
182 } else if (!build.empty()) {
183 // No version, just a build number, return the first one that matches.
184 for (i = 0; i < num_sdk_infos; ++i)
185 if (check_sdk_info[i])
186 return &m_sdk_directory_infos[i];
187 }
188 }
189 return nullptr;
190}
191
194 const PlatformDarwinDevice::SDKDirectoryInfo *result = nullptr;
196 auto max = std::max_element(
198 [](const SDKDirectoryInfo &a, const SDKDirectoryInfo &b) {
199 return a.version < b.version;
200 });
201 if (max != m_sdk_directory_infos.end())
202 result = &*max;
203 }
204 return result;
205}
206
208 std::string platform_dir =
209 ("/Platforms/" + GetPlatformName() + "/DeviceSupport").str();
210 if (m_device_support_directory.empty()) {
211 if (FileSpec fspec = HostInfo::GetXcodeDeveloperDirectory()) {
212 m_device_support_directory = fspec.GetPath();
213 m_device_support_directory.append(platform_dir.c_str());
214 } else {
215 // Assign a single NULL character so we know we tried to find the device
216 // support directory and we don't keep trying to find it over and over.
217 m_device_support_directory.assign(1, '\0');
218 }
219 }
220 // We should have put a single NULL character into m_device_support_directory
221 // or it should have a valid path if the code gets here
222 assert(m_device_support_directory.empty() == false);
224 return m_device_support_directory.c_str();
225 return nullptr;
226}
227
229 if (!m_sdk_sysroot.empty())
230 return m_sdk_sysroot.c_str();
231
233 const PlatformDarwinDevice::SDKDirectoryInfo *sdk_dir_info =
235 if (sdk_dir_info == nullptr)
236 sdk_dir_info = GetSDKDirectoryForLatestOSVersion();
237 if (sdk_dir_info) {
238 char path[PATH_MAX];
239 if (sdk_dir_info->directory.GetPath(path, sizeof(path))) {
242 }
243 } else {
244 // Assign a single NULL character so we know we tried to find the device
245 // support directory and we don't keep trying to find it over and over.
247 }
248 }
249 // We should have put a single NULL character into
250 // m_device_support_directory_for_os_version or it should have a valid path
251 // if the code gets here
252 assert(m_device_support_directory_for_os_version.empty() == false);
255 return nullptr;
256}
257
259MakeCacheFolderForFile(const FileSpec &module_cache_spec) {
260 FileSpec module_cache_folder =
261 module_cache_spec.CopyByRemovingLastPathComponent();
262 return llvm::sys::fs::create_directory(module_cache_folder.GetPath());
263}
264
267 const lldb_private::ModuleSpec &module_spec,
268 const FileSpec &module_cache_spec) {
269 MakeCacheFolderForFile(module_cache_spec);
270 Status err = platform->GetFile(module_spec.GetFileSpec(), module_cache_spec);
271 return err;
272}
273
275 const lldb_private::ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
276 llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr,
277 Process *process) {
278
280 LLDB_LOGF(log,
281 "[%s] Trying to find module %s/%s - platform path %s/%s symbol "
282 "path %s/%s",
283 (IsHost() ? "host" : "remote"),
284 module_spec.GetFileSpec().GetDirectory().AsCString(),
285 module_spec.GetFileSpec().GetFilename().AsCString(),
287 module_spec.GetPlatformFileSpec().GetFilename().AsCString(),
288 module_spec.GetSymbolFileSpec().GetDirectory().AsCString(),
289 module_spec.GetSymbolFileSpec().GetFilename().AsCString());
290
291 Status err;
292
293 if (CheckLocalSharedCache()) {
294 err = GetModuleFromSharedCaches(module_spec, process, module_sp,
295 old_modules, did_create_ptr);
296 if (module_sp)
297 return err;
298 }
299
300 // We failed to find the module in our shared cache. Let's see if we have a
301 // copy in our device support directory.
302 FileSpec device_support_spec(GetDeviceSupportDirectoryForOSVersion());
303 device_support_spec.AppendPathComponent("Symbols");
304 device_support_spec.AppendPathComponent(
305 module_spec.GetFileSpec().GetPath());
306 FileSystem::Instance().Resolve(device_support_spec);
307 if (FileSystem::Instance().Exists(device_support_spec)) {
308 ModuleSpec local_spec(device_support_spec, module_spec.GetUUID());
309 err = ModuleList::GetSharedModule(local_spec, module_sp, old_modules,
310 did_create_ptr);
311 if (module_sp) {
312 LLDB_LOGF(log,
313 "[%s] module %s was found in Device Support "
314 "directory: %s",
315 (IsHost() ? "host" : "remote"),
316 module_spec.GetFileSpec().GetPath().c_str(),
317 local_spec.GetFileSpec().GetPath().c_str());
318 return err;
319 }
320 }
321
322 err = ModuleList::GetSharedModule(module_spec, module_sp, old_modules,
323 did_create_ptr);
324 if (module_sp)
325 return err;
326
327 if (!IsHost()) {
328 std::string cache_path(GetLocalCacheDirectory());
329 // Only search for a locally cached file if we have a valid cache path
330 if (!cache_path.empty()) {
331 std::string module_path(module_spec.GetFileSpec().GetPath());
332 cache_path.append(module_path);
333 FileSpec module_cache_spec(cache_path);
334
335 // if rsync is supported, always bring in the file - rsync will be very
336 // efficient when files are the same on the local and remote end of the
337 // connection
338 if (this->GetSupportsRSync()) {
339 err = BringInRemoteFile(this, module_spec, module_cache_spec);
340 if (err.Fail())
341 return err;
342 if (FileSystem::Instance().Exists(module_cache_spec)) {
344 LLDB_LOGF(log, "[%s] module %s/%s was rsynced and is now there",
345 (IsHost() ? "host" : "remote"),
346 module_spec.GetFileSpec().GetDirectory().AsCString(),
347 module_spec.GetFileSpec().GetFilename().AsCString());
348 ModuleSpec local_spec(module_cache_spec,
349 module_spec.GetArchitecture());
350 module_sp = std::make_shared<Module>(local_spec);
351 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
352 return Status();
353 }
354 }
355
356 // try to find the module in the cache
357 if (FileSystem::Instance().Exists(module_cache_spec)) {
358 // get the local and remote MD5 and compare
360 // when going over the *slow* GDB remote transfer mechanism we first
361 // check the hashes of the files - and only do the actual transfer if
362 // they differ
363 auto MD5 = llvm::sys::fs::md5_contents(module_cache_spec.GetPath());
364 if (!MD5)
365 return Status(MD5.getError());
366
368 bool requires_transfer = true;
369 llvm::ErrorOr<llvm::MD5::MD5Result> remote_md5 =
370 m_remote_platform_sp->CalculateMD5(module_spec.GetFileSpec());
371 if (std::error_code ec = remote_md5.getError())
372 LLDB_LOG(log, "couldn't get md5 sum from remote: {0}",
373 ec.message());
374 else
375 requires_transfer = *MD5 != *remote_md5;
376 if (requires_transfer) {
377 // bring in the remote file
378 LLDB_LOGF(log,
379 "[%s] module %s/%s needs to be replaced from remote copy",
380 (IsHost() ? "host" : "remote"),
381 module_spec.GetFileSpec().GetDirectory().AsCString(),
382 module_spec.GetFileSpec().GetFilename().AsCString());
383 Status err =
384 BringInRemoteFile(this, module_spec, module_cache_spec);
385 if (err.Fail())
386 return err;
387 }
388 }
389
390 ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
391 module_sp = std::make_shared<Module>(local_spec);
392 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
394 LLDB_LOGF(log, "[%s] module %s/%s was found in the cache",
395 (IsHost() ? "host" : "remote"),
396 module_spec.GetFileSpec().GetDirectory().AsCString(),
397 module_spec.GetFileSpec().GetFilename().AsCString());
398 return Status();
399 }
400
401 // bring in the remote module file
402 LLDB_LOGF(log, "[%s] module %s/%s needs to come in remotely",
403 (IsHost() ? "host" : "remote"),
404 module_spec.GetFileSpec().GetDirectory().AsCString(),
405 module_spec.GetFileSpec().GetFilename().AsCString());
406 Status err = BringInRemoteFile(this, module_spec, module_cache_spec);
407 if (err.Fail())
408 return err;
409 if (FileSystem::Instance().Exists(module_cache_spec)) {
411 LLDB_LOGF(log, "[%s] module %s/%s is now cached and fine",
412 (IsHost() ? "host" : "remote"),
413 module_spec.GetFileSpec().GetDirectory().AsCString(),
414 module_spec.GetFileSpec().GetFilename().AsCString());
415 ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
416 module_sp = std::make_shared<Module>(local_spec);
417 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
418 return Status();
419 } else
420 return Status::FromErrorString("unable to obtain valid module file");
421 } else
422 return Status::FromErrorString("no cache path");
423 } else
424 return Status::FromErrorString("unable to resolve module");
425}
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:369
#define LLDB_LOGF(log,...)
Definition Log.h:383
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.
A file utility class.
Definition FileSpec.h:57
void AppendPathComponent(llvm::StringRef component)
Definition FileSpec.cpp:454
const ConstString & GetFilename() const
Filename string const get accessor.
Definition FileSpec.h:250
const ConstString & GetDirectory() const
Directory string const get accessor.
Definition FileSpec.h:234
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition FileSpec.cpp:374
FileSpec CopyByRemovingLastPathComponent() const
Definition FileSpec.cpp:431
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:182
static FileSystem & Instance()
void Resolve(llvm::SmallVectorImpl< char > &path, bool force_make_absolute=false)
Resolve path to make it canonical.
static Status GetSharedModule(const ModuleSpec &module_spec, lldb::ModuleSP &module_sp, llvm::SmallVectorImpl< lldb::ModuleSP > *old_modules, bool *did_create_ptr, bool invoke_locate_callback=true)
FileSpec & GetPlatformFileSpec()
Definition ModuleSpec.h:69
FileSpec & GetFileSpec()
Definition ModuleSpec.h:57
ArchSpec & GetArchitecture()
Definition ModuleSpec.h:93
FileSpec & GetSymbolFileSpec()
Definition ModuleSpec.h:81
static FileSystem::EnumerateDirectoryResult GetContainedFilesIntoVectorOfFileSpecsCallback(void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path)
virtual llvm::StringRef GetDeviceSupportDirectoryName()=0
virtual llvm::StringRef GetPlatformName()=0
const SDKDirectoryInfo * GetSDKDirectoryForCurrentOSVersion()
SDKDirectoryInfoCollection m_sdk_directory_infos
const SDKDirectoryInfo * GetSDKDirectoryForLatestOSVersion()
void AddSharedCacheDirectory(llvm::StringRef dir, llvm::StringRef log_msg_descriptor)
Look for expanded shared cache directories under the given dir.
virtual Status GetSharedModuleWithLocalCache(const ModuleSpec &module_spec, lldb::ModuleSP &module_sp, llvm::SmallVectorImpl< lldb::ModuleSP > *old_modules, bool *did_create_ptr, lldb_private::Process *process)
Status GetModuleFromSharedCaches(const ModuleSpec &module_spec, Process *process, lldb::ModuleSP &module_sp, 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:79
const std::string & GetSDKBuild() const
Definition Platform.h:557
virtual const char * GetLocalCacheDirectory()
std::optional< std::string > GetOSBuildString()
Definition Platform.cpp:415
virtual Status GetFile(const FileSpec &source, const FileSpec &destination)
virtual bool GetSupportsRSync()
Definition Platform.h:658
bool IsHost() const
Definition Platform.h:523
std::string m_sdk_sysroot
Definition Platform.h:1029
A plug-in interface definition class for debugging a process.
Definition Process.h:354
An error handling class.
Definition Status.h:118
static Status FromErrorString(const char *str)
Definition Status.h:141
bool Fail() const
Test for error condition.
Definition Status.cpp:293
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:332
std::shared_ptr< lldb_private::Module > ModuleSP
#define PATH_MAX