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