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