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