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