LLDB  mainline
LocateSymbolFileMacOSX.cpp
Go to the documentation of this file.
1 //===-- LocateSymbolFileMacOSX.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 
11 #include <dirent.h>
12 #include <dlfcn.h>
13 #include <pwd.h>
14 
15 #include <CoreFoundation/CoreFoundation.h>
16 
21 #include "lldb/Core/Module.h"
22 #include "lldb/Core/ModuleList.h"
23 #include "lldb/Core/ModuleSpec.h"
24 #include "lldb/Host/Host.h"
25 #include "lldb/Host/HostInfo.h"
26 #include "lldb/Symbol/ObjectFile.h"
27 #include "lldb/Utility/ArchSpec.h"
30 #include "lldb/Utility/Endian.h"
31 #include "lldb/Utility/LLDBLog.h"
32 #include "lldb/Utility/Log.h"
34 #include "lldb/Utility/Timer.h"
35 #include "lldb/Utility/UUID.h"
36 #include "mach/machine.h"
37 
38 #include "llvm/ADT/ScopeExit.h"
39 #include "llvm/Support/FileSystem.h"
40 
41 using namespace lldb;
42 using namespace lldb_private;
43 
45  CFUUIDRef uuid, CFURLRef exec_url) = nullptr;
46 static CFDictionaryRef (*g_dlsym_DBGCopyDSYMPropertyLists)(CFURLRef dsym_url) =
47  nullptr;
48 
50  ModuleSpec &return_module_spec) {
51  Log *log = GetLog(LLDBLog::Host);
52  if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) {
53  LLDB_LOGF(log, "Spotlight lookup for .dSYM bundles is disabled.");
54  return 0;
55  }
56 
57  return_module_spec = module_spec;
58  return_module_spec.GetFileSpec().Clear();
59  return_module_spec.GetSymbolFileSpec().Clear();
60 
61  const UUID *uuid = module_spec.GetUUIDPtr();
62  const ArchSpec *arch = module_spec.GetArchitecturePtr();
63 
64  int items_found = 0;
65 
66  if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr ||
68  void *handle = dlopen(
69  "/System/Library/PrivateFrameworks/DebugSymbols.framework/DebugSymbols",
70  RTLD_LAZY | RTLD_LOCAL);
71  if (handle) {
73  (CFURLRef(*)(CFUUIDRef, CFURLRef))dlsym(handle,
74  "DBGCopyFullDSYMURLForUUID");
75  g_dlsym_DBGCopyDSYMPropertyLists = (CFDictionaryRef(*)(CFURLRef))dlsym(
76  handle, "DBGCopyDSYMPropertyLists");
77  }
78  }
79 
80  if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr ||
82  return items_found;
83  }
84 
85  if (uuid && uuid->IsValid()) {
86  // Try and locate the dSYM file using DebugSymbols first
87  llvm::ArrayRef<uint8_t> module_uuid = uuid->GetBytes();
88  if (module_uuid.size() == 16) {
89  CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes(
90  NULL, module_uuid[0], module_uuid[1], module_uuid[2], module_uuid[3],
91  module_uuid[4], module_uuid[5], module_uuid[6], module_uuid[7],
92  module_uuid[8], module_uuid[9], module_uuid[10], module_uuid[11],
93  module_uuid[12], module_uuid[13], module_uuid[14], module_uuid[15]));
94 
95  if (module_uuid_ref.get()) {
96  CFCReleaser<CFURLRef> exec_url;
97  const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
98  if (exec_fspec) {
99  char exec_cf_path[PATH_MAX];
100  if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path)))
101  exec_url.reset(::CFURLCreateFromFileSystemRepresentation(
102  NULL, (const UInt8 *)exec_cf_path, strlen(exec_cf_path),
103  FALSE));
104  }
105 
107  module_uuid_ref.get(), exec_url.get()));
108  char path[PATH_MAX];
109 
110  if (dsym_url.get()) {
111  if (::CFURLGetFileSystemRepresentation(
112  dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
113  LLDB_LOGF(log,
114  "DebugSymbols framework returned dSYM path of %s for "
115  "UUID %s -- looking for the dSYM",
116  path, uuid->GetAsString().c_str());
117  FileSpec dsym_filespec(path);
118  if (path[0] == '~')
119  FileSystem::Instance().Resolve(dsym_filespec);
120 
121  if (FileSystem::Instance().IsDirectory(dsym_filespec)) {
122  dsym_filespec =
123  Symbols::FindSymbolFileInBundle(dsym_filespec, uuid, arch);
124  ++items_found;
125  } else {
126  ++items_found;
127  }
128  return_module_spec.GetSymbolFileSpec() = dsym_filespec;
129  }
130 
131  bool success = false;
132  if (log) {
133  if (::CFURLGetFileSystemRepresentation(
134  dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
135  LLDB_LOGF(log,
136  "DebugSymbols framework returned dSYM path of %s for "
137  "UUID %s -- looking for an exec file",
138  path, uuid->GetAsString().c_str());
139  }
140  }
141 
143  g_dlsym_DBGCopyDSYMPropertyLists(dsym_url.get()));
144  CFDictionaryRef uuid_dict = NULL;
145  if (dict.get()) {
146  CFCString uuid_cfstr(uuid->GetAsString().c_str());
147  uuid_dict = static_cast<CFDictionaryRef>(
148  ::CFDictionaryGetValue(dict.get(), uuid_cfstr.get()));
149  }
150 
151  // Check to see if we have the file on the local filesystem.
152  if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
153  ModuleSpec exe_spec;
154  exe_spec.GetFileSpec() = module_spec.GetFileSpec();
155  exe_spec.GetUUID() = module_spec.GetUUID();
156  ModuleSP module_sp;
157  module_sp.reset(new Module(exe_spec));
158  if (module_sp && module_sp->GetObjectFile() &&
159  module_sp->MatchesModuleSpec(exe_spec)) {
160  success = true;
161  return_module_spec.GetFileSpec() = module_spec.GetFileSpec();
162  LLDB_LOGF(log, "using original binary filepath %s for UUID %s",
163  module_spec.GetFileSpec().GetPath().c_str(),
164  uuid->GetAsString().c_str());
165  ++items_found;
166  }
167  }
168 
169  // Check if the requested image is in our shared cache.
170  if (!success) {
171  SharedCacheImageInfo image_info = HostInfo::GetSharedCacheImageInfo(
172  module_spec.GetFileSpec().GetPath());
173 
174  // If we found it and it has the correct UUID, let's proceed with
175  // creating a module from the memory contents.
176  if (image_info.uuid && (!module_spec.GetUUID() ||
177  module_spec.GetUUID() == image_info.uuid)) {
178  success = true;
179  return_module_spec.GetFileSpec() = module_spec.GetFileSpec();
180  LLDB_LOGF(log,
181  "using binary from shared cache for filepath %s for "
182  "UUID %s",
183  module_spec.GetFileSpec().GetPath().c_str(),
184  uuid->GetAsString().c_str());
185  ++items_found;
186  }
187  }
188 
189  // Use the DBGSymbolRichExecutable filepath if present
190  if (!success && uuid_dict) {
191  CFStringRef exec_cf_path =
192  static_cast<CFStringRef>(::CFDictionaryGetValue(
193  uuid_dict, CFSTR("DBGSymbolRichExecutable")));
194  if (exec_cf_path && ::CFStringGetFileSystemRepresentation(
195  exec_cf_path, path, sizeof(path))) {
196  LLDB_LOGF(log, "plist bundle has exec path of %s for UUID %s",
197  path, uuid->GetAsString().c_str());
198  ++items_found;
199  FileSpec exec_filespec(path);
200  if (path[0] == '~')
201  FileSystem::Instance().Resolve(exec_filespec);
202  if (FileSystem::Instance().Exists(exec_filespec)) {
203  success = true;
204  return_module_spec.GetFileSpec() = exec_filespec;
205  }
206  }
207  }
208 
209  // Look next to the dSYM for the binary file.
210  if (!success) {
211  if (::CFURLGetFileSystemRepresentation(
212  dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
213  char *dsym_extension_pos = ::strstr(path, ".dSYM");
214  if (dsym_extension_pos) {
215  *dsym_extension_pos = '\0';
216  LLDB_LOGF(log,
217  "Looking for executable binary next to dSYM "
218  "bundle with name with name %s",
219  path);
220  FileSpec file_spec(path);
221  FileSystem::Instance().Resolve(file_spec);
222  ModuleSpecList module_specs;
223  ModuleSpec matched_module_spec;
224  using namespace llvm::sys::fs;
225  switch (get_file_type(file_spec.GetPath())) {
226 
227  case file_type::directory_file: // Bundle directory?
228  {
229  CFCBundle bundle(path);
230  CFCReleaser<CFURLRef> bundle_exe_url(
231  bundle.CopyExecutableURL());
232  if (bundle_exe_url.get()) {
233  if (::CFURLGetFileSystemRepresentation(bundle_exe_url.get(),
234  true, (UInt8 *)path,
235  sizeof(path) - 1)) {
236  FileSpec bundle_exe_file_spec(path);
237  FileSystem::Instance().Resolve(bundle_exe_file_spec);
238  if (ObjectFile::GetModuleSpecifications(
239  bundle_exe_file_spec, 0, 0, module_specs) &&
240  module_specs.FindMatchingModuleSpec(
241  module_spec, matched_module_spec))
242 
243  {
244  ++items_found;
245  return_module_spec.GetFileSpec() = bundle_exe_file_spec;
246  LLDB_LOGF(log,
247  "Executable binary %s next to dSYM is "
248  "compatible; using",
249  path);
250  }
251  }
252  }
253  } break;
254 
255  case file_type::fifo_file: // Forget pipes
256  case file_type::socket_file: // We can't process socket files
257  case file_type::file_not_found: // File doesn't exist...
258  case file_type::status_error:
259  break;
260 
261  case file_type::type_unknown:
262  case file_type::regular_file:
263  case file_type::symlink_file:
264  case file_type::block_file:
265  case file_type::character_file:
266  if (ObjectFile::GetModuleSpecifications(file_spec, 0, 0,
267  module_specs) &&
268  module_specs.FindMatchingModuleSpec(module_spec,
269  matched_module_spec))
270 
271  {
272  ++items_found;
273  return_module_spec.GetFileSpec() = file_spec;
274  LLDB_LOGF(log,
275  "Executable binary %s next to dSYM is "
276  "compatible; using",
277  path);
278  }
279  break;
280  }
281  }
282  }
283  }
284  }
285  }
286  }
287  }
288 
289  return items_found;
290 }
291 
292 FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec,
293  const lldb_private::UUID *uuid,
294  const ArchSpec *arch) {
295  std::string dsym_bundle_path = dsym_bundle_fspec.GetPath();
296  llvm::SmallString<128> buffer(dsym_bundle_path);
297  llvm::sys::path::append(buffer, "Contents", "Resources", "DWARF");
298 
299  std::error_code EC;
300  llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs =
301  FileSystem::Instance().GetVirtualFileSystem();
302  llvm::vfs::recursive_directory_iterator Iter(*vfs, buffer.str(), EC);
303  llvm::vfs::recursive_directory_iterator End;
304  for (; Iter != End && !EC; Iter.increment(EC)) {
305  llvm::ErrorOr<llvm::vfs::Status> Status = vfs->status(Iter->path());
306  if (Status->isDirectory())
307  continue;
308 
309  FileSpec dsym_fspec(Iter->path());
310  ModuleSpecList module_specs;
311  if (ObjectFile::GetModuleSpecifications(dsym_fspec, 0, 0, module_specs)) {
312  ModuleSpec spec;
313  for (size_t i = 0; i < module_specs.GetSize(); ++i) {
314  bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec);
315  assert(got_spec); // The call has side-effects so can't be inlined.
316  UNUSED_IF_ASSERT_DISABLED(got_spec);
317  if ((uuid == nullptr ||
318  (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
319  (arch == nullptr ||
320  (spec.GetArchitecturePtr() &&
321  spec.GetArchitecture().IsCompatibleMatch(*arch)))) {
322  return dsym_fspec;
323  }
324  }
325  }
326  }
327 
328  return {};
329 }
330 
331 static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict,
332  ModuleSpec &module_spec,
333  Status &error) {
334  Log *log = GetLog(LLDBLog::Host);
335  bool success = false;
336  if (uuid_dict != NULL && CFGetTypeID(uuid_dict) == CFDictionaryGetTypeID()) {
337  std::string str;
338  CFStringRef cf_str;
339  CFDictionaryRef cf_dict;
340 
341  cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
342  CFSTR("DBGError"));
343  if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
344  if (CFCString::FileSystemRepresentation(cf_str, str)) {
345  error.SetErrorString(str);
346  }
347  }
348 
349  cf_str = (CFStringRef)CFDictionaryGetValue(
350  (CFDictionaryRef)uuid_dict, CFSTR("DBGSymbolRichExecutable"));
351  if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
352  if (CFCString::FileSystemRepresentation(cf_str, str)) {
353  module_spec.GetFileSpec().SetFile(str.c_str(), FileSpec::Style::native);
354  FileSystem::Instance().Resolve(module_spec.GetFileSpec());
355  LLDB_LOGF(log,
356  "From dsymForUUID plist: Symbol rich executable is at '%s'",
357  str.c_str());
358  }
359  }
360 
361  cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
362  CFSTR("DBGDSYMPath"));
363  if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
364  if (CFCString::FileSystemRepresentation(cf_str, str)) {
365  module_spec.GetSymbolFileSpec().SetFile(str.c_str(),
366  FileSpec::Style::native);
367  FileSystem::Instance().Resolve(module_spec.GetFileSpec());
368  success = true;
369  LLDB_LOGF(log, "From dsymForUUID plist: dSYM is at '%s'", str.c_str());
370  }
371  }
372 
373  std::string DBGBuildSourcePath;
374  std::string DBGSourcePath;
375 
376  // If DBGVersion 1 or DBGVersion missing, ignore DBGSourcePathRemapping.
377  // If DBGVersion 2, strip last two components of path remappings from
378  // entries to fix an issue with a specific set of
379  // DBGSourcePathRemapping entries that lldb worked
380  // with.
381  // If DBGVersion 3, trust & use the source path remappings as-is.
382  //
383  cf_dict = (CFDictionaryRef)CFDictionaryGetValue(
384  (CFDictionaryRef)uuid_dict, CFSTR("DBGSourcePathRemapping"));
385  if (cf_dict && CFGetTypeID(cf_dict) == CFDictionaryGetTypeID()) {
386  // If we see DBGVersion with a value of 2 or higher, this is a new style
387  // DBGSourcePathRemapping dictionary
388  bool new_style_source_remapping_dictionary = false;
389  bool do_truncate_remapping_names = false;
390  std::string original_DBGSourcePath_value = DBGSourcePath;
391  cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
392  CFSTR("DBGVersion"));
393  if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
394  std::string version;
395  CFCString::FileSystemRepresentation(cf_str, version);
396  if (!version.empty() && isdigit(version[0])) {
397  int version_number = atoi(version.c_str());
398  if (version_number > 1) {
399  new_style_source_remapping_dictionary = true;
400  }
401  if (version_number == 2) {
402  do_truncate_remapping_names = true;
403  }
404  }
405  }
406 
407  CFIndex kv_pair_count = CFDictionaryGetCount((CFDictionaryRef)uuid_dict);
408  if (kv_pair_count > 0) {
409  CFStringRef *keys =
410  (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
411  CFStringRef *values =
412  (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
413  if (keys != nullptr && values != nullptr) {
414  CFDictionaryGetKeysAndValues((CFDictionaryRef)uuid_dict,
415  (const void **)keys,
416  (const void **)values);
417  }
418  for (CFIndex i = 0; i < kv_pair_count; i++) {
419  DBGBuildSourcePath.clear();
420  DBGSourcePath.clear();
421  if (keys[i] && CFGetTypeID(keys[i]) == CFStringGetTypeID()) {
422  CFCString::FileSystemRepresentation(keys[i], DBGBuildSourcePath);
423  }
424  if (values[i] && CFGetTypeID(values[i]) == CFStringGetTypeID()) {
425  CFCString::FileSystemRepresentation(values[i], DBGSourcePath);
426  }
427  if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
428  // In the "old style" DBGSourcePathRemapping dictionary, the
429  // DBGSourcePath values (the "values" half of key-value path pairs)
430  // were wrong. Ignore them and use the universal DBGSourcePath
431  // string from earlier.
432  if (new_style_source_remapping_dictionary &&
433  !original_DBGSourcePath_value.empty()) {
434  DBGSourcePath = original_DBGSourcePath_value;
435  }
436  if (DBGSourcePath[0] == '~') {
437  FileSpec resolved_source_path(DBGSourcePath.c_str());
438  FileSystem::Instance().Resolve(resolved_source_path);
439  DBGSourcePath = resolved_source_path.GetPath();
440  }
441  // With version 2 of DBGSourcePathRemapping, we can chop off the
442  // last two filename parts from the source remapping and get a more
443  // general source remapping that still works. Add this as another
444  // option in addition to the full source path remap.
445  module_spec.GetSourceMappingList().Append(DBGBuildSourcePath,
446  DBGSourcePath, true);
447  if (do_truncate_remapping_names) {
448  FileSpec build_path(DBGBuildSourcePath.c_str());
449  FileSpec source_path(DBGSourcePath.c_str());
450  build_path.RemoveLastPathComponent();
451  build_path.RemoveLastPathComponent();
452  source_path.RemoveLastPathComponent();
453  source_path.RemoveLastPathComponent();
454  module_spec.GetSourceMappingList().Append(
455  build_path.GetPath(), source_path.GetPath(), true);
456  }
457  }
458  }
459  if (keys)
460  free(keys);
461  if (values)
462  free(values);
463  }
464  }
465 
466  // If we have a DBGBuildSourcePath + DBGSourcePath pair, append them to the
467  // source remappings list.
468 
469  cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
470  CFSTR("DBGBuildSourcePath"));
471  if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
472  CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath);
473  }
474 
475  cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
476  CFSTR("DBGSourcePath"));
477  if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
478  CFCString::FileSystemRepresentation(cf_str, DBGSourcePath);
479  }
480 
481  if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
482  if (DBGSourcePath[0] == '~') {
483  FileSpec resolved_source_path(DBGSourcePath.c_str());
484  FileSystem::Instance().Resolve(resolved_source_path);
485  DBGSourcePath = resolved_source_path.GetPath();
486  }
487  module_spec.GetSourceMappingList().Append(DBGBuildSourcePath,
488  DBGSourcePath, true);
489  }
490  }
491  return success;
492 }
493 
494 bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
495  Status &error, bool force_lookup) {
496  bool success = false;
497  const UUID *uuid_ptr = module_spec.GetUUIDPtr();
498  const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr();
499 
500  // It's expensive to check for the DBGShellCommands defaults setting, only do
501  // it once per lldb run and cache the result.
502  static bool g_have_checked_for_dbgshell_command = false;
503  static const char *g_dbgshell_command = NULL;
504  if (!g_have_checked_for_dbgshell_command) {
505  g_have_checked_for_dbgshell_command = true;
506  CFTypeRef defaults_setting = CFPreferencesCopyAppValue(
507  CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols"));
508  if (defaults_setting &&
509  CFGetTypeID(defaults_setting) == CFStringGetTypeID()) {
510  char cstr_buf[PATH_MAX];
511  if (CFStringGetCString((CFStringRef)defaults_setting, cstr_buf,
512  sizeof(cstr_buf), kCFStringEncodingUTF8)) {
513  g_dbgshell_command =
514  strdup(cstr_buf); // this malloc'ed memory will never be freed
515  }
516  }
517  if (defaults_setting) {
518  CFRelease(defaults_setting);
519  }
520  }
521 
522  // When g_dbgshell_command is NULL, the user has not enabled the use of an
523  // external program to find the symbols, don't run it for them.
524  if (!force_lookup && g_dbgshell_command == NULL) {
525  return false;
526  }
527 
528  if (uuid_ptr ||
529  (file_spec_ptr && FileSystem::Instance().Exists(*file_spec_ptr))) {
530  static bool g_located_dsym_for_uuid_exe = false;
531  static bool g_dsym_for_uuid_exe_exists = false;
532  static char g_dsym_for_uuid_exe_path[PATH_MAX];
533  if (!g_located_dsym_for_uuid_exe) {
534  g_located_dsym_for_uuid_exe = true;
535  const char *dsym_for_uuid_exe_path_cstr =
536  getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE");
537  FileSpec dsym_for_uuid_exe_spec;
538  if (dsym_for_uuid_exe_path_cstr) {
539  dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr,
540  FileSpec::Style::native);
541  FileSystem::Instance().Resolve(dsym_for_uuid_exe_spec);
542  g_dsym_for_uuid_exe_exists =
543  FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
544  }
545 
546  if (!g_dsym_for_uuid_exe_exists) {
547  dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID",
548  FileSpec::Style::native);
549  g_dsym_for_uuid_exe_exists =
550  FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
551  if (!g_dsym_for_uuid_exe_exists) {
552  long bufsize;
553  if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) != -1) {
554  char buffer[bufsize];
555  struct passwd pwd;
556  struct passwd *tilde_rc = NULL;
557  // we are a library so we need to use the reentrant version of
558  // getpwnam()
559  if (getpwnam_r("rc", &pwd, buffer, bufsize, &tilde_rc) == 0 &&
560  tilde_rc && tilde_rc->pw_dir) {
561  std::string dsymforuuid_path(tilde_rc->pw_dir);
562  dsymforuuid_path += "/bin/dsymForUUID";
563  dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(),
564  FileSpec::Style::native);
565  g_dsym_for_uuid_exe_exists =
566  FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
567  }
568  }
569  }
570  }
571  if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL) {
572  dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command,
573  FileSpec::Style::native);
574  FileSystem::Instance().Resolve(dsym_for_uuid_exe_spec);
575  g_dsym_for_uuid_exe_exists =
576  FileSystem::Instance().Exists(dsym_for_uuid_exe_spec);
577  }
578 
579  if (g_dsym_for_uuid_exe_exists)
580  dsym_for_uuid_exe_spec.GetPath(g_dsym_for_uuid_exe_path,
581  sizeof(g_dsym_for_uuid_exe_path));
582  }
583  if (g_dsym_for_uuid_exe_exists) {
584  std::string uuid_str;
585  char file_path[PATH_MAX];
586  file_path[0] = '\0';
587 
588  if (uuid_ptr)
589  uuid_str = uuid_ptr->GetAsString();
590 
591  if (file_spec_ptr)
592  file_spec_ptr->GetPath(file_path, sizeof(file_path));
593 
594  StreamString command;
595  if (!uuid_str.empty())
596  command.Printf("%s --ignoreNegativeCache --copyExecutable %s",
597  g_dsym_for_uuid_exe_path, uuid_str.c_str());
598  else if (file_path[0] != '\0')
599  command.Printf("%s --ignoreNegativeCache --copyExecutable %s",
600  g_dsym_for_uuid_exe_path, file_path);
601 
602  if (!command.GetString().empty()) {
603  Log *log = GetLog(LLDBLog::Host);
604  int exit_status = -1;
605  int signo = -1;
606  std::string command_output;
607  if (log) {
608  if (!uuid_str.empty())
609  LLDB_LOGF(log, "Calling %s with UUID %s to find dSYM",
610  g_dsym_for_uuid_exe_path, uuid_str.c_str());
611  else if (file_path[0] != '\0')
612  LLDB_LOGF(log, "Calling %s with file %s to find dSYM",
613  g_dsym_for_uuid_exe_path, file_path);
614  }
615  error = Host::RunShellCommand(
616  command.GetData(),
617  FileSpec(), // current working directory
618  &exit_status, // Exit status
619  &signo, // Signal int *
620  &command_output, // Command output
621  std::chrono::seconds(
622  640), // Large timeout to allow for long dsym download times
623  false); // Don't run in a shell (we don't need shell expansion)
624  if (error.Success() && exit_status == 0 && !command_output.empty()) {
625  CFCData data(CFDataCreateWithBytesNoCopy(
626  NULL, (const UInt8 *)command_output.data(), command_output.size(),
627  kCFAllocatorNull));
628 
630  (CFDictionaryRef)::CFPropertyListCreateFromXMLData(
631  NULL, data.get(), kCFPropertyListImmutable, NULL));
632 
633  if (plist.get() &&
634  CFGetTypeID(plist.get()) == CFDictionaryGetTypeID()) {
635  if (!uuid_str.empty()) {
636  CFCString uuid_cfstr(uuid_str.c_str());
637  CFDictionaryRef uuid_dict = (CFDictionaryRef)CFDictionaryGetValue(
638  plist.get(), uuid_cfstr.get());
639  success = GetModuleSpecInfoFromUUIDDictionary(uuid_dict,
640  module_spec, error);
641  } else {
642  const CFIndex num_values = ::CFDictionaryGetCount(plist.get());
643  if (num_values > 0) {
644  std::vector<CFStringRef> keys(num_values, NULL);
645  std::vector<CFDictionaryRef> values(num_values, NULL);
646  ::CFDictionaryGetKeysAndValues(plist.get(), NULL,
647  (const void **)&values[0]);
648  if (num_values == 1) {
650  values[0], module_spec, error);
651  return success;
652  } else {
653  for (CFIndex i = 0; i < num_values; ++i) {
654  ModuleSpec curr_module_spec;
656  values[i], curr_module_spec, error)) {
657  if (module_spec.GetArchitecture().IsCompatibleMatch(
658  curr_module_spec.GetArchitecture())) {
659  module_spec = curr_module_spec;
660  return true;
661  }
662  }
663  }
664  }
665  }
666  }
667  }
668  } else {
669  if (!uuid_str.empty())
670  LLDB_LOGF(log, "Called %s on %s, no matches",
671  g_dsym_for_uuid_exe_path, uuid_str.c_str());
672  else if (file_path[0] != '\0')
673  LLDB_LOGF(log, "Called %s on %s, no matches",
674  g_dsym_for_uuid_exe_path, file_path);
675  }
676  }
677  }
678  }
679  return success;
680 }
LocateMacOSXFilesUsingDebugSymbols
int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, ModuleSpec &return_module_spec)
Definition: LocateSymbolFileMacOSX.cpp:49
lldb_private::UUID
Definition: UUID.h:23
lldb_private::ArchSpec
Definition: ArchSpec.h:33
UNUSED_IF_ASSERT_DISABLED
#define UNUSED_IF_ASSERT_DISABLED(x)
Definition: lldb-defines.h:125
lldb_private::ModuleSpec::GetUUIDPtr
UUID * GetUUIDPtr()
Definition: ModuleSpec.h:93
ModuleSpec.h
UUID.h
Host.h
lldb_private::UUID::IsValid
bool IsValid() const
Definition: UUID.h:79
lldb_private::ModuleSpecList
Definition: ModuleSpec.h:275
LLDB_LOGF
#define LLDB_LOGF(log,...)
Definition: Log.h:270
Module.h
lldb_private::Module
Definition: Module.h:85
LocateSymbolFile.h
CFCBundle.h
lldb_private::ModuleSpec::GetFileSpecPtr
FileSpec * GetFileSpecPtr()
Definition: ModuleSpec.h:47
lldb_private::UUID::GetAsString
std::string GetAsString(llvm::StringRef separator="-") const
Definition: UUID.cpp:48
CFCString
Definition: CFCString.h:16
lldb_private::StreamString::GetString
llvm::StringRef GetString() const
Definition: StreamString.cpp:51
lldb_private::ModuleSpec::GetSymbolFileSpec
FileSpec & GetSymbolFileSpec()
Definition: ModuleSpec.h:77
CFCReleaser
lldb_private::ArchSpec::IsCompatibleMatch
bool IsCompatibleMatch(const ArchSpec &rhs) const
Compare an ArchSpec to another ArchSpec, requiring a compatible cpu type match between them.
Definition: ArchSpec.cpp:935
lldb_private::ModuleSpec::GetUUID
UUID & GetUUID()
Definition: ModuleSpec.h:99
lldb_private::ModuleSpec::GetSourceMappingList
PathMappingList & GetSourceMappingList() const
Definition: ModuleSpec.h:125
lldb_private::FileSpec
Definition: FileSpec.h:56
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
ModuleList.h
CFCReleaser.h
Log.h
lldb_private::StreamString::GetData
const char * GetData() const
Definition: StreamString.h:43
StreamString.h
lldb_private::StreamString
Definition: StreamString.h:23
Timer.h
CFCData.h
CFCBundle::CopyExecutableURL
CFURLRef CopyExecutableURL() const
Definition: CFCBundle.cpp:71
HostInfo.h
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:40
lldb_private::ModuleSpecList::FindMatchingModuleSpec
bool FindMatchingModuleSpec(const ModuleSpec &module_spec, ModuleSpec &match_module_spec) const
Definition: ModuleSpec.h:333
lldb_private::PathMappingList::Append
void Append(llvm::StringRef path, llvm::StringRef replacement, bool notify)
Definition: PathMappingList.cpp:60
g_dlsym_DBGCopyFullDSYMURLForUUID
static CFURLRef(* g_dlsym_DBGCopyFullDSYMURLForUUID)(CFUUIDRef uuid, CFURLRef exec_url)
Definition: LocateSymbolFileMacOSX.cpp:44
CFCBundle
Definition: CFCBundle.h:14
CFCData
Definition: CFCData.h:14
ObjectFile.h
lldb_private::FileSpec::Clear
void Clear()
Clears the object state.
Definition: FileSpec.cpp:259
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
lldb_private::FileSpec::RemoveLastPathComponent
bool RemoveLastPathComponent()
Removes the last path component by replacing the current path with its parent.
Definition: FileSpec.cpp:445
lldb_private::ModuleSpec::GetArchitecturePtr
ArchSpec * GetArchitecturePtr()
Definition: ModuleSpec.h:81
lldb_private::SharedCacheImageInfo::uuid
UUID uuid
Definition: HostInfoBase.h:29
ArchSpec.h
GetModuleSpecInfoFromUUIDDictionary
static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict, ModuleSpec &module_spec, Status &error)
Definition: LocateSymbolFileMacOSX.cpp:331
lldb_private::ModuleSpec::GetArchitecture
ArchSpec & GetArchitecture()
Definition: ModuleSpec.h:89
DataExtractor.h
lldb_private::Stream::Printf
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
CFCString.h
lldb_private::ModuleSpecList::GetModuleSpecAtIndex
bool GetModuleSpecAtIndex(size_t i, ModuleSpec &module_spec) const
Definition: ModuleSpec.h:323
lldb_private::ModuleSpecList::GetSize
size_t GetSize() const
Definition: ModuleSpec.h:298
lldb_private::Log
Definition: Log.h:48
lldb_private::FileSpec::SetFile
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
Definition: FileSpec.cpp:172
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:235
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
DataBuffer.h
lldb
Definition: SBAddress.h:15
Endian.h
lldb_private::UUID::GetBytes
llvm::ArrayRef< uint8_t > GetBytes() const
Definition: UUID.h:76
LLDBLog.h
g_dlsym_DBGCopyDSYMPropertyLists
static CFDictionaryRef(* g_dlsym_DBGCopyDSYMPropertyLists)(CFURLRef dsym_url)
Definition: LocateSymbolFileMacOSX.cpp:46
CFCString::FileSystemRepresentation
static const char * FileSystemRepresentation(CFStringRef cf_str, std::string &str)
Definition: CFCString.cpp:126