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