1 //===-- Symbols.cpp ---------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Host/Symbols.h" 11 12 // C Includes 13 #include <dirent.h> 14 #include <pwd.h> 15 #include "llvm/Support/MachO.h" 16 17 // C++ Includes 18 // Other libraries and framework includes 19 #include <CoreFoundation/CoreFoundation.h> 20 21 // Project includes 22 #include "lldb/Core/ArchSpec.h" 23 #include "lldb/Core/DataBuffer.h" 24 #include "lldb/Core/DataExtractor.h" 25 #include "lldb/Core/Module.h" 26 #include "lldb/Core/ModuleSpec.h" 27 #include "lldb/Core/StreamString.h" 28 #include "lldb/Core/Timer.h" 29 #include "lldb/Core/UUID.h" 30 #include "lldb/Host/Endian.h" 31 #include "lldb/Host/Host.h" 32 #include "lldb/Utility/CleanUp.h" 33 #include "Host/macosx/cfcpp/CFCBundle.h" 34 #include "Host/macosx/cfcpp/CFCData.h" 35 #include "Host/macosx/cfcpp/CFCReleaser.h" 36 #include "Host/macosx/cfcpp/CFCString.h" 37 #include "mach/machine.h" 38 39 40 using namespace lldb; 41 using namespace lldb_private; 42 using namespace llvm::MachO; 43 44 #if !defined (__arm__) // No DebugSymbols on the iOS devices 45 extern "C" { 46 47 CFURLRef DBGCopyFullDSYMURLForUUID (CFUUIDRef uuid, CFURLRef exec_url); 48 CFDictionaryRef DBGCopyDSYMPropertyLists (CFURLRef dsym_url); 49 50 } 51 #endif 52 53 static bool 54 SkinnyMachOFileContainsArchAndUUID 55 ( 56 const FileSpec &file_spec, 57 const ArchSpec *arch, 58 const lldb_private::UUID *uuid, // the UUID we are looking for 59 off_t file_offset, 60 DataExtractor& data, 61 lldb::offset_t data_offset, 62 const uint32_t magic 63 ) 64 { 65 assert(magic == HeaderMagic32 || magic == HeaderMagic32Swapped || magic == HeaderMagic64 || magic == HeaderMagic64Swapped); 66 if (magic == HeaderMagic32 || magic == HeaderMagic64) 67 data.SetByteOrder (lldb::endian::InlHostByteOrder()); 68 else if (lldb::endian::InlHostByteOrder() == eByteOrderBig) 69 data.SetByteOrder (eByteOrderLittle); 70 else 71 data.SetByteOrder (eByteOrderBig); 72 73 uint32_t i; 74 const uint32_t cputype = data.GetU32(&data_offset); // cpu specifier 75 const uint32_t cpusubtype = data.GetU32(&data_offset); // machine specifier 76 data_offset+=4; // Skip mach file type 77 const uint32_t ncmds = data.GetU32(&data_offset); // number of load commands 78 const uint32_t sizeofcmds = data.GetU32(&data_offset); // the size of all the load commands 79 data_offset+=4; // Skip flags 80 81 // Check the architecture if we have a valid arch pointer 82 if (arch) 83 { 84 ArchSpec file_arch(eArchTypeMachO, cputype, cpusubtype); 85 86 if (!file_arch.IsCompatibleMatch(*arch)) 87 return false; 88 } 89 90 // The file exists, and if a valid arch pointer was passed in we know 91 // if already matches, so we can return if we aren't looking for a specific 92 // UUID 93 if (uuid == NULL) 94 return true; 95 96 if (magic == HeaderMagic64Swapped || magic == HeaderMagic64) 97 data_offset += 4; // Skip reserved field for in mach_header_64 98 99 // Make sure we have enough data for all the load commands 100 if (magic == HeaderMagic64Swapped || magic == HeaderMagic64) 101 { 102 if (data.GetByteSize() < sizeof(struct mach_header_64) + sizeofcmds) 103 { 104 DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, sizeof(struct mach_header_64) + sizeofcmds)); 105 data.SetData (data_buffer_sp); 106 } 107 } 108 else 109 { 110 if (data.GetByteSize() < sizeof(struct mach_header) + sizeofcmds) 111 { 112 DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, sizeof(struct mach_header) + sizeofcmds)); 113 data.SetData (data_buffer_sp); 114 } 115 } 116 117 for (i=0; i<ncmds; i++) 118 { 119 const lldb::offset_t cmd_offset = data_offset; // Save this data_offset in case parsing of the segment goes awry! 120 uint32_t cmd = data.GetU32(&data_offset); 121 uint32_t cmd_size = data.GetU32(&data_offset); 122 if (cmd == LoadCommandUUID) 123 { 124 lldb_private::UUID file_uuid (data.GetData(&data_offset, 16), 16); 125 if (file_uuid == *uuid) 126 return true; 127 return false; 128 } 129 data_offset = cmd_offset + cmd_size; 130 } 131 return false; 132 } 133 134 bool 135 UniversalMachOFileContainsArchAndUUID 136 ( 137 const FileSpec &file_spec, 138 const ArchSpec *arch, 139 const lldb_private::UUID *uuid, 140 off_t file_offset, 141 DataExtractor& data, 142 lldb::offset_t data_offset, 143 const uint32_t magic 144 ) 145 { 146 assert(magic == UniversalMagic || magic == UniversalMagicSwapped); 147 148 // Universal mach-o files always have their headers encoded as BIG endian 149 data.SetByteOrder(eByteOrderBig); 150 151 uint32_t i; 152 const uint32_t nfat_arch = data.GetU32(&data_offset); // number of structs that follow 153 const uint32_t fat_header_and_arch_size = sizeof(struct fat_header) + nfat_arch * sizeof(struct fat_arch); 154 if (data.GetByteSize() < fat_header_and_arch_size) 155 { 156 DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, fat_header_and_arch_size)); 157 data.SetData (data_buffer_sp); 158 } 159 160 for (i=0; i<nfat_arch; i++) 161 { 162 cpu_type_t arch_cputype = data.GetU32(&data_offset); // cpu specifier (int) 163 cpu_subtype_t arch_cpusubtype = data.GetU32(&data_offset); // machine specifier (int) 164 uint32_t arch_offset = data.GetU32(&data_offset); // file offset to this object file 165 // uint32_t arch_size = data.GetU32(&data_offset); // size of this object file 166 // uint32_t arch_align = data.GetU32(&data_offset); // alignment as a power of 2 167 data_offset += 8; // Skip size and align as we don't need those 168 // Only process this slice if the cpu type/subtype matches 169 if (arch) 170 { 171 ArchSpec fat_arch(eArchTypeMachO, arch_cputype, arch_cpusubtype); 172 if (!fat_arch.IsExactMatch(*arch)) 173 continue; 174 } 175 176 // Create a buffer with only the arch slice date in it 177 DataExtractor arch_data; 178 DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset + arch_offset, 0x1000)); 179 arch_data.SetData(data_buffer_sp); 180 lldb::offset_t arch_data_offset = 0; 181 uint32_t arch_magic = arch_data.GetU32(&arch_data_offset); 182 183 switch (arch_magic) 184 { 185 case HeaderMagic32: 186 case HeaderMagic32Swapped: 187 case HeaderMagic64: 188 case HeaderMagic64Swapped: 189 if (SkinnyMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset + arch_offset, arch_data, arch_data_offset, arch_magic)) 190 return true; 191 break; 192 } 193 } 194 return false; 195 } 196 197 static bool 198 FileAtPathContainsArchAndUUID 199 ( 200 const FileSpec &file_spec, 201 const ArchSpec *arch, 202 const lldb_private::UUID *uuid 203 ) 204 { 205 DataExtractor data; 206 off_t file_offset = 0; 207 DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, 0x1000)); 208 209 if (data_buffer_sp && data_buffer_sp->GetByteSize() > 0) 210 { 211 data.SetData(data_buffer_sp); 212 213 lldb::offset_t data_offset = 0; 214 uint32_t magic = data.GetU32(&data_offset); 215 216 switch (magic) 217 { 218 // 32 bit mach-o file 219 case HeaderMagic32: 220 case HeaderMagic32Swapped: 221 case HeaderMagic64: 222 case HeaderMagic64Swapped: 223 return SkinnyMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset, data, data_offset, magic); 224 225 // fat mach-o file 226 case UniversalMagic: 227 case UniversalMagicSwapped: 228 return UniversalMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset, data, data_offset, magic); 229 230 default: 231 break; 232 } 233 } 234 return false; 235 } 236 237 FileSpec 238 Symbols::FindSymbolFileInBundle (const FileSpec& dsym_bundle_fspec, 239 const lldb_private::UUID *uuid, 240 const ArchSpec *arch) 241 { 242 char path[PATH_MAX]; 243 244 FileSpec dsym_fspec; 245 246 if (dsym_bundle_fspec.GetPath(path, sizeof(path))) 247 { 248 ::strncat (path, "/Contents/Resources/DWARF", sizeof(path) - strlen(path) - 1); 249 250 lldb_utility::CleanUp <DIR *, int> dirp (opendir(path), NULL, closedir); 251 if (dirp.is_valid()) 252 { 253 dsym_fspec.GetDirectory().SetCString(path); 254 struct dirent* dp; 255 while ((dp = readdir(dirp.get())) != NULL) 256 { 257 // Only search directories 258 if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) 259 { 260 if (dp->d_namlen == 1 && dp->d_name[0] == '.') 261 continue; 262 263 if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.') 264 continue; 265 } 266 267 if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN) 268 { 269 dsym_fspec.GetFilename().SetCString(dp->d_name); 270 if (FileAtPathContainsArchAndUUID (dsym_fspec, arch, uuid)) 271 return dsym_fspec; 272 } 273 } 274 } 275 } 276 dsym_fspec.Clear(); 277 return dsym_fspec; 278 } 279 280 static int 281 LocateMacOSXFilesUsingDebugSymbols 282 ( 283 const ModuleSpec &module_spec, 284 FileSpec *out_exec_fspec, // If non-NULL, try and find the executable 285 FileSpec *out_dsym_fspec // If non-NULL try and find the debug symbol file 286 ) 287 { 288 int items_found = 0; 289 290 if (out_exec_fspec) 291 out_exec_fspec->Clear(); 292 293 if (out_dsym_fspec) 294 out_dsym_fspec->Clear(); 295 296 #if !defined (__arm__) // No DebugSymbols on the iOS devices 297 298 const UUID *uuid = module_spec.GetUUIDPtr(); 299 const ArchSpec *arch = module_spec.GetArchitecturePtr(); 300 301 if (uuid && uuid->IsValid()) 302 { 303 // Try and locate the dSYM file using DebugSymbols first 304 const UInt8 *module_uuid = (const UInt8 *)uuid->GetBytes(); 305 if (module_uuid != NULL) 306 { 307 CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes (NULL, 308 module_uuid[0], 309 module_uuid[1], 310 module_uuid[2], 311 module_uuid[3], 312 module_uuid[4], 313 module_uuid[5], 314 module_uuid[6], 315 module_uuid[7], 316 module_uuid[8], 317 module_uuid[9], 318 module_uuid[10], 319 module_uuid[11], 320 module_uuid[12], 321 module_uuid[13], 322 module_uuid[14], 323 module_uuid[15])); 324 325 if (module_uuid_ref.get()) 326 { 327 CFCReleaser<CFURLRef> exec_url; 328 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); 329 if (exec_fspec) 330 { 331 char exec_cf_path[PATH_MAX]; 332 if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path))) 333 exec_url.reset(::CFURLCreateFromFileSystemRepresentation (NULL, 334 (const UInt8 *)exec_cf_path, 335 strlen(exec_cf_path), 336 FALSE)); 337 } 338 339 CFCReleaser<CFURLRef> dsym_url (::DBGCopyFullDSYMURLForUUID(module_uuid_ref.get(), exec_url.get())); 340 char path[PATH_MAX]; 341 342 if (dsym_url.get()) 343 { 344 if (out_dsym_fspec) 345 { 346 if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1)) 347 { 348 out_dsym_fspec->SetFile(path, path[0] == '~'); 349 350 if (out_dsym_fspec->GetFileType () == FileSpec::eFileTypeDirectory) 351 { 352 *out_dsym_fspec = Symbols::FindSymbolFileInBundle (*out_dsym_fspec, uuid, arch); 353 if (*out_dsym_fspec) 354 ++items_found; 355 } 356 else 357 { 358 ++items_found; 359 } 360 } 361 } 362 363 CFCReleaser<CFDictionaryRef> dict(::DBGCopyDSYMPropertyLists (dsym_url.get())); 364 CFDictionaryRef uuid_dict = NULL; 365 if (dict.get()) 366 { 367 CFCString uuid_cfstr (uuid->GetAsString().c_str()); 368 uuid_dict = static_cast<CFDictionaryRef>(::CFDictionaryGetValue (dict.get(), uuid_cfstr.get())); 369 if (uuid_dict) 370 { 371 372 CFStringRef actual_src_cfpath = static_cast<CFStringRef>(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGSourcePath"))); 373 if (actual_src_cfpath) 374 { 375 CFStringRef build_src_cfpath = static_cast<CFStringRef>(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGBuildSourcePath"))); 376 if (build_src_cfpath) 377 { 378 char actual_src_path[PATH_MAX]; 379 char build_src_path[PATH_MAX]; 380 ::CFStringGetFileSystemRepresentation (actual_src_cfpath, actual_src_path, sizeof(actual_src_path)); 381 ::CFStringGetFileSystemRepresentation (build_src_cfpath, build_src_path, sizeof(build_src_path)); 382 if (actual_src_path[0] == '~') 383 { 384 FileSpec resolved_source_path(actual_src_path, true); 385 resolved_source_path.GetPath(actual_src_path, sizeof(actual_src_path)); 386 } 387 module_spec.GetSourceMappingList().Append (ConstString(build_src_path), ConstString(actual_src_path), true); 388 } 389 } 390 } 391 } 392 393 if (out_exec_fspec) 394 { 395 bool success = false; 396 if (uuid_dict) 397 { 398 CFStringRef exec_cf_path = static_cast<CFStringRef>(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGSymbolRichExecutable"))); 399 if (exec_cf_path && ::CFStringGetFileSystemRepresentation (exec_cf_path, path, sizeof(path))) 400 { 401 ++items_found; 402 out_exec_fspec->SetFile(path, path[0] == '~'); 403 if (out_exec_fspec->Exists()) 404 success = true; 405 } 406 } 407 408 if (!success) 409 { 410 // No dictionary, check near the dSYM bundle for an executable that matches... 411 if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1)) 412 { 413 char *dsym_extension_pos = ::strstr (path, ".dSYM"); 414 if (dsym_extension_pos) 415 { 416 *dsym_extension_pos = '\0'; 417 FileSpec file_spec (path, true); 418 switch (file_spec.GetFileType()) 419 { 420 case FileSpec::eFileTypeDirectory: // Bundle directory? 421 { 422 CFCBundle bundle (path); 423 CFCReleaser<CFURLRef> bundle_exe_url (bundle.CopyExecutableURL ()); 424 if (bundle_exe_url.get()) 425 { 426 if (::CFURLGetFileSystemRepresentation (bundle_exe_url.get(), true, (UInt8*)path, sizeof(path)-1)) 427 { 428 FileSpec bundle_exe_file_spec (path, true); 429 430 if (FileAtPathContainsArchAndUUID (bundle_exe_file_spec, arch, uuid)) 431 { 432 ++items_found; 433 *out_exec_fspec = bundle_exe_file_spec; 434 } 435 } 436 } 437 } 438 break; 439 440 case FileSpec::eFileTypePipe: // Forget pipes 441 case FileSpec::eFileTypeSocket: // We can't process socket files 442 case FileSpec::eFileTypeInvalid: // File doesn't exist... 443 break; 444 445 case FileSpec::eFileTypeUnknown: 446 case FileSpec::eFileTypeRegular: 447 case FileSpec::eFileTypeSymbolicLink: 448 case FileSpec::eFileTypeOther: 449 if (FileAtPathContainsArchAndUUID (file_spec, arch, uuid)) 450 { 451 ++items_found; 452 *out_exec_fspec = file_spec; 453 } 454 break; 455 } 456 } 457 } 458 } 459 } 460 } 461 } 462 } 463 } 464 #endif // #if !defined (__arm__) 465 466 return items_found; 467 } 468 469 static bool 470 LocateDSYMInVincinityOfExecutable (const ModuleSpec &module_spec, FileSpec &dsym_fspec) 471 { 472 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); 473 if (exec_fspec) 474 { 475 char path[PATH_MAX]; 476 if (exec_fspec->GetPath(path, sizeof(path))) 477 { 478 // Make sure the module isn't already just a dSYM file... 479 if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL) 480 { 481 size_t obj_file_path_length = strlen(path); 482 strlcat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path)); 483 strlcat(path, exec_fspec->GetFilename().AsCString(), sizeof(path)); 484 485 dsym_fspec.SetFile(path, false); 486 487 if (dsym_fspec.Exists() && FileAtPathContainsArchAndUUID (dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr())) 488 { 489 return true; 490 } 491 else 492 { 493 path[obj_file_path_length] = '\0'; 494 495 char *last_dot = strrchr(path, '.'); 496 while (last_dot != NULL && last_dot[0]) 497 { 498 char *next_slash = strchr(last_dot, '/'); 499 if (next_slash != NULL) 500 { 501 *next_slash = '\0'; 502 strlcat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path)); 503 strlcat(path, exec_fspec->GetFilename().AsCString(), sizeof(path)); 504 dsym_fspec.SetFile(path, false); 505 if (dsym_fspec.Exists() && FileAtPathContainsArchAndUUID (dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr())) 506 return true; 507 else 508 { 509 *last_dot = '\0'; 510 char *prev_slash = strrchr(path, '/'); 511 if (prev_slash != NULL) 512 *prev_slash = '\0'; 513 else 514 break; 515 } 516 } 517 else 518 { 519 break; 520 } 521 } 522 } 523 } 524 } 525 } 526 dsym_fspec.Clear(); 527 return false; 528 } 529 530 FileSpec 531 Symbols::LocateExecutableObjectFile (const ModuleSpec &module_spec) 532 { 533 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); 534 const ArchSpec *arch = module_spec.GetArchitecturePtr(); 535 const UUID *uuid = module_spec.GetUUIDPtr(); 536 Timer scoped_timer (__PRETTY_FUNCTION__, 537 "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)", 538 exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>", 539 arch ? arch->GetArchitectureName() : "<NULL>", 540 uuid); 541 542 FileSpec objfile_fspec; 543 if (exec_fspec && FileAtPathContainsArchAndUUID (exec_fspec, arch, uuid)) 544 objfile_fspec = exec_fspec; 545 else 546 LocateMacOSXFilesUsingDebugSymbols (module_spec, &objfile_fspec, NULL); 547 return objfile_fspec; 548 } 549 550 FileSpec 551 Symbols::LocateExecutableSymbolFile (const ModuleSpec &module_spec) 552 { 553 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); 554 const ArchSpec *arch = module_spec.GetArchitecturePtr(); 555 const UUID *uuid = module_spec.GetUUIDPtr(); 556 557 Timer scoped_timer (__PRETTY_FUNCTION__, 558 "LocateExecutableSymbolFile (file = %s, arch = %s, uuid = %p)", 559 exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>", 560 arch ? arch->GetArchitectureName() : "<NULL>", 561 uuid); 562 563 FileSpec symbol_fspec; 564 // First try and find the dSYM in the same directory as the executable or in 565 // an appropriate parent directory 566 if (LocateDSYMInVincinityOfExecutable (module_spec, symbol_fspec) == false) 567 { 568 // We failed to easily find the dSYM above, so use DebugSymbols 569 LocateMacOSXFilesUsingDebugSymbols (module_spec, NULL, &symbol_fspec); 570 } 571 return symbol_fspec; 572 } 573 574 575 static bool 576 GetModuleSpecInfoFromUUIDDictionary (CFDictionaryRef uuid_dict, ModuleSpec &module_spec) 577 { 578 bool success = false; 579 if (uuid_dict != NULL && CFGetTypeID (uuid_dict) == CFDictionaryGetTypeID ()) 580 { 581 std::string str; 582 CFStringRef cf_str; 583 584 cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGSymbolRichExecutable")); 585 if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ()) 586 { 587 if (CFCString::FileSystemRepresentation(cf_str, str)) 588 module_spec.GetFileSpec().SetFile (str.c_str(), true); 589 } 590 591 cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGDSYMPath")); 592 if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ()) 593 { 594 if (CFCString::FileSystemRepresentation(cf_str, str)) 595 { 596 module_spec.GetSymbolFileSpec().SetFile (str.c_str(), true); 597 success = true; 598 } 599 } 600 601 cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGArchitecture")); 602 if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ()) 603 { 604 if (CFCString::FileSystemRepresentation(cf_str, str)) 605 module_spec.GetArchitecture().SetTriple(str.c_str()); 606 } 607 608 std::string DBGBuildSourcePath; 609 std::string DBGSourcePath; 610 611 cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGBuildSourcePath")); 612 if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ()) 613 { 614 CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath); 615 } 616 617 cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGSourcePath")); 618 if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ()) 619 { 620 CFCString::FileSystemRepresentation(cf_str, DBGSourcePath); 621 } 622 623 if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) 624 { 625 module_spec.GetSourceMappingList().Append (ConstString(DBGBuildSourcePath.c_str()), ConstString(DBGSourcePath.c_str()), true); 626 } 627 } 628 return success; 629 } 630 631 632 bool 633 Symbols::DownloadObjectAndSymbolFile (ModuleSpec &module_spec, bool force_lookup) 634 { 635 bool success = false; 636 const UUID *uuid_ptr = module_spec.GetUUIDPtr(); 637 const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr(); 638 639 // It's expensive to check for the DBGShellCommands defaults setting, only do it once per 640 // lldb run and cache the result. 641 static bool g_have_checked_for_dbgshell_command = false; 642 static const char *g_dbgshell_command = NULL; 643 if (g_have_checked_for_dbgshell_command == false) 644 { 645 g_have_checked_for_dbgshell_command = true; 646 CFTypeRef defaults_setting = CFPreferencesCopyAppValue (CFSTR ("DBGShellCommands"), CFSTR ("com.apple.DebugSymbols")); 647 if (defaults_setting && CFGetTypeID (defaults_setting) == CFStringGetTypeID()) 648 { 649 char cstr_buf[PATH_MAX]; 650 if (CFStringGetCString ((CFStringRef) defaults_setting, cstr_buf, sizeof (cstr_buf), kCFStringEncodingUTF8)) 651 { 652 g_dbgshell_command = strdup (cstr_buf); // this malloc'ed memory will never be freed 653 } 654 } 655 if (defaults_setting) 656 { 657 CFRelease (defaults_setting); 658 } 659 } 660 661 // When g_dbgshell_command is NULL, the user has not enabled the use of an external program 662 // to find the symbols, don't run it for them. 663 if (force_lookup == false && g_dbgshell_command == NULL) 664 { 665 return false; 666 } 667 668 if (uuid_ptr || (file_spec_ptr && file_spec_ptr->Exists())) 669 { 670 static bool g_located_dsym_for_uuid_exe = false; 671 static bool g_dsym_for_uuid_exe_exists = false; 672 static char g_dsym_for_uuid_exe_path[PATH_MAX]; 673 if (!g_located_dsym_for_uuid_exe) 674 { 675 g_located_dsym_for_uuid_exe = true; 676 const char *dsym_for_uuid_exe_path_cstr = getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE"); 677 FileSpec dsym_for_uuid_exe_spec; 678 if (dsym_for_uuid_exe_path_cstr) 679 { 680 dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr, true); 681 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists(); 682 } 683 684 if (!g_dsym_for_uuid_exe_exists) 685 { 686 dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID", false); 687 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists(); 688 if (!g_dsym_for_uuid_exe_exists) 689 { 690 long bufsize; 691 if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) != -1) 692 { 693 char buffer[bufsize]; 694 struct passwd pwd; 695 struct passwd *tilde_rc = NULL; 696 // we are a library so we need to use the reentrant version of getpwnam() 697 if (getpwnam_r ("rc", &pwd, buffer, bufsize, &tilde_rc) == 0 698 && tilde_rc 699 && tilde_rc->pw_dir) 700 { 701 std::string dsymforuuid_path(tilde_rc->pw_dir); 702 dsymforuuid_path += "/bin/dsymForUUID"; 703 dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(), false); 704 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists(); 705 } 706 } 707 } 708 } 709 if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL) 710 { 711 dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command, true); 712 g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists(); 713 } 714 715 if (g_dsym_for_uuid_exe_exists) 716 dsym_for_uuid_exe_spec.GetPath (g_dsym_for_uuid_exe_path, sizeof(g_dsym_for_uuid_exe_path)); 717 } 718 if (g_dsym_for_uuid_exe_exists) 719 { 720 std::string uuid_str; 721 char file_path[PATH_MAX]; 722 file_path[0] = '\0'; 723 724 if (uuid_ptr) 725 uuid_str = uuid_ptr->GetAsString(); 726 727 if (file_spec_ptr) 728 file_spec_ptr->GetPath(file_path, sizeof(file_path)); 729 730 StreamString command; 731 if (!uuid_str.empty()) 732 command.Printf("%s --ignoreNegativeCache --copyExecutable %s", g_dsym_for_uuid_exe_path, uuid_str.c_str()); 733 else if (file_path && file_path[0]) 734 command.Printf("%s --ignoreNegativeCache --copyExecutable %s", g_dsym_for_uuid_exe_path, file_path); 735 736 if (!command.GetString().empty()) 737 { 738 int exit_status = -1; 739 int signo = -1; 740 std::string command_output; 741 Error error = Host::RunShellCommand (command.GetData(), 742 NULL, // current working directory 743 &exit_status, // Exit status 744 &signo, // Signal int * 745 &command_output, // Command output 746 30, // Large timeout to allow for long dsym download times 747 NULL); // Don't run in a shell (we don't need shell expansion) 748 if (error.Success() && exit_status == 0 && !command_output.empty()) 749 { 750 CFCData data (CFDataCreateWithBytesNoCopy (NULL, 751 (const UInt8 *)command_output.data(), 752 command_output.size(), 753 kCFAllocatorNull)); 754 755 CFCReleaser<CFDictionaryRef> plist((CFDictionaryRef)::CFPropertyListCreateFromXMLData (NULL, data.get(), kCFPropertyListImmutable, NULL)); 756 757 if (plist.get() && CFGetTypeID (plist.get()) == CFDictionaryGetTypeID ()) 758 { 759 if (!uuid_str.empty()) 760 { 761 CFCString uuid_cfstr(uuid_str.c_str()); 762 CFDictionaryRef uuid_dict = (CFDictionaryRef)CFDictionaryGetValue (plist.get(), uuid_cfstr.get()); 763 success = GetModuleSpecInfoFromUUIDDictionary (uuid_dict, module_spec); 764 } 765 else 766 { 767 const CFIndex num_values = ::CFDictionaryGetCount(plist.get()); 768 if (num_values > 0) 769 { 770 std::vector<CFStringRef> keys (num_values, NULL); 771 std::vector<CFDictionaryRef> values (num_values, NULL); 772 ::CFDictionaryGetKeysAndValues(plist.get(), NULL, (const void **)&values[0]); 773 if (num_values == 1) 774 { 775 return GetModuleSpecInfoFromUUIDDictionary (values[0], module_spec); 776 } 777 else 778 { 779 for (CFIndex i=0; i<num_values; ++i) 780 { 781 ModuleSpec curr_module_spec; 782 if (GetModuleSpecInfoFromUUIDDictionary (values[i], curr_module_spec)) 783 { 784 if (module_spec.GetArchitecture().IsCompatibleMatch(curr_module_spec.GetArchitecture())) 785 { 786 module_spec = curr_module_spec; 787 return true; 788 } 789 } 790 } 791 } 792 } 793 } 794 } 795 } 796 } 797 } 798 } 799 return success; 800 } 801 802