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.
100 llvm::StringRef dirname = GetDeviceSupportDirectoryName();
101 std::string local_sdk_cache_str = "~/Library/Developer/Xcode/";
102 local_sdk_cache_str += std::string(dirname);
103 FileSpec local_sdk_cache(local_sdk_cache_str.c_str());
104 FileSystem::Instance().Resolve(local_sdk_cache);
105 if (FileSystem::Instance().Exists(local_sdk_cache)) {
106 LLDB_LOGF(log,
107 "PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded "
108 "searching %s for additional SDKs",
109 local_sdk_cache.GetPath().c_str());
110 AddSharedCacheDirectory(local_sdk_cache.GetPath().c_str(),
111 "system developer dir directory");
112 }
113
114 const char *addtional_platform_dirs = getenv("PLATFORM_SDK_DIRECTORY");
115 if (addtional_platform_dirs)
116 AddSharedCacheDirectory(addtional_platform_dirs,
117 "env var SDK directory");
118 }
119 }
120 return !m_sdk_directory_infos.empty();
121}
122
125 uint32_t i;
127 const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
128 std::vector<bool> check_sdk_info(num_sdk_infos, true);
129
130 // Prefer the user SDK build string.
131 std::string build = GetSDKBuild();
132
133 // Fall back to the platform's build string.
134 if (build.empty()) {
135 if (std::optional<std::string> os_build_str = GetOSBuildString())
136 build.assign(*os_build_str);
137 }
138
139 // If we have a build string, only check platforms for which the build
140 // string matches.
141 if (!build.empty()) {
142 for (i = 0; i < num_sdk_infos; ++i)
143 check_sdk_info[i] = m_sdk_directory_infos[i].build.GetStringRef() ==
144 llvm::StringRef(build);
145 }
146
147 // If we are connected we can find the version of the OS the platform us
148 // running on and select the right SDK
149 llvm::VersionTuple version = GetOSVersion();
150 if (!version.empty()) {
152 // First try for an exact match of major, minor and update.
153 for (i = 0; i < num_sdk_infos; ++i) {
154 if (check_sdk_info[i]) {
155 if (m_sdk_directory_infos[i].version == version)
156 return &m_sdk_directory_infos[i];
157 }
158 }
159 // Try for an exact match of major and minor.
160 for (i = 0; i < num_sdk_infos; ++i) {
161 if (check_sdk_info[i]) {
162 if (m_sdk_directory_infos[i].version.getMajor() ==
163 version.getMajor() &&
164 m_sdk_directory_infos[i].version.getMinor() ==
165 version.getMinor()) {
166 return &m_sdk_directory_infos[i];
167 }
168 }
169 }
170 // Lastly try to match of major version only.
171 for (i = 0; i < num_sdk_infos; ++i) {
172 if (check_sdk_info[i]) {
173 if (m_sdk_directory_infos[i].version.getMajor() ==
174 version.getMajor()) {
175 return &m_sdk_directory_infos[i];
176 }
177 }
178 }
179 }
180 } else if (!build.empty()) {
181 // No version, just a build number, return the first one that matches.
182 for (i = 0; i < num_sdk_infos; ++i)
183 if (check_sdk_info[i])
184 return &m_sdk_directory_infos[i];
185 }
186 }
187 return nullptr;
188}
189
192 const PlatformDarwinDevice::SDKDirectoryInfo *result = nullptr;
194 auto max = std::max_element(
196 [](const SDKDirectoryInfo &a, const SDKDirectoryInfo &b) {
197 return a.version < b.version;
198 });
199 if (max != m_sdk_directory_infos.end())
200 result = &*max;
201 }
202 return result;
203}
204
206 std::string platform_dir =
207 ("/Platforms/" + GetPlatformName() + "/DeviceSupport").str();
208 if (m_device_support_directory.empty()) {
209 if (FileSpec fspec = HostInfo::GetXcodeDeveloperDirectory()) {
210 m_device_support_directory = fspec.GetPath();
211 m_device_support_directory.append(platform_dir.c_str());
212 } else {
213 // Assign a single NULL character so we know we tried to find the device
214 // support directory and we don't keep trying to find it over and over.
215 m_device_support_directory.assign(1, '\0');
216 }
217 }
218 // We should have put a single NULL character into m_device_support_directory
219 // or it should have a valid path if the code gets here
220 assert(m_device_support_directory.empty() == false);
222 return m_device_support_directory.c_str();
223 return nullptr;
224}
225
227 if (!m_sdk_sysroot.empty())
228 return m_sdk_sysroot.c_str();
229
231 const PlatformDarwinDevice::SDKDirectoryInfo *sdk_dir_info =
233 if (sdk_dir_info == nullptr)
234 sdk_dir_info = GetSDKDirectoryForLatestOSVersion();
235 if (sdk_dir_info) {
236 char path[PATH_MAX];
237 if (sdk_dir_info->directory.GetPath(path, sizeof(path))) {
240 }
241 } else {
242 // Assign a single NULL character so we know we tried to find the device
243 // support directory and we don't keep trying to find it over and over.
245 }
246 }
247 // We should have put a single NULL character into
248 // m_device_support_directory_for_os_version or it should have a valid path
249 // if the code gets here
250 assert(m_device_support_directory_for_os_version.empty() == false);
253 return nullptr;
254}
255
257MakeCacheFolderForFile(const FileSpec &module_cache_spec) {
258 FileSpec module_cache_folder =
259 module_cache_spec.CopyByRemovingLastPathComponent();
260 return llvm::sys::fs::create_directory(module_cache_folder.GetPath());
261}
262
265 const lldb_private::ModuleSpec &module_spec,
266 const FileSpec &module_cache_spec) {
267 MakeCacheFolderForFile(module_cache_spec);
268 Status err = platform->GetFile(module_spec.GetFileSpec(), module_cache_spec);
269 return err;
270}
271
273 const lldb_private::ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
274 llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr,
275 Process *process) {
276
278 LLDB_LOG(log,
279 "[{0}] Trying to find module {1}/{2} - platform path {3}/{4} symbol "
280 "path {5}/{6}",
281 (IsHost() ? "host" : "remote"),
282 module_spec.GetFileSpec().GetDirectory(),
283 module_spec.GetFileSpec().GetFilename(),
284 module_spec.GetPlatformFileSpec().GetDirectory(),
285 module_spec.GetPlatformFileSpec().GetFilename(),
286 module_spec.GetSymbolFileSpec().GetDirectory(),
287 module_spec.GetSymbolFileSpec().GetFilename());
288
289 Status err;
290
291 if (CheckLocalSharedCache()) {
292 err = GetModuleFromSharedCaches(module_spec, process, module_sp,
293 old_modules, did_create_ptr);
294 if (module_sp)
295 return err;
296 }
297
298 // We failed to find the module in our shared cache. Let's see if we have a
299 // copy in our device support directory.
300 FileSpec device_support_spec(GetDeviceSupportDirectoryForOSVersion());
301 device_support_spec.AppendPathComponent("Symbols");
302 device_support_spec.AppendPathComponent(
303 module_spec.GetFileSpec().GetPath());
304 FileSystem::Instance().Resolve(device_support_spec);
305 if (FileSystem::Instance().Exists(device_support_spec)) {
306 ModuleSpec local_spec(device_support_spec, module_spec.GetUUID());
307 err = ModuleList::GetSharedModule(local_spec, module_sp, old_modules,
308 did_create_ptr);
309 if (module_sp) {
310 LLDB_LOGF(log,
311 "[%s] module %s was found in Device Support "
312 "directory: %s",
313 (IsHost() ? "host" : "remote"),
314 module_spec.GetFileSpec().GetPath().c_str(),
315 local_spec.GetFileSpec().GetPath().c_str());
316 return err;
317 }
318 }
319
320 err = ModuleList::GetSharedModule(module_spec, module_sp, old_modules,
321 did_create_ptr);
322 if (module_sp)
323 return err;
324
325 if (!IsHost()) {
326 std::string cache_path(GetLocalCacheDirectory());
327 // Only search for a locally cached file if we have a valid cache path
328 if (!cache_path.empty()) {
329 std::string module_path(module_spec.GetFileSpec().GetPath());
330 cache_path.append(module_path);
331 FileSpec module_cache_spec(cache_path);
332
333 // if rsync is supported, always bring in the file - rsync will be very
334 // efficient when files are the same on the local and remote end of the
335 // connection
336 if (this->GetSupportsRSync()) {
337 err = BringInRemoteFile(this, module_spec, module_cache_spec);
338 if (err.Fail())
339 return err;
340 if (FileSystem::Instance().Exists(module_cache_spec)) {
342 LLDB_LOG(log, "[{0}] module {1}/{2} was rsynced and is now there",
343 (IsHost() ? "host" : "remote"),
344 module_spec.GetFileSpec().GetDirectory(),
345 module_spec.GetFileSpec().GetFilename());
346 ModuleSpec local_spec(module_cache_spec,
347 module_spec.GetArchitecture());
348 module_sp = std::make_shared<Module>(local_spec);
349 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
350 return Status();
351 }
352 }
353
354 // try to find the module in the cache
355 if (FileSystem::Instance().Exists(module_cache_spec)) {
356 // get the local and remote MD5 and compare
358 // when going over the *slow* GDB remote transfer mechanism we first
359 // check the hashes of the files - and only do the actual transfer if
360 // they differ
361 auto MD5 = llvm::sys::fs::md5_contents(module_cache_spec.GetPath());
362 if (!MD5)
363 return Status(MD5.getError());
364
366 bool requires_transfer = true;
367 llvm::ErrorOr<llvm::MD5::MD5Result> remote_md5 =
368 m_remote_platform_sp->CalculateMD5(module_spec.GetFileSpec());
369 if (std::error_code ec = remote_md5.getError())
370 LLDB_LOG(log, "couldn't get md5 sum from remote: {0}",
371 ec.message());
372 else
373 requires_transfer = *MD5 != *remote_md5;
374 if (requires_transfer) {
375 // bring in the remote file
376 LLDB_LOG(
377 log,
378 "[{0}] module {1}/{2} needs to be replaced from remote copy",
379 (IsHost() ? "host" : "remote"),
380 module_spec.GetFileSpec().GetDirectory(),
381 module_spec.GetFileSpec().GetFilename());
382 Status err =
383 BringInRemoteFile(this, module_spec, module_cache_spec);
384 if (err.Fail())
385 return err;
386 }
387 }
388
389 ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
390 module_sp = std::make_shared<Module>(local_spec);
391 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
393 LLDB_LOG(log, "[{0}] module {1}/{2} was found in the cache",
394 (IsHost() ? "host" : "remote"),
395 module_spec.GetFileSpec().GetDirectory(),
396 module_spec.GetFileSpec().GetFilename());
397 return Status();
398 }
399
400 // bring in the remote module file
401 LLDB_LOG(log, "[{0}] module {1}/{2} needs to come in remotely",
402 (IsHost() ? "host" : "remote"),
403 module_spec.GetFileSpec().GetDirectory(),
404 module_spec.GetFileSpec().GetFilename());
405 Status err = BringInRemoteFile(this, module_spec, module_cache_spec);
406 if (err.Fail())
407 return err;
408 if (FileSystem::Instance().Exists(module_cache_spec)) {
410 LLDB_LOG(log, "[{0}] module {1}/{2} is now cached and fine",
411 (IsHost() ? "host" : "remote"),
412 module_spec.GetFileSpec().GetDirectory(),
413 module_spec.GetFileSpec().GetFilename());
414 ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
415 module_sp = std::make_shared<Module>(local_spec);
416 module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
417 return Status();
418 } else
419 return Status::FromErrorString("unable to obtain valid module file");
420 } else
421 return Status::FromErrorString("no cache path");
422 } else
423 return Status::FromErrorString("unable to resolve module");
424}
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:376
#define LLDB_LOGF(log,...)
Definition Log.h:390
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:57
void AppendPathComponent(llvm::StringRef component)
Definition FileSpec.cpp:452
llvm::StringRef GetFilename() const
Filename string const get accessor.
Definition FileSpec.h:249
llvm::StringRef 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:376
FileSpec CopyByRemovingLastPathComponent() const
Definition FileSpec.cpp:429
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:591
virtual const char * GetLocalCacheDirectory()
std::optional< std::string > GetOSBuildString()
Definition Platform.cpp:433
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
A plug-in interface definition class for debugging a process.
Definition Process.h:359
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:339
std::shared_ptr< lldb_private::Module > ModuleSP
#define PATH_MAX