1 /* 2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2012-2014, Rene Gollent, rene@gollent.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include "DwarfFile.h" 9 10 #include <algorithm> 11 #include <new> 12 13 #include <AutoDeleter.h> 14 #include <Entry.h> 15 #include <FindDirectory.h> 16 #include <Path.h> 17 #include <PathFinder.h> 18 19 #include "AttributeClasses.h" 20 #include "AttributeValue.h" 21 #include "AbbreviationTable.h" 22 #include "CfaContext.h" 23 #include "CompilationUnit.h" 24 #include "DataReader.h" 25 #include "DwarfExpressionEvaluator.h" 26 #include "DwarfTargetInterface.h" 27 #include "ElfFile.h" 28 #include "TagNames.h" 29 #include "TargetAddressRangeList.h" 30 #include "Tracing.h" 31 #include "Variant.h" 32 33 34 // #pragma mark - AutoSectionPutter 35 36 37 class AutoSectionPutter { 38 public: 39 AutoSectionPutter(ElfFile* elfFile, ElfSection* elfSection) 40 : 41 fElfFile(elfFile), 42 fElfSection(elfSection) 43 { 44 } 45 46 ~AutoSectionPutter() 47 { 48 if (fElfSection != NULL) 49 fElfFile->PutSection(fElfSection); 50 } 51 52 private: 53 ElfFile* fElfFile; 54 ElfSection* fElfSection; 55 }; 56 57 58 // #pragma mark - ExpressionEvaluationContext 59 60 61 struct DwarfFile::ExpressionEvaluationContext 62 : DwarfExpressionEvaluationContext { 63 public: 64 ExpressionEvaluationContext(DwarfFile* file, CompilationUnit* unit, 65 uint8 addressSize, bool isBigEndian, DIESubprogram* subprogramEntry, 66 const DwarfTargetInterface* targetInterface, 67 target_addr_t instructionPointer, target_addr_t objectPointer, 68 bool hasObjectPointer, target_addr_t framePointer, 69 target_addr_t relocationDelta) 70 : 71 DwarfExpressionEvaluationContext(targetInterface, addressSize, isBigEndian, 72 relocationDelta), 73 fFile(file), 74 fUnit(unit), 75 fSubprogramEntry(subprogramEntry), 76 fInstructionPointer(instructionPointer), 77 fObjectPointer(objectPointer), 78 fHasObjectPointer(hasObjectPointer), 79 fFramePointer(framePointer), 80 fFrameBasePointer(0), 81 fFrameBaseEvaluated(false) 82 { 83 } 84 85 virtual bool GetObjectAddress(target_addr_t& _address) 86 { 87 if (!fHasObjectPointer) 88 return false; 89 90 _address = fObjectPointer; 91 return true; 92 } 93 94 virtual bool GetFrameAddress(target_addr_t& _address) 95 { 96 if (fFramePointer == 0) 97 return false; 98 99 _address = fFramePointer; 100 return true; 101 } 102 103 virtual bool GetFrameBaseAddress(target_addr_t& _address) 104 { 105 if (fFrameBaseEvaluated) { 106 if (fFrameBasePointer == 0) 107 return false; 108 109 _address = fFrameBasePointer; 110 return true; 111 } 112 113 // set flag already to prevent recursion for a buggy expression 114 fFrameBaseEvaluated = true; 115 116 // get the subprogram's frame base location 117 if (fSubprogramEntry == NULL) 118 return false; 119 const LocationDescription* location = fSubprogramEntry->FrameBase(); 120 if (!location->IsValid()) 121 return false; 122 123 // get the expression 124 const void* expression; 125 off_t expressionLength; 126 status_t error = fFile->_GetLocationExpression(fUnit, location, 127 fInstructionPointer, expression, expressionLength); 128 if (error != B_OK) 129 return false; 130 131 // evaluate the expression 132 DwarfExpressionEvaluator evaluator(this); 133 error = evaluator.Evaluate(expression, expressionLength, 134 fFrameBasePointer); 135 if (error != B_OK) 136 return false; 137 138 TRACE_EXPR(" -> frame base: %" B_PRIx64 "\n", fFrameBasePointer); 139 140 _address = fFrameBasePointer; 141 return true; 142 } 143 144 virtual bool GetTLSAddress(target_addr_t localAddress, 145 target_addr_t& _address) 146 { 147 // TODO:... 148 return false; 149 } 150 151 virtual status_t GetCallTarget(uint64 offset, uint8 refType, 152 const void*& _block, off_t& _size) 153 { 154 // resolve the entry 155 DebugInfoEntry* entry = fFile->_ResolveReference(fUnit, offset, refType); 156 if (entry == NULL) 157 return B_ENTRY_NOT_FOUND; 158 159 // get the location description 160 LocationDescription* location = entry->GetLocationDescription(); 161 if (location == NULL || !location->IsValid()) { 162 _block = NULL; 163 _size = 0; 164 return B_OK; 165 } 166 167 // get the expression 168 return fFile->_GetLocationExpression(fUnit, location, 169 fInstructionPointer, _block, _size); 170 } 171 172 private: 173 DwarfFile* fFile; 174 CompilationUnit* fUnit; 175 DIESubprogram* fSubprogramEntry; 176 target_addr_t fInstructionPointer; 177 target_addr_t fObjectPointer; 178 bool fHasObjectPointer; 179 target_addr_t fFramePointer; 180 target_addr_t fFrameBasePointer; 181 bool fFrameBaseEvaluated; 182 }; 183 184 185 // #pragma mark - FDEAugmentation 186 187 188 struct DwarfFile::FDEAugmentation { 189 // Currently we're ignoring all augmentation data. 190 }; 191 192 193 // #pragma mark - CIEAugmentation 194 195 196 enum { 197 CFI_AUGMENTATION_DATA = 0x01, 198 CFI_AUGMENTATION_LANGUAGE_SPECIFIC_DATA = 0x02, 199 CFI_AUGMENTATION_PERSONALITY = 0x04, 200 CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT = 0x08, 201 }; 202 203 204 // encodings for CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT 205 enum { 206 CFI_ADDRESS_FORMAT_ABSOLUTE = 0x00, 207 CFI_ADDRESS_FORMAT_UNSIGNED_LEB128 = 0x01, 208 CFI_ADDRESS_FORMAT_UNSIGNED_16 = 0x02, 209 CFI_ADDRESS_FORMAT_UNSIGNED_32 = 0x03, 210 CFI_ADDRESS_FORMAT_UNSIGNED_64 = 0x04, 211 CFI_ADDRESS_FORMAT_SIGNED = 0x08, 212 CFI_ADDRESS_FORMAT_SIGNED_LEB128 = 213 CFI_ADDRESS_FORMAT_UNSIGNED_LEB128 | CFI_ADDRESS_FORMAT_SIGNED, 214 CFI_ADDRESS_FORMAT_SIGNED_16 = 215 CFI_ADDRESS_FORMAT_UNSIGNED_16 | CFI_ADDRESS_FORMAT_SIGNED, 216 CFI_ADDRESS_FORMAT_SIGNED_32 = 217 CFI_ADDRESS_FORMAT_UNSIGNED_32 | CFI_ADDRESS_FORMAT_SIGNED, 218 CFI_ADDRESS_FORMAT_SIGNED_64 = 219 CFI_ADDRESS_FORMAT_UNSIGNED_64 | CFI_ADDRESS_FORMAT_SIGNED 220 }; 221 222 223 enum { 224 CFI_ADDRESS_TYPE_PC_RELATIVE = 0x10, 225 CFI_ADDRESS_TYPE_TEXT_RELATIVE = 0x20, 226 CFI_ADDRESS_TYPE_DATA_RELATIVE = 0x30, 227 CFI_ADDRESS_TYPE_FUNCTION_RELATIVE = 0x40, 228 CFI_ADDRESS_TYPE_ALIGNED = 0x50, 229 CFI_ADDRESS_TYPE_INDIRECT = 0x80 230 }; 231 232 233 struct DwarfFile::CIEAugmentation { 234 CIEAugmentation() 235 : 236 fString(NULL), 237 fFlags(0), 238 fAddressEncoding(CFI_ADDRESS_FORMAT_ABSOLUTE) 239 { 240 // we default to absolute address format since that corresponds 241 // to the DWARF standard for .debug_frame. In gcc's case, however, 242 // .eh_frame will generally override that via augmentation 'R' 243 } 244 245 void Init(DataReader& dataReader) 246 { 247 fFlags = 0; 248 fString = dataReader.ReadString(); 249 } 250 251 status_t Read(DataReader& dataReader) 252 { 253 if (fString == NULL || *fString == '\0') 254 return B_OK; 255 256 if (*fString == 'z') { 257 // There are augmentation data. 258 fFlags |= CFI_AUGMENTATION_DATA; 259 const char* string = fString + 1; 260 261 // read the augmentation data block -- it is preceeded by an 262 // LEB128 indicating the length of the data block 263 uint64 length = dataReader.ReadUnsignedLEB128(0); 264 uint64 remaining = length; 265 // let's see what data we have to expect 266 267 TRACE_CFI(" %" B_PRIu64 " bytes of augmentation data\n", length); 268 while (*string != '\0') { 269 switch (*string) { 270 case 'L': 271 fFlags |= CFI_AUGMENTATION_LANGUAGE_SPECIFIC_DATA; 272 dataReader.Read<char>(0); 273 --remaining; 274 break; 275 case 'P': 276 { 277 char tempEncoding = fAddressEncoding; 278 fAddressEncoding = dataReader.Read<char>(0); 279 off_t offset = dataReader.Offset(); 280 ReadEncodedAddress(dataReader, NULL, NULL, true); 281 fAddressEncoding = tempEncoding; 282 remaining -= dataReader.Offset() - offset + 1; 283 break; 284 } 285 case 'R': 286 fFlags |= CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT; 287 fAddressEncoding = dataReader.Read<char>(0); 288 --remaining; 289 break; 290 default: 291 WARNING("Encountered unsupported augmentation '%c' " 292 " while parsing CIE augmentation string %s\n", 293 *string, fString); 294 return B_UNSUPPORTED; 295 } 296 string++; 297 } 298 299 // we should have read through all of the augmentation data 300 // at this point, if not, something is wrong. 301 if (remaining != 0 || dataReader.HasOverflow()) { 302 WARNING("Error while reading CIE Augmentation, expected " 303 "%" B_PRIu64 " bytes of augmentation data, but read " 304 "%" B_PRIu64 " bytes.\n", length, length - remaining); 305 return B_BAD_DATA; 306 } 307 308 return B_OK; 309 } 310 311 // nothing to do 312 if (strcmp(fString, "eh") == 0) 313 return B_OK; 314 315 // something we can't handle 316 return B_UNSUPPORTED; 317 } 318 319 status_t ReadFDEData(DataReader& dataReader, 320 FDEAugmentation& fdeAugmentation) 321 { 322 if (!HasData()) 323 return B_OK; 324 325 // read the augmentation data block -- it is preceeded by an LEB128 326 // indicating the length of the data block 327 uint64 length = dataReader.ReadUnsignedLEB128(0); 328 dataReader.Skip(length); 329 // TODO: Actually read what is interesting for us! 330 331 TRACE_CFI(" %" B_PRIu64 " bytes of augmentation data\n", length); 332 333 if (dataReader.HasOverflow()) 334 return B_BAD_DATA; 335 336 return B_OK; 337 } 338 339 const char* String() const 340 { 341 return fString; 342 } 343 344 bool HasData() const 345 { 346 return (fFlags & CFI_AUGMENTATION_DATA) != 0; 347 } 348 349 bool HasFDEAddressFormat() const 350 { 351 return (fFlags & CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT) != 0; 352 } 353 354 target_addr_t FDEAddressOffset(ElfFile* file, 355 ElfSection* debugFrameSection) const 356 { 357 switch (FDEAddressType()) { 358 case CFI_ADDRESS_FORMAT_ABSOLUTE: 359 TRACE_CFI("FDE address format: absolute, "); 360 return 0; 361 case CFI_ADDRESS_TYPE_PC_RELATIVE: 362 TRACE_CFI("FDE address format: PC relative, "); 363 return debugFrameSection->LoadAddress(); 364 case CFI_ADDRESS_TYPE_FUNCTION_RELATIVE: 365 TRACE_CFI("FDE address format: function relative, "); 366 return 0; 367 case CFI_ADDRESS_TYPE_TEXT_RELATIVE: 368 TRACE_CFI("FDE address format: text relative, "); 369 return file->TextSegment()->LoadAddress(); 370 case CFI_ADDRESS_TYPE_DATA_RELATIVE: 371 TRACE_CFI("FDE address format: data relative, "); 372 return file->DataSegment()->LoadAddress(); 373 case CFI_ADDRESS_TYPE_ALIGNED: 374 case CFI_ADDRESS_TYPE_INDIRECT: 375 TRACE_CFI("FDE address format: UNIMPLEMENTED, "); 376 // TODO: implement 377 // -- note: type indirect is currently not generated 378 return 0; 379 } 380 381 return 0; 382 } 383 384 uint8 FDEAddressType() const 385 { 386 return fAddressEncoding & 0x70; 387 } 388 389 target_addr_t ReadEncodedAddress(DataReader &reader, 390 ElfFile* file, ElfSection* debugFrameSection, 391 bool valueOnly = false) const 392 { 393 target_addr_t address = valueOnly ? 0 : FDEAddressOffset(file, 394 debugFrameSection); 395 switch (fAddressEncoding & 0x0f) { 396 case CFI_ADDRESS_FORMAT_ABSOLUTE: 397 address += reader.ReadAddress(0); 398 TRACE_CFI(" target address: %" B_PRId64 "\n", address); 399 break; 400 case CFI_ADDRESS_FORMAT_UNSIGNED_LEB128: 401 address += reader.ReadUnsignedLEB128(0); 402 TRACE_CFI(" unsigned LEB128: %" B_PRId64 "\n", address); 403 break; 404 case CFI_ADDRESS_FORMAT_SIGNED_LEB128: 405 address += reader.ReadSignedLEB128(0); 406 TRACE_CFI(" signed LEB128: %" B_PRId64 "\n", address); 407 break; 408 case CFI_ADDRESS_FORMAT_UNSIGNED_16: 409 address += reader.Read<uint16>(0); 410 TRACE_CFI(" unsigned 16-bit: %" B_PRId64 "\n", address); 411 break; 412 case CFI_ADDRESS_FORMAT_SIGNED_16: 413 address += reader.Read<int16>(0); 414 TRACE_CFI(" signed 16-bit: %" B_PRId64 "\n", address); 415 break; 416 case CFI_ADDRESS_FORMAT_UNSIGNED_32: 417 address += reader.Read<uint32>(0); 418 TRACE_CFI(" unsigned 32-bit: %" B_PRId64 "\n", address); 419 break; 420 case CFI_ADDRESS_FORMAT_SIGNED_32: 421 address += reader.Read<int32>(0); 422 TRACE_CFI(" signed 32-bit: %" B_PRId64 "\n", address); 423 break; 424 case CFI_ADDRESS_FORMAT_UNSIGNED_64: 425 address += reader.Read<uint64>(0); 426 TRACE_CFI(" unsigned 64-bit: %" B_PRId64 "\n", address); 427 break; 428 case CFI_ADDRESS_FORMAT_SIGNED_64: 429 address += reader.Read<int64>(0); 430 TRACE_CFI(" signed 64-bit: %" B_PRId64 "\n", address); 431 break; 432 } 433 434 return address; 435 } 436 437 438 private: 439 const char* fString; 440 uint32 fFlags; 441 int8 fAddressEncoding; 442 }; 443 444 445 // #pragma mark - FDELookupInfo 446 447 448 struct DwarfFile::FDELookupInfo { 449 public: 450 FDELookupInfo(target_addr_t start, target_addr_t end, 451 uint64 fdeOffset, uint64 cieOffset, bool ehFrame) 452 : 453 start(start), 454 end(end), 455 fdeOffset(fdeOffset), 456 cieOffset(cieOffset), 457 ehFrame(ehFrame) 458 { 459 } 460 461 static int CompareFDEInfos(const FDELookupInfo* a, const FDELookupInfo* b) 462 { 463 if (a->start < b->start) 464 return -1; 465 else if (a->start > b->start) 466 return 1; 467 468 return 0; 469 } 470 471 inline bool ContainsAddress(target_addr_t address) const 472 { 473 return address >= start && address < end; 474 } 475 476 target_addr_t start; 477 target_addr_t end; 478 uint64 fdeOffset; 479 uint64 cieOffset; 480 bool ehFrame; 481 }; 482 483 484 // #pragma mark - DwarfFile 485 486 487 DwarfFile::DwarfFile() 488 : 489 fName(NULL), 490 fAlternateName(NULL), 491 fElfFile(NULL), 492 fAlternateElfFile(NULL), 493 fDebugInfoSection(NULL), 494 fDebugAbbrevSection(NULL), 495 fDebugAddressSection(NULL), 496 fDebugStringSection(NULL), 497 fDebugStrOffsetsSection(NULL), 498 fDebugRangesSection(NULL), 499 fDebugLineSection(NULL), 500 fDebugLineStrSection(NULL), 501 fDebugFrameSection(NULL), 502 fEHFrameSection(NULL), 503 fDebugLocationSection(NULL), 504 fDebugPublicTypesSection(NULL), 505 fDebugTypesSection(NULL), 506 fCompilationUnits(20, true), 507 fTypeUnits(), 508 fDebugFrameInfos(100, true), 509 fEHFrameInfos(100, true), 510 fTypesSectionRequired(false), 511 fFinished(false), 512 fItaniumEHFrameFormat(false), 513 fFinishError(B_OK) 514 { 515 } 516 517 518 DwarfFile::~DwarfFile() 519 { 520 while (AbbreviationTable* table = fAbbreviationTables.RemoveHead()) 521 delete table; 522 523 if (fElfFile != NULL) { 524 ElfFile* debugInfoFile = fAlternateElfFile != NULL 525 ? fAlternateElfFile : fElfFile; 526 527 debugInfoFile->PutSection(fDebugInfoSection); 528 debugInfoFile->PutSection(fDebugAbbrevSection); 529 debugInfoFile->PutSection(fDebugAddressSection); 530 debugInfoFile->PutSection(fDebugStringSection); 531 debugInfoFile->PutSection(fDebugStrOffsetsSection); 532 debugInfoFile->PutSection(fDebugRangesSection); 533 debugInfoFile->PutSection(fDebugLineSection); 534 debugInfoFile->PutSection(fDebugLineStrSection); 535 debugInfoFile->PutSection(fDebugFrameSection); 536 fElfFile->PutSection(fEHFrameSection); 537 debugInfoFile->PutSection(fDebugLocationSection); 538 debugInfoFile->PutSection(fDebugPublicTypesSection); 539 delete fElfFile; 540 delete fAlternateElfFile; 541 } 542 543 TypeUnitTableEntry* entry = fTypeUnits.Clear(true); 544 while (entry != NULL) { 545 TypeUnitTableEntry* nextEntry = entry->next; 546 delete entry; 547 entry = nextEntry; 548 } 549 550 free(fName); 551 free(fAlternateName); 552 } 553 554 555 status_t 556 DwarfFile::StartLoading(const char* fileName, BString& _requiredExternalFile) 557 { 558 fName = strdup(fileName); 559 if (fName == NULL) 560 return B_NO_MEMORY; 561 562 status_t error = fTypeUnits.Init(); 563 if (error != B_OK) 564 return error; 565 566 // load the ELF file 567 fElfFile = new(std::nothrow) ElfFile; 568 if (fElfFile == NULL) 569 return B_NO_MEMORY; 570 571 error = fElfFile->Init(fileName); 572 if (error != B_OK) 573 return error; 574 575 return _LocateDebugInfo(_requiredExternalFile); 576 } 577 578 579 status_t 580 DwarfFile::Load(uint8 addressSize, bool isBigEndian, const BString& externalInfoFilePath) 581 { 582 status_t error = B_OK; 583 if (fDebugInfoSection == NULL) { 584 BString path; 585 error = _LocateDebugInfo(path, externalInfoFilePath.IsEmpty() 586 ? NULL : externalInfoFilePath.String()); 587 if (error != B_OK) 588 return error; 589 } 590 591 ElfFile* debugInfoFile = fAlternateElfFile != NULL 592 ? fAlternateElfFile : fElfFile; 593 594 // non mandatory sections 595 fDebugAddressSection = debugInfoFile->GetSection(".debug_addr"); 596 fDebugStringSection = debugInfoFile->GetSection(".debug_str"); 597 fDebugStrOffsetsSection = debugInfoFile->GetSection(".debug_str_offsets"); 598 fDebugRangesSection = debugInfoFile->GetSection(".debug_ranges"); 599 fDebugLineSection = debugInfoFile->GetSection(".debug_line"); 600 fDebugLineStrSection = debugInfoFile->GetSection(".debug_line_str"); 601 fDebugFrameSection = debugInfoFile->GetSection(".debug_frame"); 602 603 if (fDebugFrameSection != NULL) { 604 error = _ParseFrameSection(fDebugFrameSection, 605 addressSize, isBigEndian, 606 false, fDebugFrameInfos); 607 if (error != B_OK) 608 return error; 609 } 610 611 // .eh_frame doesn't appear to get copied into separate debug 612 // info files properly, therefore always use it off the main 613 // executable image 614 if (fEHFrameSection == NULL) 615 fEHFrameSection = fElfFile->GetSection(".eh_frame"); 616 617 if (fEHFrameSection != NULL) { 618 error = _ParseFrameSection(fEHFrameSection, 619 addressSize, isBigEndian, 620 true, fEHFrameInfos); 621 if (error != B_OK) 622 return error; 623 } 624 625 fDebugLocationSection = debugInfoFile->GetSection(".debug_loc"); 626 fDebugPublicTypesSection = debugInfoFile->GetSection(".debug_pubtypes"); 627 628 if (fDebugInfoSection == NULL) { 629 fFinished = true; 630 return B_OK; 631 } 632 633 error = _ParseDebugInfoSection(addressSize, isBigEndian); 634 if (error != B_OK) 635 return error; 636 637 if (fTypesSectionRequired) { 638 fDebugTypesSection = debugInfoFile->GetSection(".debug_types"); 639 if (fDebugTypesSection == NULL) { 640 WARNING(".debug_types section required but missing.\n"); 641 return B_BAD_DATA; 642 } 643 error = _ParseTypesSection(addressSize, isBigEndian); 644 if (error != B_OK) 645 return error; 646 } 647 648 return B_OK; 649 } 650 651 652 status_t 653 DwarfFile::FinishLoading(uint8 addressSize, bool isBigEndian) 654 { 655 if (fFinished) 656 return B_OK; 657 if (fFinishError != B_OK) 658 return fFinishError; 659 660 status_t error; 661 for (TypeUnitTable::Iterator it = fTypeUnits.GetIterator(); 662 TypeUnitTableEntry* entry = it.Next();) { 663 error = _FinishUnit(entry->unit); 664 if (error != B_OK) 665 return fFinishError = error; 666 } 667 668 for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i); 669 i++) { 670 error = _FinishUnit(unit); 671 if (error != B_OK) 672 return fFinishError = error; 673 } 674 675 _ParsePublicTypesInfo(addressSize, isBigEndian); 676 677 fFinished = true; 678 return B_OK; 679 } 680 681 682 int32 683 DwarfFile::CountCompilationUnits() const 684 { 685 return fCompilationUnits.CountItems(); 686 } 687 688 689 CompilationUnit* 690 DwarfFile::CompilationUnitAt(int32 index) const 691 { 692 return fCompilationUnits.ItemAt(index); 693 } 694 695 696 CompilationUnit* 697 DwarfFile::CompilationUnitForDIE(const DebugInfoEntry* entry) const 698 { 699 // find the root of the tree the entry lives in 700 while (entry != NULL && entry->Parent() != NULL) 701 entry = entry->Parent(); 702 703 // that should be the compilation unit entry 704 const DIECompileUnitBase* unitEntry 705 = dynamic_cast<const DIECompileUnitBase*>(entry); 706 if (unitEntry == NULL) 707 return NULL; 708 709 // find the compilation unit 710 for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i); 711 i++) { 712 if (unit->UnitEntry() == unitEntry) 713 return unit; 714 } 715 716 return NULL; 717 } 718 719 720 TargetAddressRangeList* 721 DwarfFile::ResolveRangeList(CompilationUnit* unit, uint64 offset) const 722 { 723 if (unit == NULL || fDebugRangesSection == NULL) 724 return NULL; 725 726 if (offset >= (uint64)fDebugRangesSection->Size()) 727 return NULL; 728 729 TargetAddressRangeList* ranges = new(std::nothrow) TargetAddressRangeList; 730 if (ranges == NULL) { 731 ERROR("Out of memory.\n"); 732 return NULL; 733 } 734 BReference<TargetAddressRangeList> rangesReference(ranges, true); 735 736 target_addr_t baseAddress = unit->AddressRangeBase(); 737 target_addr_t maxAddress = unit->MaxAddress(); 738 739 DataReader dataReader((uint8*)fDebugRangesSection->Data() + offset, 740 fDebugRangesSection->Size() - offset, unit->AddressSize(), unit->IsBigEndian()); 741 while (true) { 742 target_addr_t start = dataReader.ReadAddress(0); 743 target_addr_t end = dataReader.ReadAddress(0); 744 if (dataReader.HasOverflow()) 745 return NULL; 746 747 if (start == 0 && end == 0) 748 break; 749 if (start == maxAddress) { 750 baseAddress = end; 751 continue; 752 } 753 if (start == end) 754 continue; 755 756 if (!ranges->AddRange(baseAddress + start, end - start)) { 757 ERROR("Out of memory.\n"); 758 return NULL; 759 } 760 } 761 762 return rangesReference.Detach(); 763 } 764 765 766 status_t 767 DwarfFile::UnwindCallFrame(CompilationUnit* unit, uint8 addressSize, bool isBigEndian, 768 DIESubprogram* subprogramEntry, target_addr_t location, 769 const DwarfTargetInterface* inputInterface, 770 DwarfTargetInterface* outputInterface, target_addr_t& _framePointer) 771 { 772 FDELookupInfo* info = _GetContainingFDEInfo(location); 773 if (info == NULL) 774 return B_ENTRY_NOT_FOUND; 775 776 return _UnwindCallFrame(unit, addressSize, isBigEndian, 777 subprogramEntry, location, info, 778 inputInterface, outputInterface, _framePointer); 779 } 780 781 782 status_t 783 DwarfFile::EvaluateExpression(CompilationUnit* unit, uint8 addressSize, bool isBigEndian, 784 DIESubprogram* subprogramEntry, const void* expression, 785 off_t expressionLength, const DwarfTargetInterface* targetInterface, 786 target_addr_t instructionPointer, target_addr_t framePointer, 787 target_addr_t valueToPush, bool pushValue, target_addr_t& _result) 788 { 789 ExpressionEvaluationContext context(this, unit, addressSize, isBigEndian, 790 subprogramEntry, targetInterface, instructionPointer, 0, false, 791 framePointer, 0); 792 DwarfExpressionEvaluator evaluator(&context); 793 794 if (pushValue && evaluator.Push(valueToPush) != B_OK) 795 return B_NO_MEMORY; 796 797 return evaluator.Evaluate(expression, expressionLength, _result); 798 } 799 800 801 status_t 802 DwarfFile::ResolveLocation(CompilationUnit* unit, uint8 addressSize, bool isBigEndian, 803 DIESubprogram* subprogramEntry, const LocationDescription* location, 804 const DwarfTargetInterface* targetInterface, 805 target_addr_t instructionPointer, target_addr_t objectPointer, 806 bool hasObjectPointer, target_addr_t framePointer, 807 target_addr_t relocationDelta, ValueLocation& _result) 808 { 809 // get the expression 810 const void* expression; 811 off_t expressionLength; 812 status_t error = _GetLocationExpression(unit, location, instructionPointer, 813 expression, expressionLength); 814 if (error != B_OK) 815 return error; 816 817 // evaluate it 818 ExpressionEvaluationContext context(this, unit, addressSize, isBigEndian, 819 subprogramEntry, targetInterface, instructionPointer, objectPointer, 820 hasObjectPointer, framePointer, relocationDelta); 821 DwarfExpressionEvaluator evaluator(&context); 822 return evaluator.EvaluateLocation(expression, expressionLength, 823 _result); 824 } 825 826 827 status_t 828 DwarfFile::EvaluateConstantValue(CompilationUnit* unit, uint8 addressSize, bool isBigEndian, 829 DIESubprogram* subprogramEntry, const ConstantAttributeValue* value, 830 const DwarfTargetInterface* targetInterface, 831 target_addr_t instructionPointer, target_addr_t framePointer, 832 BVariant& _result) 833 { 834 if (!value->IsValid()) 835 return B_BAD_VALUE; 836 837 switch (value->attributeClass) { 838 case ATTRIBUTE_CLASS_CONSTANT: 839 _result.SetTo(value->constant); 840 return B_OK; 841 case ATTRIBUTE_CLASS_STRING: 842 _result.SetTo(value->string); 843 return B_OK; 844 case ATTRIBUTE_CLASS_BLOCK: 845 { 846 target_addr_t result; 847 status_t error = EvaluateExpression(unit, addressSize, isBigEndian, 848 subprogramEntry, value->block.data, value->block.length, 849 targetInterface, instructionPointer, framePointer, 0, false, 850 result); 851 if (error != B_OK) 852 return error; 853 854 _result.SetTo(result); 855 return B_OK; 856 } 857 default: 858 return B_BAD_VALUE; 859 } 860 } 861 862 863 status_t 864 DwarfFile::EvaluateDynamicValue(CompilationUnit* unit, uint8 addressSize, bool isBigEndian, 865 DIESubprogram* subprogramEntry, const DynamicAttributeValue* value, 866 const DwarfTargetInterface* targetInterface, 867 target_addr_t instructionPointer, target_addr_t framePointer, 868 BVariant& _result, DIEType** _type) 869 { 870 if (!value->IsValid()) 871 return B_BAD_VALUE; 872 873 DIEType* dummyType; 874 if (_type == NULL) 875 _type = &dummyType; 876 877 switch (value->attributeClass) { 878 case ATTRIBUTE_CLASS_CONSTANT: 879 _result.SetTo(value->constant); 880 *_type = NULL; 881 return B_OK; 882 883 case ATTRIBUTE_CLASS_REFERENCE: 884 { 885 // TODO: The specs are a bit fuzzy on this one: "the value is a 886 // reference to another entity whose value is the value of the 887 // attribute". Supposedly that also means e.g. if the referenced 888 // entity is a variable, we should read the value of that variable. 889 // ATM we only check for the types that can have a DW_AT_const_value 890 // attribute and evaluate it, if present. 891 DebugInfoEntry* entry = value->reference; 892 if (entry == NULL) 893 return B_BAD_VALUE; 894 895 const ConstantAttributeValue* constantValue = NULL; 896 DIEType* type = NULL; 897 898 switch (entry->Tag()) { 899 case DW_TAG_constant: 900 { 901 DIEConstant* constantEntry 902 = dynamic_cast<DIEConstant*>(entry); 903 constantValue = constantEntry->ConstValue(); 904 type = constantEntry->GetType(); 905 break; 906 } 907 case DW_TAG_enumerator: 908 constantValue = dynamic_cast<DIEEnumerator*>(entry) 909 ->ConstValue(); 910 if (DIEEnumerationType* enumerationType 911 = dynamic_cast<DIEEnumerationType*>( 912 entry->Parent())) { 913 type = enumerationType->GetType(); 914 } 915 break; 916 case DW_TAG_formal_parameter: 917 { 918 DIEFormalParameter* parameterEntry 919 = dynamic_cast<DIEFormalParameter*>(entry); 920 constantValue = parameterEntry->ConstValue(); 921 type = parameterEntry->GetType(); 922 break; 923 } 924 case DW_TAG_template_value_parameter: 925 { 926 DIETemplateValueParameter* parameterEntry 927 = dynamic_cast<DIETemplateValueParameter*>(entry); 928 constantValue = parameterEntry->ConstValue(); 929 type = parameterEntry->GetType(); 930 break; 931 } 932 case DW_TAG_variable: 933 { 934 DIEVariable* variableEntry 935 = dynamic_cast<DIEVariable*>(entry); 936 constantValue = variableEntry->ConstValue(); 937 type = variableEntry->GetType(); 938 break; 939 } 940 default: 941 return B_BAD_VALUE; 942 } 943 944 if (constantValue == NULL || !constantValue->IsValid()) 945 return B_BAD_VALUE; 946 947 status_t error = EvaluateConstantValue(unit, addressSize, isBigEndian, 948 subprogramEntry, constantValue, targetInterface, 949 instructionPointer, framePointer, _result); 950 if (error != B_OK) 951 return error; 952 953 *_type = type; 954 return B_OK; 955 } 956 957 case ATTRIBUTE_CLASS_BLOCK: 958 { 959 target_addr_t result; 960 status_t error = EvaluateExpression(unit, addressSize, isBigEndian, 961 subprogramEntry, value->block.data, value->block.length, 962 targetInterface, instructionPointer, framePointer, 0, false, 963 result); 964 if (error != B_OK) 965 return error; 966 967 _result.SetTo(result); 968 *_type = NULL; 969 return B_OK; 970 } 971 972 default: 973 return B_BAD_VALUE; 974 } 975 } 976 977 978 status_t 979 DwarfFile::_ParseDebugInfoSection(uint8 _addressSize, bool isBigEndian) 980 { 981 // iterate through the debug info section 982 DataReader dataReader(fDebugInfoSection->Data(), 983 fDebugInfoSection->Size(), _addressSize, isBigEndian); 984 985 while (dataReader.HasData()) { 986 off_t unitHeaderOffset = dataReader.Offset(); 987 bool dwarf64; 988 uint64 unitLength = dataReader.ReadInitialLength(dwarf64); 989 990 off_t unitLengthOffset = dataReader.Offset(); 991 // the unitLength starts here 992 993 if (unitLengthOffset + unitLength 994 > (uint64)fDebugInfoSection->Size()) { 995 WARNING("\"%s\": Invalid compilation unit length.\n", fName); 996 break; 997 } 998 999 int version = dataReader.Read<uint16>(0); 1000 if (version >= 5) { 1001 uint8 unitType = dataReader.Read<uint8>(0); 1002 if (unitType != DW_UT_compile) { 1003 WARNING("\"%s\": Unsupported unit type %d\n", 1004 fName, unitType); 1005 return B_UNSUPPORTED; 1006 } 1007 } 1008 1009 off_t abbrevOffset; 1010 uint8 addressSize; 1011 1012 if (version >= 5) { 1013 addressSize = dataReader.Read<uint8>(0); 1014 abbrevOffset = dwarf64 1015 ? dataReader.Read<uint64>(0) 1016 : dataReader.Read<uint32>(0); 1017 } else { 1018 abbrevOffset = dwarf64 1019 ? dataReader.Read<uint64>(0) 1020 : dataReader.Read<uint32>(0); 1021 addressSize = dataReader.Read<uint8>(0); 1022 } 1023 1024 if (dataReader.HasOverflow()) { 1025 WARNING("\"%s\": Unexpected end of data in compilation unit " 1026 "header.\n", fName); 1027 break; 1028 } 1029 1030 TRACE_DIE("DWARF%d compilation unit: version %d, length: %" B_PRIu64 1031 ", abbrevOffset: %" B_PRIdOFF ", address size: %d\n", 1032 dwarf64 ? 64 : 32, version, unitLength, abbrevOffset, addressSize); 1033 1034 if (version < 2 || version > 4) { 1035 WARNING("\"%s\": Unsupported compilation unit version: %d\n", 1036 fName, version); 1037 break; 1038 } 1039 1040 if (addressSize != 4 && addressSize != 8) { 1041 WARNING("\"%s\": Unsupported address size: %d\n", fName, 1042 addressSize); 1043 break; 1044 } 1045 dataReader.SetAddressSize(addressSize); 1046 1047 off_t unitContentOffset = dataReader.Offset(); 1048 1049 // create a compilation unit object 1050 CompilationUnit* unit = new(std::nothrow) CompilationUnit( 1051 unitHeaderOffset, unitContentOffset, 1052 unitLength + (unitLengthOffset - unitHeaderOffset), 1053 abbrevOffset, addressSize, isBigEndian, dwarf64); 1054 if (unit == NULL || !fCompilationUnits.AddItem(unit)) { 1055 delete unit; 1056 return B_NO_MEMORY; 1057 } 1058 1059 // parse the debug info for the unit 1060 status_t error = _ParseCompilationUnit(unit); 1061 if (error != B_OK) 1062 return error; 1063 1064 dataReader.SeekAbsolute(unitLengthOffset + unitLength); 1065 } 1066 1067 return B_OK; 1068 } 1069 1070 1071 status_t 1072 DwarfFile::_ParseTypesSection(uint8 _addressSize, bool isBigEndian) 1073 { 1074 DataReader dataReader(fDebugTypesSection->Data(), 1075 fDebugTypesSection->Size(), _addressSize, isBigEndian); 1076 while (dataReader.HasData()) { 1077 off_t unitHeaderOffset = dataReader.Offset(); 1078 bool dwarf64; 1079 uint64 unitLength = dataReader.ReadInitialLength(dwarf64); 1080 1081 off_t unitLengthOffset = dataReader.Offset(); 1082 // the unitLength starts here 1083 1084 if (unitLengthOffset + unitLength 1085 > (uint64)fDebugTypesSection->Size()) { 1086 WARNING("Invalid type unit length, offset %#" B_PRIx64 ".\n", 1087 unitHeaderOffset); 1088 break; 1089 } 1090 1091 int version = dataReader.Read<uint16>(0); 1092 off_t abbrevOffset = dwarf64 1093 ? dataReader.Read<uint64>(0) 1094 : dataReader.Read<uint32>(0); 1095 uint8 addressSize = dataReader.Read<uint8>(0); 1096 1097 if (dataReader.HasOverflow()) { 1098 WARNING("Unexpected end of data in type unit header at %#" 1099 B_PRIx64 ".\n", unitHeaderOffset); 1100 break; 1101 } 1102 1103 dataReader.SetAddressSize(addressSize); 1104 1105 uint64 signature = dataReader.Read<uint64>(0); 1106 1107 off_t typeOffset = dwarf64 1108 ? dataReader.Read<uint64>(0) 1109 : dataReader.Read<uint32>(0); 1110 1111 off_t unitContentOffset = dataReader.Offset(); 1112 1113 TRACE_DIE("DWARF%d type unit: version %d, length: %" B_PRIu64 1114 ", abbrevOffset: %" B_PRIdOFF ", address size: %d, " 1115 "signature: %#" B_PRIx64 ", type offset: %" B_PRIu64 "\n", 1116 dwarf64 ? 64 : 32, version, unitLength, abbrevOffset, addressSize, 1117 signature, typeOffset); 1118 1119 if (version > 4) { 1120 WARNING("\"%s\": Unsupported type unit version: %d\n", 1121 fName, version); 1122 break; 1123 } 1124 1125 if (addressSize != 4 && addressSize != 8) { 1126 WARNING("\"%s\": Unsupported address size: %d\n", fName, 1127 addressSize); 1128 break; 1129 } 1130 1131 // create a type unit object 1132 TypeUnit* unit = new(std::nothrow) TypeUnit( 1133 unitHeaderOffset, unitContentOffset, 1134 unitLength + (unitLengthOffset - unitHeaderOffset), 1135 abbrevOffset, typeOffset, addressSize, isBigEndian, 1136 signature, dwarf64); 1137 if (unit == NULL) 1138 return B_NO_MEMORY; 1139 1140 // parse the debug info for the unit 1141 status_t error = _ParseTypeUnit(unit); 1142 if (error != B_OK) 1143 return error; 1144 1145 // TODO: it should theoretically never happen that we get a duplicate, 1146 // but it wouldn't hurt to check since that situation would potentially 1147 // be problematic. 1148 if (fTypeUnits.Lookup(signature) == NULL) { 1149 TypeUnitTableEntry* entry = new(std::nothrow) 1150 TypeUnitTableEntry(signature, unit); 1151 if (entry == NULL) 1152 return B_NO_MEMORY; 1153 1154 fTypeUnits.Insert(entry); 1155 } 1156 1157 dataReader.SeekAbsolute(unitLengthOffset + unitLength); 1158 } 1159 1160 return B_OK; 1161 } 1162 1163 1164 status_t 1165 DwarfFile::_ParseFrameSection(ElfSection* section, uint8 addressSize, bool isBigEndian, 1166 bool ehFrame, FDEInfoList& infos) 1167 { 1168 if (ehFrame) { 1169 fItaniumEHFrameFormat = section->IsWritable(); 1170 // Crude heuristic for recognizing GCC 4 (Itanium ABI) style 1171 // .eh_frame sections. The ones generated by GCC 2 are writable, 1172 // the ones generated by GCC 4 aren't. 1173 } 1174 1175 DataReader dataReader((uint8*)section->Data(), 1176 section->Size(), addressSize, isBigEndian); 1177 1178 while (dataReader.BytesRemaining() > 0) { 1179 // length 1180 bool dwarf64; 1181 off_t entryOffset = dataReader.Offset(); 1182 uint64 length = dataReader.ReadInitialLength(dwarf64); 1183 1184 TRACE_CFI("DwarfFile::_ParseFrameSection(): offset: %" B_PRIdOFF 1185 ", length: %" B_PRId64 "\n", entryOffset, length); 1186 1187 if (length > (uint64)dataReader.BytesRemaining()) 1188 return B_BAD_DATA; 1189 off_t lengthOffset = dataReader.Offset(); 1190 1191 // If the length is 0, it means a terminator of the CIE. 1192 // Then just skip this .debug_frame/.eh_frame section. 1193 if (length == 0) 1194 return B_OK; 1195 1196 // CIE ID/CIE pointer 1197 uint64 cieID = dwarf64 1198 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0); 1199 1200 // In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does. 1201 if (ehFrame 1202 ? cieID == 0 1203 : (dwarf64 1204 ? cieID == 0xffffffffffffffffULL 1205 : cieID == 0xffffffff)) { 1206 // this is a CIE -- skip it 1207 } else { 1208 // this is a FDE 1209 uint64 initialLocationOffset = dataReader.Offset(); 1210 // In .eh_frame the CIE offset is a relative back offset. 1211 if (ehFrame) { 1212 if (cieID > (uint64)lengthOffset) { 1213 TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max " 1214 "possible: %" B_PRIu64 "\n", cieID, lengthOffset); 1215 break; 1216 } 1217 // convert to a section relative offset 1218 cieID = lengthOffset - cieID; 1219 } 1220 1221 1222 CfaContext context; 1223 CIEAugmentation cieAugmentation; 1224 // when using .eh_frame format, we need to parse the CIE's 1225 // augmentation up front in order to know how the FDE's addresses 1226 // will be represented 1227 DataReader cieReader; 1228 off_t cieRemaining; 1229 status_t error = _ParseCIEHeader(section, ehFrame, NULL, 1230 addressSize, isBigEndian, context, 1231 cieID, cieAugmentation, cieReader, cieRemaining); 1232 if (error != B_OK) 1233 return error; 1234 if (cieReader.HasOverflow()) 1235 return B_BAD_DATA; 1236 if (cieRemaining < 0) 1237 return B_BAD_DATA; 1238 1239 target_addr_t initialLocation = cieAugmentation.ReadEncodedAddress( 1240 dataReader, fElfFile, section); 1241 target_addr_t addressRange = cieAugmentation.ReadEncodedAddress( 1242 dataReader, fElfFile, section, true); 1243 1244 if (dataReader.HasOverflow()) 1245 return B_BAD_DATA; 1246 1247 if ((cieAugmentation.FDEAddressType() 1248 & CFI_ADDRESS_TYPE_PC_RELATIVE) != 0) { 1249 initialLocation += initialLocationOffset; 1250 } 1251 1252 // for unknown reasons, the debug frame sections generated by gcc 1253 // sometimes contain duplicates at different offsets within the 1254 // section. In such a case, simply skip the duplicates. 1255 FDELookupInfo* temp = _GetContainingFDEInfo(initialLocation, 1256 infos); 1257 if (temp == NULL) { 1258 FDELookupInfo* info = new(std::nothrow)FDELookupInfo( 1259 initialLocation, initialLocation + addressRange - 1, 1260 entryOffset, cieID, ehFrame); 1261 if (info == NULL) 1262 return B_NO_MEMORY; 1263 1264 ObjectDeleter<FDELookupInfo> infoDeleter(info); 1265 if (!infos.BinaryInsert(info, FDELookupInfo::CompareFDEInfos)) 1266 return B_NO_MEMORY; 1267 1268 infoDeleter.Detach(); 1269 } 1270 } 1271 1272 dataReader.SeekAbsolute(lengthOffset + length); 1273 } 1274 1275 return B_OK; 1276 } 1277 1278 1279 status_t 1280 DwarfFile::_ParseCompilationUnit(CompilationUnit* unit) 1281 { 1282 AbbreviationTable* abbreviationTable; 1283 status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(), 1284 abbreviationTable); 1285 if (error != B_OK) 1286 return error; 1287 1288 unit->SetAbbreviationTable(abbreviationTable); 1289 1290 DataReader dataReader( 1291 (const uint8*)fDebugInfoSection->Data() + unit->ContentOffset(), 1292 unit->ContentSize(), unit->AddressSize(), unit->IsBigEndian()); 1293 1294 DebugInfoEntry* entry; 1295 bool endOfEntryList; 1296 error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry, 1297 endOfEntryList); 1298 if (error != B_OK) 1299 return error; 1300 1301 DIECompileUnitBase* unitEntry = dynamic_cast<DIECompileUnitBase*>(entry); 1302 if (unitEntry == NULL) { 1303 WARNING("No compilation unit entry in .debug_info section.\n"); 1304 return B_BAD_DATA; 1305 } 1306 1307 unit->SetUnitEntry(unitEntry); 1308 1309 TRACE_DIE_ONLY( 1310 TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n", 1311 dataReader.BytesRemaining()); 1312 if (dataReader.HasData()) { 1313 TRACE_DIE(" "); 1314 while (dataReader.HasData()) 1315 TRACE_DIE("%02x", dataReader.Read<uint8>(0)); 1316 TRACE_DIE("\n"); 1317 } 1318 ) 1319 return B_OK; 1320 } 1321 1322 1323 status_t 1324 DwarfFile::_ParseTypeUnit(TypeUnit* unit) 1325 { 1326 AbbreviationTable* abbreviationTable; 1327 status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(), 1328 abbreviationTable); 1329 if (error != B_OK) 1330 return error; 1331 1332 unit->SetAbbreviationTable(abbreviationTable); 1333 1334 DataReader dataReader( 1335 (const uint8*)fDebugTypesSection->Data() + unit->ContentOffset(), 1336 unit->ContentSize(), unit->AddressSize(), unit->IsBigEndian()); 1337 1338 DebugInfoEntry* entry; 1339 bool endOfEntryList; 1340 error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry, 1341 endOfEntryList); 1342 if (error != B_OK) 1343 return error; 1344 1345 DIETypeUnit* unitEntry = dynamic_cast<DIETypeUnit*>(entry); 1346 if (unitEntry == NULL) { 1347 WARNING("No type unit entry in .debug_types section.\n"); 1348 return B_BAD_DATA; 1349 } 1350 1351 unit->SetUnitEntry(unitEntry); 1352 DebugInfoEntry* typeEntry = unit->EntryForOffset(unit->TypeOffset()); 1353 if (typeEntry == NULL) { 1354 WARNING("No type found for type unit %p at specified offset %" 1355 B_PRId64 ".\n", unit, unit->TypeOffset()); 1356 return B_BAD_DATA; 1357 } 1358 unit->SetTypeEntry(typeEntry); 1359 1360 TRACE_DIE_ONLY( 1361 TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n", 1362 dataReader.BytesRemaining()); 1363 if (dataReader.HasData()) { 1364 TRACE_DIE(" "); 1365 while (dataReader.HasData()) 1366 TRACE_DIE("%02x", dataReader.Read<uint8>(0)); 1367 TRACE_DIE("\n"); 1368 } 1369 ) 1370 return B_OK; 1371 } 1372 1373 1374 status_t 1375 DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader, 1376 BaseUnit* unit, AbbreviationTable* abbreviationTable, 1377 DebugInfoEntry*& _entry, bool& _endOfEntryList, int level) 1378 { 1379 off_t entryOffset = dataReader.Offset() 1380 + unit->RelativeContentOffset(); 1381 1382 uint32 code = dataReader.ReadUnsignedLEB128(0); 1383 if (code == 0) { 1384 if (dataReader.HasOverflow()) { 1385 WARNING("Unexpected end of .debug_info section.\n"); 1386 return B_BAD_DATA; 1387 } 1388 _entry = NULL; 1389 _endOfEntryList = true; 1390 return B_OK; 1391 } 1392 1393 // get the corresponding abbreviation entry 1394 AbbreviationEntry abbreviationEntry; 1395 if (!abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry)) { 1396 WARNING("No abbreviation entry for code %" B_PRIx32 "\n", code); 1397 return B_BAD_DATA; 1398 } 1399 1400 DebugInfoEntry* entry; 1401 status_t error = fDebugInfoFactory.CreateDebugInfoEntry( 1402 abbreviationEntry.Tag(), entry); 1403 if (error != B_OK) { 1404 WARNING("Failed to generate entry for tag %" B_PRIu32 ", code %" 1405 B_PRIu32 "\n", abbreviationEntry.Tag(), code); 1406 return error; 1407 } 1408 1409 ObjectDeleter<DebugInfoEntry> entryDeleter(entry); 1410 1411 TRACE_DIE("%*sentry %p at %" B_PRIdOFF ": %" B_PRIu32 ", tag: %s (%" 1412 B_PRIu32 "), children: %d\n", level * 2, "", entry, entryOffset, 1413 abbreviationEntry.Code(), get_entry_tag_name(abbreviationEntry.Tag()), 1414 abbreviationEntry.Tag(), abbreviationEntry.HasChildren()); 1415 1416 error = unit->AddDebugInfoEntry(entry, entryOffset); 1417 1418 if (error != B_OK) 1419 return error; 1420 1421 // parse the attributes (supply NULL entry to avoid adding them yet) 1422 error = _ParseEntryAttributes(dataReader, unit, NULL, abbreviationEntry); 1423 if (error != B_OK) 1424 return error; 1425 1426 // parse children, if the entry has any 1427 if (abbreviationEntry.HasChildren()) { 1428 while (true) { 1429 DebugInfoEntry* childEntry; 1430 bool endOfEntryList; 1431 status_t error = _ParseDebugInfoEntry(dataReader, 1432 unit, abbreviationTable, childEntry, endOfEntryList, level + 1); 1433 if (error != B_OK) 1434 return error; 1435 1436 // add the child to our entry 1437 if (childEntry != NULL) { 1438 if (entry != NULL) { 1439 error = entry->AddChild(childEntry); 1440 if (error == B_OK) { 1441 childEntry->SetParent(entry); 1442 } else if (error == ENTRY_NOT_HANDLED) { 1443 error = B_OK; 1444 TRACE_DIE("%*s -> child unhandled\n", level * 2, ""); 1445 } 1446 1447 if (error != B_OK) { 1448 delete childEntry; 1449 return error; 1450 } 1451 } else 1452 delete childEntry; 1453 } 1454 1455 if (endOfEntryList) 1456 break; 1457 } 1458 } 1459 1460 entryDeleter.Detach(); 1461 _entry = entry; 1462 _endOfEntryList = false; 1463 return B_OK; 1464 } 1465 1466 1467 status_t 1468 DwarfFile::_FinishUnit(BaseUnit* unit) 1469 { 1470 CompilationUnit* compilationUnit = dynamic_cast<CompilationUnit*>(unit); 1471 bool isTypeUnit = compilationUnit == NULL; 1472 TRACE_DIE("\nfinishing %s unit %p\n", 1473 isTypeUnit ? "type" : "compilation", unit); 1474 1475 1476 AbbreviationTable* abbreviationTable = unit->GetAbbreviationTable(); 1477 1478 ElfSection* section = isTypeUnit 1479 ? fDebugTypesSection : fDebugInfoSection; 1480 DataReader dataReader( 1481 (const uint8*)section->Data() + unit->HeaderOffset(), 1482 unit->TotalSize(), unit->AddressSize(), unit->IsBigEndian()); 1483 1484 DebugInfoEntryInitInfo entryInitInfo; 1485 1486 int entryCount = unit->CountEntries(); 1487 for (int i = 0; i < entryCount; i++) { 1488 // get the entry 1489 DebugInfoEntry* entry; 1490 off_t offset; 1491 unit->GetEntryAt(i, entry, offset); 1492 1493 TRACE_DIE("entry %p at %" B_PRIdOFF "\n", entry, offset); 1494 1495 // seek the reader to the entry 1496 dataReader.SeekAbsolute(offset); 1497 1498 // read the entry code 1499 uint32 code = dataReader.ReadUnsignedLEB128(0); 1500 1501 // get the respective abbreviation entry 1502 AbbreviationEntry abbreviationEntry; 1503 abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry); 1504 1505 // initialization before setting the attributes 1506 status_t error = entry->InitAfterHierarchy(entryInitInfo); 1507 if (error != B_OK) { 1508 WARNING("Init after hierarchy failed!\n"); 1509 return error; 1510 } 1511 1512 // parse the attributes -- this time pass the entry, so that the 1513 // attribute get set on it 1514 error = _ParseEntryAttributes(dataReader, unit, entry, 1515 abbreviationEntry); 1516 if (error != B_OK) 1517 return error; 1518 1519 // initialization after setting the attributes 1520 error = entry->InitAfterAttributes(entryInitInfo); 1521 if (error != B_OK) { 1522 WARNING("Init after attributes failed!\n"); 1523 return error; 1524 } 1525 } 1526 1527 // set the compilation unit's source language 1528 unit->SetSourceLanguage(entryInitInfo.languageInfo); 1529 1530 if (isTypeUnit) 1531 return B_OK; 1532 1533 // resolve the compilation unit's address range list 1534 if (TargetAddressRangeList* ranges = ResolveRangeList(compilationUnit, 1535 compilationUnit->UnitEntry()->AddressRangesOffset())) { 1536 compilationUnit->SetAddressRanges(ranges); 1537 ranges->ReleaseReference(); 1538 } 1539 1540 // add compilation dir to directory list 1541 const char* compilationDir = compilationUnit->UnitEntry() 1542 ->CompilationDir(); 1543 if (!compilationUnit->AddDirectory(compilationDir != NULL 1544 ? compilationDir : ".")) { 1545 return B_NO_MEMORY; 1546 } 1547 1548 // parse line info header 1549 if (fDebugLineSection != NULL) 1550 _ParseLineInfo(compilationUnit); 1551 1552 return B_OK; 1553 } 1554 1555 1556 status_t 1557 DwarfFile::_ReadStringIndirect(BaseUnit* unit, uint64 index, const char*& value) const 1558 { 1559 if (fDebugStrOffsetsSection == NULL) { 1560 WARNING("Invalid DW_FORM_strx*: no debug_str_offsets section!\n"); 1561 return B_BAD_DATA; 1562 } 1563 1564 uint64 strOffsetsBase = unit->IsDwarf64() ? 16 : 8; 1565 uint64 offsetSize = unit->IsDwarf64() ? 8 : 4; 1566 1567 if (strOffsetsBase + index * offsetSize >= fDebugStrOffsetsSection->Size()) { 1568 WARNING("Invalid DW_FORM_strx* index: %" B_PRIu64 "\n", index); 1569 return B_BAD_DATA; 1570 } 1571 1572 const char *strOffsets = (const char*)fDebugStrOffsetsSection->Data() + strOffsetsBase; 1573 uint64 offset = unit->IsDwarf64() 1574 ? ((uint64*)strOffsets)[index] 1575 : ((uint32*)strOffsets)[index]; 1576 1577 if (offset >= fDebugStringSection->Size()) { 1578 WARNING("Invalid DW_FORM_strx* offset: %" B_PRIu64 "\n", offset); 1579 return B_BAD_DATA; 1580 } 1581 1582 value = (const char*)fDebugStringSection->Data() + offset; 1583 return B_OK; 1584 } 1585 1586 1587 status_t 1588 DwarfFile::_ReadAddressIndirect(BaseUnit* unit, uint64 index, uint64& value) const 1589 { 1590 if (fDebugAddressSection == NULL) { 1591 WARNING("Invalid DW_FORM_addrx*: no debug_addr section!\n"); 1592 return B_BAD_DATA; 1593 } 1594 1595 uint64 addrBase = unit->IsDwarf64() ? 16 : 8; 1596 1597 if (addrBase + index * unit->AddressSize() >= fDebugAddressSection->Size()) { 1598 WARNING("Invalid DW_FORM_addrx* index: %" B_PRIu64 "\n", index); 1599 return B_BAD_DATA; 1600 } 1601 1602 const char *addrPtr = (const char*)fDebugAddressSection->Data() 1603 + addrBase + index * unit->AddressSize(); 1604 1605 if (unit->AddressSize() == 8) 1606 value = *(uint64*)addrPtr; 1607 else 1608 value = *(uint32*)addrPtr; 1609 1610 return B_OK; 1611 } 1612 1613 1614 status_t 1615 DwarfFile::_ParseEntryAttributes(DataReader& dataReader, 1616 BaseUnit* unit, DebugInfoEntry* entry, AbbreviationEntry& abbreviationEntry) 1617 { 1618 uint32 attributeName; 1619 uint32 attributeForm; 1620 int32 attributeImplicitConst = 0; 1621 while (abbreviationEntry.GetNextAttribute(attributeName, 1622 attributeForm, attributeImplicitConst)) { 1623 // resolve attribute form indirection 1624 if (attributeForm == DW_FORM_indirect) 1625 attributeForm = dataReader.ReadUnsignedLEB128(0); 1626 1627 // prepare an AttributeValue 1628 AttributeValue attributeValue; 1629 attributeValue.attributeForm = attributeForm; 1630 bool isSigned = false; 1631 1632 // Read the attribute value according to the attribute's form. For 1633 // the forms that don't map to a single attribute class only or 1634 // those that need additional processing, we read a temporary value 1635 // first. 1636 uint64 value = 0; 1637 off_t blockLength = 0; 1638 off_t valueOffset = dataReader.Offset() + unit->ContentOffset(); 1639 uint8 refType = dwarf_reference_type_local; 1640 1641 switch (attributeForm) { 1642 case DW_FORM_addr: 1643 value = dataReader.ReadAddress(0); 1644 break; 1645 case DW_FORM_block2: 1646 blockLength = dataReader.Read<uint16>(0); 1647 break; 1648 case DW_FORM_block4: 1649 blockLength = dataReader.Read<uint32>(0); 1650 break; 1651 case DW_FORM_data2: 1652 value = dataReader.Read<uint16>(0); 1653 break; 1654 case DW_FORM_data4: 1655 value = dataReader.Read<uint32>(0); 1656 break; 1657 case DW_FORM_data8: 1658 value = dataReader.Read<uint64>(0); 1659 break; 1660 case DW_FORM_string: 1661 attributeValue.SetToString(dataReader.ReadString()); 1662 break; 1663 case DW_FORM_block: 1664 case DW_FORM_exprloc: 1665 blockLength = dataReader.ReadUnsignedLEB128(0); 1666 break; 1667 case DW_FORM_block1: 1668 blockLength = dataReader.Read<uint8>(0); 1669 break; 1670 case DW_FORM_data1: 1671 value = dataReader.Read<uint8>(0); 1672 break; 1673 case DW_FORM_flag: 1674 attributeValue.SetToFlag(dataReader.Read<uint8>(0) != 0); 1675 break; 1676 case DW_FORM_sdata: 1677 value = dataReader.ReadSignedLEB128(0); 1678 isSigned = true; 1679 break; 1680 case DW_FORM_strp: 1681 { 1682 if (fDebugStringSection != NULL) { 1683 uint64 offset = unit->IsDwarf64() 1684 ? dataReader.Read<uint64>(0) 1685 : dataReader.Read<uint32>(0); 1686 if (offset >= fDebugStringSection->Size()) { 1687 WARNING("Invalid DW_FORM_strp offset: %" B_PRIu64 "\n", 1688 offset); 1689 return B_BAD_DATA; 1690 } 1691 attributeValue.SetToString( 1692 (const char*)fDebugStringSection->Data() + offset); 1693 } else { 1694 WARNING("Invalid DW_FORM_strp: no string section!\n"); 1695 return B_BAD_DATA; 1696 } 1697 break; 1698 } 1699 case DW_FORM_udata: 1700 value = dataReader.ReadUnsignedLEB128(0); 1701 break; 1702 case DW_FORM_ref_addr: 1703 value = unit->IsDwarf64() 1704 ? dataReader.Read<uint64>(0) 1705 : (uint64)dataReader.Read<uint32>(0); 1706 refType = dwarf_reference_type_global; 1707 break; 1708 case DW_FORM_ref1: 1709 value = dataReader.Read<uint8>(0); 1710 break; 1711 case DW_FORM_ref2: 1712 value = dataReader.Read<uint16>(0); 1713 break; 1714 case DW_FORM_ref4: 1715 value = dataReader.Read<uint32>(0); 1716 break; 1717 case DW_FORM_ref8: 1718 value = dataReader.Read<uint64>(0); 1719 break; 1720 case DW_FORM_ref_udata: 1721 value = dataReader.ReadUnsignedLEB128(0); 1722 break; 1723 case DW_FORM_flag_present: 1724 attributeValue.SetToFlag(true); 1725 break; 1726 case DW_FORM_strx: 1727 { 1728 uint64 index = dataReader.ReadUnsignedLEB128(0); 1729 const char* strValue; 1730 status_t res = _ReadStringIndirect(unit, index, strValue); 1731 if (res != B_OK) 1732 return res; 1733 attributeValue.SetToString(strValue); 1734 break; 1735 } 1736 case DW_FORM_addrx: 1737 { 1738 uint64 index = dataReader.ReadUnsignedLEB128(0); 1739 status_t res = _ReadAddressIndirect(unit, index, value); 1740 if (res != B_OK) 1741 return res; 1742 break; 1743 } 1744 case DW_FORM_line_strp: 1745 { 1746 if (fDebugLineStrSection != NULL) { 1747 uint64 offset = unit->IsDwarf64() 1748 ? dataReader.Read<uint64>(0) 1749 : dataReader.Read<uint32>(0); 1750 if (offset >= fDebugLineStrSection->Size()) { 1751 WARNING("Invalid DW_FORM_line_strp offset: %" B_PRIu64 "\n", 1752 offset); 1753 return B_BAD_DATA; 1754 } 1755 attributeValue.SetToString( 1756 (const char*)fDebugLineStrSection->Data() + offset); 1757 } else { 1758 WARNING("Invalid DW_FORM_line_strp: no debug_line_str section!\n"); 1759 return B_BAD_DATA; 1760 } 1761 break; 1762 } 1763 case DW_FORM_ref_sig8: 1764 fTypesSectionRequired = true; 1765 value = dataReader.Read<uint64>(0); 1766 refType = dwarf_reference_type_signature; 1767 break; 1768 case DW_FORM_implicit_const: 1769 value = attributeImplicitConst; 1770 break; 1771 case DW_FORM_sec_offset: 1772 value = unit->IsDwarf64() 1773 ? dataReader.Read<uint64>(0) 1774 : (uint64)dataReader.Read<uint32>(0); 1775 break; 1776 case DW_FORM_strx1: 1777 case DW_FORM_strx2: 1778 case DW_FORM_strx3: 1779 case DW_FORM_strx4: 1780 { 1781 size_t numBytes = attributeForm - DW_FORM_strx1 + 1; 1782 uint64 index = dataReader.ReadUInt(numBytes, 0); 1783 const char* strValue; 1784 status_t res = _ReadStringIndirect(unit, index, strValue); 1785 if (res != B_OK) 1786 return res; 1787 attributeValue.SetToString(strValue); 1788 break; 1789 } 1790 case DW_FORM_addrx1: 1791 case DW_FORM_addrx2: 1792 case DW_FORM_addrx3: 1793 case DW_FORM_addrx4: 1794 { 1795 size_t numBytes = attributeForm - DW_FORM_addrx1 + 1; 1796 uint64 index = dataReader.ReadUInt(numBytes, 0); 1797 status_t res = _ReadAddressIndirect(unit, index, value); 1798 if (res != B_OK) 1799 return res; 1800 break; 1801 } 1802 case DW_FORM_indirect: 1803 default: 1804 WARNING("Unsupported attribute form: %" B_PRIu32 "\n", 1805 attributeForm); 1806 return B_BAD_DATA; 1807 } 1808 1809 // get the attribute class -- skip the attribute, if we can't handle 1810 // it 1811 uint8 attributeClass = get_attribute_class(attributeName, 1812 attributeForm); 1813 1814 if (attributeClass == ATTRIBUTE_CLASS_UNKNOWN) { 1815 TRACE_DIE("skipping attribute with unrecognized class: %s (%#" 1816 B_PRIx32 ") %s (%#" B_PRIx32 ")\n", 1817 get_attribute_name_name(attributeName), attributeName, 1818 get_attribute_form_name(attributeForm), attributeForm); 1819 continue; 1820 } 1821 1822 // set the attribute value according to the attribute's class 1823 switch (attributeClass) { 1824 case ATTRIBUTE_CLASS_ADDRESS: 1825 attributeValue.SetToAddress(value); 1826 break; 1827 case ATTRIBUTE_CLASS_ADDRPTR: 1828 attributeValue.SetToAddrPtr(value); 1829 break; 1830 case ATTRIBUTE_CLASS_BLOCK: 1831 attributeValue.SetToBlock(dataReader.Data(), blockLength); 1832 dataReader.Skip(blockLength); 1833 break; 1834 case ATTRIBUTE_CLASS_CONSTANT: 1835 attributeValue.SetToConstant(value, isSigned); 1836 break; 1837 case ATTRIBUTE_CLASS_LINEPTR: 1838 attributeValue.SetToLinePointer(value); 1839 break; 1840 case ATTRIBUTE_CLASS_LOCLIST: 1841 attributeValue.SetToLocationList(value); 1842 break; 1843 case ATTRIBUTE_CLASS_LOCLISTPTR: 1844 attributeValue.SetToLocationListPointer(value); 1845 break; 1846 case ATTRIBUTE_CLASS_MACPTR: 1847 attributeValue.SetToMacroPointer(value); 1848 break; 1849 case ATTRIBUTE_CLASS_RANGELIST: 1850 attributeValue.SetToRangeList(value); 1851 break; 1852 case ATTRIBUTE_CLASS_RANGELISTPTR: 1853 attributeValue.SetToRangeListPointer(value); 1854 break; 1855 case ATTRIBUTE_CLASS_REFERENCE: 1856 if (entry != NULL) { 1857 attributeValue.SetToReference(_ResolveReference( 1858 unit, value, refType)); 1859 if (attributeValue.reference == NULL) { 1860 // gcc 2 apparently somtimes produces DW_AT_sibling 1861 // attributes pointing to the end of the sibling list. 1862 // Just ignore those. 1863 if (attributeName == DW_AT_sibling) 1864 continue; 1865 1866 WARNING("Failed to resolve reference on entry %p: " 1867 "(%#" B_PRIx64 ") %s (%#" B_PRIx32 ") %s " 1868 "(%#" B_PRIx32 "): value: %#" B_PRIx64 "\n", 1869 entry, 1870 valueOffset, 1871 get_attribute_name_name(attributeName), 1872 attributeName, 1873 get_attribute_form_name(attributeForm), 1874 attributeForm, value); 1875 return B_ENTRY_NOT_FOUND; 1876 } 1877 } 1878 break; 1879 case ATTRIBUTE_CLASS_FLAG: 1880 case ATTRIBUTE_CLASS_STRING: 1881 // already set 1882 break; 1883 case ATTRIBUTE_CLASS_STROFFSETSPTR: 1884 attributeValue.SetToStrOffsetsPtr(value); 1885 break; 1886 } 1887 1888 if (dataReader.HasOverflow()) { 1889 WARNING("Unexpected end of .debug_info section.\n"); 1890 return B_BAD_DATA; 1891 } 1892 1893 TRACE_DIE_ONLY( 1894 char buffer[1024]; 1895 TRACE_DIE(" attr (%#" B_PRIx64 ") %s %s (%d): %s\n", 1896 valueOffset, 1897 get_attribute_name_name(attributeName), 1898 get_attribute_form_name(attributeForm), attributeClass, 1899 attributeValue.ToString(buffer, sizeof(buffer))); 1900 ) 1901 1902 // add the attribute 1903 if (entry != NULL) { 1904 DebugInfoEntrySetter attributeSetter 1905 = get_attribute_name_setter(attributeName); 1906 if (attributeSetter != 0) { 1907 status_t error = (entry->*attributeSetter)(attributeName, 1908 attributeValue); 1909 1910 if (error == ATTRIBUTE_NOT_HANDLED) { 1911 error = B_OK; 1912 TRACE_DIE(" -> unhandled\n"); 1913 } 1914 1915 if (error != B_OK) { 1916 WARNING("Failed to set attribute: name: %s, form: %s: %s\n", 1917 get_attribute_name_name(attributeName), 1918 get_attribute_form_name(attributeForm), 1919 strerror(error)); 1920 } 1921 } else 1922 TRACE_DIE(" -> no attribute setter!\n"); 1923 } 1924 } 1925 1926 return B_OK; 1927 } 1928 1929 1930 status_t 1931 DwarfFile::_ParseLineInfoFormatString(CompilationUnit* unit, DataReader &dataReader, 1932 uint64 format, const char*& value) 1933 { 1934 switch (format) { 1935 case DW_FORM_string: 1936 value = dataReader.ReadString(); 1937 break; 1938 case DW_FORM_line_strp: 1939 { 1940 if (fDebugLineStrSection == NULL) { 1941 WARNING("Invalid DW_FORM_line_strp: no line_str section!\n"); 1942 return B_BAD_DATA; 1943 } 1944 1945 target_addr_t offset = unit->IsDwarf64() 1946 ? dataReader.Read<uint64>(0) 1947 : dataReader.Read<uint32>(0); 1948 if (offset > fDebugLineStrSection->Size()) { 1949 WARNING("Invalid DW_FORM_line_strp offset: %" B_PRIu64 "\n", 1950 offset); 1951 return B_BAD_DATA; 1952 } 1953 1954 value = (const char*)fDebugLineStrSection->Data() + offset; 1955 break; 1956 } 1957 case DW_FORM_strp: 1958 { 1959 if (fDebugStringSection == NULL) { 1960 WARNING("Invalid DW_FORM_strp: no string section!\n"); 1961 return B_BAD_DATA; 1962 } 1963 1964 target_addr_t offset = unit->IsDwarf64() 1965 ? dataReader.Read<uint64>(0) 1966 : dataReader.Read<uint32>(0); 1967 if (offset > fDebugStringSection->Size()) { 1968 WARNING("Invalid DW_FORM_strp offset: %" B_PRIu64 "\n", 1969 offset); 1970 return B_BAD_DATA; 1971 } 1972 1973 value = (const char*)fDebugStringSection->Data() + offset; 1974 break; 1975 } 1976 case DW_FORM_strp_sup: 1977 return B_UNSUPPORTED; 1978 break; 1979 default: 1980 WARNING("DwarfFile::_ParseLineInfoFormatString(\"%s\"): unsupported " 1981 "field type %" PRIu64 "\n", fName, format); 1982 return B_BAD_DATA; 1983 } 1984 1985 return B_OK; 1986 } 1987 1988 1989 status_t 1990 DwarfFile::_ParseLineInfoFormatUint(CompilationUnit* unit, DataReader &dataReader, 1991 uint64 format, uint64 &value) 1992 { 1993 switch (format) 1994 { 1995 case DW_FORM_data1: 1996 value = dataReader.Read<uint8>(0); 1997 break; 1998 case DW_FORM_data2: 1999 value = dataReader.Read<uint16>(0); 2000 break; 2001 case DW_FORM_data4: 2002 value = dataReader.Read<uint32>(0); 2003 break; 2004 case DW_FORM_data8: 2005 value = dataReader.Read<uint64>(0); 2006 break; 2007 case DW_FORM_udata: 2008 value = dataReader.ReadUnsignedLEB128(0); 2009 break; 2010 default: 2011 WARNING("DwarfFile::_ParseLineInfoFormatUint(\"%s\"): unsupported " 2012 "field type %" PRIu64 "\n", fName, format); 2013 return B_BAD_DATA; 2014 } 2015 2016 return B_OK; 2017 } 2018 2019 2020 status_t 2021 DwarfFile::_ParseLineInfo(CompilationUnit* unit) 2022 { 2023 off_t offset = unit->UnitEntry()->StatementListOffset(); 2024 2025 TRACE_LINES("DwarfFile::_ParseLineInfo(%p), offset: %" B_PRIdOFF "\n", unit, 2026 offset); 2027 2028 DataReader dataReader((uint8*)fDebugLineSection->Data() + offset, 2029 fDebugLineSection->Size() - offset, unit->AddressSize(), unit->IsBigEndian()); 2030 2031 // unit length 2032 bool dwarf64; 2033 uint64 unitLength = dataReader.ReadInitialLength(dwarf64); 2034 if (unitLength > (uint64)dataReader.BytesRemaining()) 2035 return B_BAD_DATA; 2036 off_t unitOffset = dataReader.Offset(); 2037 2038 // version (uhalf) 2039 uint16 version = dataReader.Read<uint16>(0); 2040 2041 if (version < 2 || version > 5) { 2042 WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported " 2043 "version %d\n", fName, version); 2044 return B_UNSUPPORTED; 2045 } 2046 2047 uint8 addressSize = unit->AddressSize(); 2048 uint8 segmentSelectorSize = 0; 2049 2050 if (version >= 5) { 2051 addressSize = dataReader.Read<uint8>(0); 2052 if (addressSize != 4 && addressSize != 8) { 2053 WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported " 2054 "addressSize %d\n", fName, addressSize); 2055 return B_BAD_DATA; 2056 } 2057 2058 segmentSelectorSize = dataReader.Read<uint8>(0); 2059 if (segmentSelectorSize != 0) { 2060 WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported " 2061 "segmentSelectorSize %d\n", fName, segmentSelectorSize); 2062 return B_BAD_DATA; 2063 } 2064 } 2065 2066 // header_length (4/8) 2067 uint64 headerLength = dwarf64 2068 ? dataReader.Read<uint64>(0) : (uint64)dataReader.Read<uint32>(0); 2069 off_t headerOffset = dataReader.Offset(); 2070 2071 if ((uint64)dataReader.BytesRemaining() < headerLength) 2072 return B_BAD_DATA; 2073 2074 // minimum instruction length 2075 uint8 minInstructionLength = dataReader.Read<uint8>(0); 2076 2077 uint8 maxOpsPerInstruction; 2078 if (version >= 4) 2079 maxOpsPerInstruction = dataReader.Read<uint8>(0); 2080 else 2081 maxOpsPerInstruction = 1; 2082 2083 if (maxOpsPerInstruction != 1) { 2084 WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported " 2085 "maxOpsPerInstruction %u\n", fName, maxOpsPerInstruction); 2086 return B_UNSUPPORTED; 2087 } 2088 2089 // default is statement 2090 bool defaultIsStatement = dataReader.Read<uint8>(0) != 0; 2091 2092 // line_base (sbyte) 2093 int8 lineBase = (int8)dataReader.Read<uint8>(0); 2094 2095 // line_range (ubyte) 2096 uint8 lineRange = dataReader.Read<uint8>(0); 2097 2098 // opcode_base (ubyte) 2099 uint8 opcodeBase = dataReader.Read<uint8>(0); 2100 2101 // standard_opcode_lengths (ubyte[]) 2102 const uint8* standardOpcodeLengths = (const uint8*)dataReader.Data(); 2103 dataReader.Skip(opcodeBase - 1); 2104 2105 if (dataReader.HasOverflow()) 2106 return B_BAD_DATA; 2107 2108 TRACE_LINES(" unitLength: %" B_PRIu64 "\n", unitLength); 2109 TRACE_LINES(" version: %u\n", version); 2110 if (version >= 5) { 2111 TRACE_LINES(" addressSize: %u\n", addressSize); 2112 TRACE_LINES(" segmentSelectorSize: %u\n", segmentSelectorSize); 2113 } 2114 TRACE_LINES(" headerLength: %" B_PRIu64 "\n", headerLength); 2115 TRACE_LINES(" minInstructionLength: %u\n", minInstructionLength); 2116 if (version >= 4) 2117 TRACE_LINES(" maxOpsPerInstruction: %u\n", maxOpsPerInstruction); 2118 TRACE_LINES(" defaultIsStatement: %d\n", defaultIsStatement); 2119 TRACE_LINES(" lineBase: %d\n", lineBase); 2120 TRACE_LINES(" lineRange: %u\n", lineRange); 2121 TRACE_LINES(" opcodeBase: %u\n", opcodeBase); 2122 2123 if (version >= 5) { 2124 uint8 dirEntryFormatCount = dataReader.Read<uint8>(0); 2125 TRACE_LINES(" dirEntryFormatCount: %u\n", dirEntryFormatCount); 2126 2127 off_t dirEntryFormatOffset = dataReader.Offset(); 2128 for (unsigned int i = 0; i < dirEntryFormatCount; i++) { 2129 TRACE_LINES_ONLY(uint64 content =) 2130 dataReader.ReadUnsignedLEB128(0); 2131 TRACE_LINES_ONLY(uint64 format =) 2132 dataReader.ReadUnsignedLEB128(0); 2133 2134 TRACE_LINES(" content: %" B_PRIu64 "\n", content); 2135 TRACE_LINES(" format: %" B_PRIu64 "\n", format); 2136 } 2137 off_t dirEntryFormatLength = dataReader.Offset() - dirEntryFormatOffset; 2138 DataReader dirEntryFormatReader = dataReader.RestrictedReader(-dirEntryFormatLength, 2139 dirEntryFormatLength); 2140 2141 uint8 dirCount = dataReader.Read<uint8>(0); 2142 TRACE_LINES(" dirCount: %u\n", dirCount); 2143 2144 for (unsigned int i = 0; i < dirCount; i++) { 2145 dirEntryFormatReader.SeekAbsolute(0); 2146 for (unsigned int j = 0; j < dirEntryFormatCount; j++) { 2147 uint64 content = dirEntryFormatReader.ReadUnsignedLEB128(0); 2148 uint64 format = dirEntryFormatReader.ReadUnsignedLEB128(0); 2149 if (content != DW_LNCT_path) { 2150 WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported " 2151 "field in dirs %" PRIu64 "\n", fName, content); 2152 return B_UNSUPPORTED; 2153 } 2154 2155 const char* directory; 2156 status_t res = _ParseLineInfoFormatString(unit, dataReader, format, directory); 2157 if (res != B_OK) 2158 return res; 2159 TRACE_LINES(" \"%s\"\n", directory); 2160 2161 if (!unit->AddDirectory(directory)) 2162 return B_NO_MEMORY; 2163 2164 } 2165 } 2166 2167 uint8 fileNameEntryFormatCount = dataReader.Read<uint8>(0); 2168 TRACE_LINES(" fileNameFormatCount: %u\n", fileNameEntryFormatCount); 2169 2170 off_t fileNameEntryFormatOffset = dataReader.Offset(); 2171 for (unsigned int i = 0; i < fileNameEntryFormatCount; i++) { 2172 TRACE_LINES_ONLY(uint64 content =) 2173 dataReader.ReadUnsignedLEB128(0); 2174 TRACE_LINES_ONLY(uint64 format =) 2175 dataReader.ReadUnsignedLEB128(0); 2176 2177 TRACE_LINES(" content: %" B_PRIu64 "\n", content); 2178 TRACE_LINES(" format: %" B_PRIu64 "\n", format); 2179 } 2180 off_t fileNameEntryFormatLength = dataReader.Offset() - fileNameEntryFormatOffset; 2181 DataReader fileNameEntryFormatReader = dataReader.RestrictedReader(-fileNameEntryFormatLength, 2182 fileNameEntryFormatLength); 2183 2184 uint8 fileNameCount = dataReader.Read<uint8>(0); 2185 TRACE_LINES(" fileNameCount: %u\n", dirCount); 2186 2187 for (unsigned int i = 0; i < fileNameCount; i++) { 2188 const char* fileName = NULL; 2189 uint64 dirIndex = 0xffffffffffffffffull; 2190 uint64 modificationTime = 0; 2191 uint64 fileLength = 0; 2192 2193 fileNameEntryFormatReader.SeekAbsolute(0); 2194 for (unsigned int j = 0; j < fileNameEntryFormatCount; j++) { 2195 2196 uint64 content = fileNameEntryFormatReader.ReadUnsignedLEB128(0); 2197 uint64 format = fileNameEntryFormatReader.ReadUnsignedLEB128(0); 2198 status_t res; 2199 switch (content) { 2200 case DW_LNCT_path: 2201 res = _ParseLineInfoFormatString(unit, dataReader, 2202 format, fileName); 2203 if (res != B_OK) 2204 return res; 2205 break; 2206 case DW_LNCT_directory_index: 2207 res = _ParseLineInfoFormatUint(unit, dataReader, 2208 format, dirIndex); 2209 if (res != B_OK) 2210 return res; 2211 break; 2212 case DW_LNCT_timestamp: 2213 res = _ParseLineInfoFormatUint(unit, dataReader, 2214 format, modificationTime); 2215 if (res != B_OK) 2216 return res; 2217 break; 2218 case DW_LNCT_size: 2219 res = _ParseLineInfoFormatUint(unit, dataReader, 2220 format, fileLength); 2221 if (res != B_OK) 2222 return res; 2223 break; 2224 case DW_LNCT_MD5: 2225 if (format != DW_FORM_data16) 2226 return B_BAD_DATA; 2227 2228 dataReader.Skip(16); 2229 break; 2230 default: 2231 WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported " 2232 "field in files %" PRIu64 "\n", 2233 fName, content); 2234 return B_UNSUPPORTED; 2235 } 2236 } 2237 2238 if ((fileName != NULL) && (dirIndex != 0xffffffffffffffffull)) { 2239 TRACE_LINES(" \"%s\", dir index: %" B_PRIu64 "\n", 2240 fileName, dirIndex); 2241 2242 if (!unit->AddFile(fileName, dirIndex)) 2243 return B_NO_MEMORY; 2244 } 2245 } 2246 } else { 2247 // include directories 2248 TRACE_LINES(" include directories:\n"); 2249 while (const char* directory = dataReader.ReadString()) { 2250 if (*directory == '\0') 2251 break; 2252 TRACE_LINES(" \"%s\"\n", directory); 2253 2254 if (!unit->AddDirectory(directory)) 2255 return B_NO_MEMORY; 2256 } 2257 2258 // file names 2259 TRACE_LINES(" files:\n"); 2260 while (const char* file = dataReader.ReadString()) { 2261 if (*file == '\0') 2262 break; 2263 uint64 dirIndex = dataReader.ReadUnsignedLEB128(0); 2264 TRACE_LINES_ONLY(uint64 modificationTime =) 2265 dataReader.ReadUnsignedLEB128(0); 2266 TRACE_LINES_ONLY(uint64 fileLength =) 2267 dataReader.ReadUnsignedLEB128(0); 2268 2269 if (dataReader.HasOverflow()) 2270 return B_BAD_DATA; 2271 2272 TRACE_LINES(" \"%s\", dir index: %" B_PRIu64 ", mtime: %" B_PRIu64 2273 ", length: %" B_PRIu64 "\n", file, dirIndex, modificationTime, 2274 fileLength); 2275 2276 if (!unit->AddFile(file, dirIndex)) 2277 return B_NO_MEMORY; 2278 } 2279 } 2280 2281 off_t readerOffset = dataReader.Offset(); 2282 if ((uint64)readerOffset > readerOffset + headerLength) 2283 return B_BAD_DATA; 2284 off_t offsetToProgram = headerOffset + headerLength - readerOffset; 2285 2286 const uint8* program = (uint8*)dataReader.Data() + offsetToProgram; 2287 size_t programSize = unitLength - (readerOffset - unitOffset); 2288 2289 return unit->GetLineNumberProgram().Init(program, programSize, 2290 minInstructionLength, defaultIsStatement, lineBase, lineRange, 2291 opcodeBase, standardOpcodeLengths); 2292 } 2293 2294 2295 status_t 2296 DwarfFile::_UnwindCallFrame(CompilationUnit* unit, uint8 addressSize, bool isBigEndian, 2297 DIESubprogram* subprogramEntry, target_addr_t location, 2298 const FDELookupInfo* info, const DwarfTargetInterface* inputInterface, 2299 DwarfTargetInterface* outputInterface, target_addr_t& _framePointer) 2300 { 2301 ElfSection* currentFrameSection = (info->ehFrame) 2302 ? fEHFrameSection : fDebugFrameSection; 2303 2304 TRACE_CFI("DwarfFile::_UnwindCallFrame(%#" B_PRIx64 ")\n", location); 2305 2306 DataReader dataReader((uint8*)currentFrameSection->Data(), 2307 currentFrameSection->Size(), 2308 unit != NULL ? unit->AddressSize() : addressSize, 2309 unit != NULL ? unit->IsBigEndian() : isBigEndian); 2310 dataReader.SeekAbsolute(info->fdeOffset); 2311 2312 bool dwarf64; 2313 uint64 length = dataReader.ReadInitialLength(dwarf64); 2314 uint64 lengthOffset = dataReader.Offset(); 2315 2316 CfaContext context; 2317 CIEAugmentation cieAugmentation; 2318 // when using .eh_frame format, we need to parse the CIE's 2319 // augmentation up front in order to know how the FDE's addresses 2320 // will be represented 2321 DataReader cieReader; 2322 off_t cieRemaining; 2323 status_t error = _ParseCIEHeader(currentFrameSection, 2324 info->ehFrame, unit, addressSize, isBigEndian, context, info->cieOffset, 2325 cieAugmentation, cieReader, cieRemaining); 2326 if (error != B_OK) 2327 return error; 2328 if (cieReader.HasOverflow()) 2329 return B_BAD_DATA; 2330 if (cieRemaining < 0) 2331 return B_BAD_DATA; 2332 2333 // skip CIE ID, initial offset and range, since we already know those 2334 // from FDELookupInfo. 2335 dwarf64 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0); 2336 cieAugmentation.ReadEncodedAddress(dataReader, fElfFile, 2337 currentFrameSection); 2338 cieAugmentation.ReadEncodedAddress(dataReader, fElfFile, 2339 currentFrameSection, true); 2340 2341 TRACE_CFI(" found fde: length: %" B_PRIu64 " (%" B_PRIdOFF 2342 "), CIE offset: %#" B_PRIx64 ", location: %#" B_PRIx64 ", " 2343 "range: %#" B_PRIx64 "\n", length, dataReader.BytesRemaining(), 2344 info->cieOffset, info->start, info->end - info->start); 2345 2346 context.SetLocation(location, info->start); 2347 uint32 registerCount = outputInterface->CountRegisters(); 2348 error = context.Init(registerCount); 2349 if (error != B_OK) 2350 return error; 2351 2352 error = outputInterface->InitRegisterRules(context); 2353 if (error != B_OK) 2354 return error; 2355 2356 // process the CIE's frame info instructions 2357 cieReader = cieReader.RestrictedReader(cieRemaining); 2358 error = _ParseFrameInfoInstructions(unit, context, 2359 cieReader, cieAugmentation); 2360 if (error != B_OK) 2361 return error; 2362 2363 // read the FDE augmentation data (if any) 2364 FDEAugmentation fdeAugmentation; 2365 error = cieAugmentation.ReadFDEData(dataReader, 2366 fdeAugmentation); 2367 if (error != B_OK) { 2368 TRACE_CFI(" failed to read FDE augmentation data!\n"); 2369 return error; 2370 } 2371 2372 error = context.SaveInitialRuleSet(); 2373 if (error != B_OK) 2374 return error; 2375 2376 uint64 remaining = lengthOffset + length - dataReader.Offset(); 2377 if (remaining < 0) 2378 return B_BAD_DATA; 2379 2380 DataReader restrictedReader = 2381 dataReader.RestrictedReader(remaining); 2382 error = _ParseFrameInfoInstructions(unit, context, 2383 restrictedReader, cieAugmentation); 2384 if (error != B_OK) 2385 return error; 2386 2387 TRACE_CFI(" found row!\n"); 2388 2389 // apply the rules of the final row 2390 // get the frameAddress first 2391 target_addr_t frameAddress; 2392 CfaCfaRule* cfaCfaRule = context.GetCfaCfaRule(); 2393 switch (cfaCfaRule->Type()) { 2394 case CFA_CFA_RULE_REGISTER_OFFSET: 2395 { 2396 BVariant value; 2397 if (!inputInterface->GetRegisterValue( 2398 cfaCfaRule->Register(), value) 2399 || !value.IsNumber()) { 2400 return B_UNSUPPORTED; 2401 } 2402 frameAddress = value.ToUInt64() + cfaCfaRule->Offset(); 2403 break; 2404 } 2405 case CFA_CFA_RULE_EXPRESSION: 2406 { 2407 error = EvaluateExpression(unit, addressSize, isBigEndian, 2408 subprogramEntry, 2409 cfaCfaRule->Expression().block, 2410 cfaCfaRule->Expression().size, 2411 inputInterface, location, 0, 0, false, 2412 frameAddress); 2413 if (error != B_OK) 2414 return error; 2415 break; 2416 } 2417 case CFA_CFA_RULE_UNDEFINED: 2418 default: 2419 return B_BAD_VALUE; 2420 } 2421 2422 TRACE_CFI(" frame address: %#" B_PRIx64 "\n", frameAddress); 2423 2424 // apply the register rules 2425 for (uint32 i = 0; i < registerCount; i++) { 2426 TRACE_CFI(" reg %" B_PRIu32 "\n", i); 2427 2428 uint32 valueType = outputInterface->RegisterValueType(i); 2429 if (valueType == 0) 2430 continue; 2431 2432 CfaRule* rule = context.RegisterRule(i); 2433 if (rule == NULL) 2434 continue; 2435 2436 // apply the rule 2437 switch (rule->Type()) { 2438 case CFA_RULE_SAME_VALUE: 2439 { 2440 TRACE_CFI(" -> CFA_RULE_SAME_VALUE\n"); 2441 2442 BVariant value; 2443 if (inputInterface->GetRegisterValue(i, value)) 2444 outputInterface->SetRegisterValue(i, value); 2445 break; 2446 } 2447 case CFA_RULE_LOCATION_OFFSET: 2448 { 2449 TRACE_CFI(" -> CFA_RULE_LOCATION_OFFSET: %" 2450 B_PRId64 "\n", rule->Offset()); 2451 2452 BVariant value; 2453 if (inputInterface->ReadValueFromMemory( 2454 frameAddress + rule->Offset(), valueType, 2455 value)) { 2456 outputInterface->SetRegisterValue(i, value); 2457 } 2458 break; 2459 } 2460 case CFA_RULE_VALUE_OFFSET: 2461 TRACE_CFI(" -> CFA_RULE_VALUE_OFFSET\n"); 2462 2463 outputInterface->SetRegisterValue(i, 2464 frameAddress + rule->Offset()); 2465 break; 2466 case CFA_RULE_REGISTER: 2467 { 2468 TRACE_CFI(" -> CFA_RULE_REGISTER\n"); 2469 2470 BVariant value; 2471 if (inputInterface->GetRegisterValue( 2472 rule->Register(), value)) { 2473 outputInterface->SetRegisterValue(i, value); 2474 } 2475 break; 2476 } 2477 case CFA_RULE_LOCATION_EXPRESSION: 2478 { 2479 TRACE_CFI(" -> CFA_RULE_LOCATION_EXPRESSION\n"); 2480 2481 target_addr_t address; 2482 error = EvaluateExpression(unit, addressSize, isBigEndian, 2483 subprogramEntry, 2484 rule->Expression().block, 2485 rule->Expression().size, 2486 inputInterface, location, frameAddress, 2487 frameAddress, true, address); 2488 BVariant value; 2489 if (error == B_OK 2490 && inputInterface->ReadValueFromMemory(address, 2491 valueType, value)) { 2492 outputInterface->SetRegisterValue(i, value); 2493 } 2494 break; 2495 } 2496 case CFA_RULE_VALUE_EXPRESSION: 2497 { 2498 TRACE_CFI(" -> CFA_RULE_VALUE_EXPRESSION\n"); 2499 2500 target_addr_t value; 2501 error = EvaluateExpression(unit, addressSize, isBigEndian, 2502 subprogramEntry, 2503 rule->Expression().block, 2504 rule->Expression().size, 2505 inputInterface, location, frameAddress, 2506 frameAddress, true, value); 2507 if (error == B_OK) 2508 outputInterface->SetRegisterValue(i, value); 2509 break; 2510 } 2511 case CFA_RULE_UNDEFINED: 2512 TRACE_CFI(" -> CFA_RULE_UNDEFINED\n"); 2513 default: 2514 break; 2515 } 2516 } 2517 2518 _framePointer = frameAddress; 2519 2520 return B_OK; 2521 } 2522 2523 2524 status_t 2525 DwarfFile::_ParseCIEHeader(ElfSection* debugFrameSection, 2526 bool usingEHFrameSection, CompilationUnit* unit, uint8 addressSize, bool isBigEndian, 2527 CfaContext& context, off_t cieOffset, CIEAugmentation& cieAugmentation, 2528 DataReader& dataReader, off_t& _cieRemaining) 2529 { 2530 if (cieOffset < 0 || (uint64)cieOffset >= debugFrameSection->Size()) 2531 return B_BAD_DATA; 2532 2533 dataReader.SetTo((uint8*)debugFrameSection->Data() + cieOffset, 2534 debugFrameSection->Size() - cieOffset, 2535 unit != NULL ? unit->AddressSize() : addressSize, 2536 unit != NULL ? unit->IsBigEndian() : isBigEndian); 2537 2538 // length 2539 bool dwarf64; 2540 uint64 length = dataReader.ReadInitialLength(dwarf64); 2541 if (length > (uint64)dataReader.BytesRemaining()) 2542 return B_BAD_DATA; 2543 2544 off_t lengthOffset = dataReader.Offset(); 2545 2546 // CIE ID/CIE pointer 2547 uint64 cieID = dwarf64 2548 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0); 2549 if (usingEHFrameSection) { 2550 if (cieID != 0) 2551 return B_BAD_DATA; 2552 } else { 2553 if (dwarf64 ? cieID != 0xffffffffffffffffULL : cieID != 0xffffffff) 2554 return B_BAD_DATA; 2555 } 2556 2557 uint8 version = dataReader.Read<uint8>(0); 2558 if (version != 1) { 2559 TRACE_CFI(" cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", " 2560 "version: %u -- unsupported\n", length, (uint64)cieOffset, version); 2561 return B_UNSUPPORTED; 2562 } 2563 2564 // read the augmentation string 2565 cieAugmentation.Init(dataReader); 2566 2567 // in the cause of augmentation string "eh", 2568 // the exception table pointer is located immediately before the 2569 // code/data alignment values. We have no use for it so simply skip. 2570 if (strcmp(cieAugmentation.String(), "eh") == 0) 2571 dataReader.Skip(dwarf64 ? sizeof(uint64) : sizeof(uint32)); 2572 2573 context.SetCodeAlignment(dataReader.ReadUnsignedLEB128(0)); 2574 context.SetDataAlignment(dataReader.ReadSignedLEB128(0)); 2575 context.SetReturnAddressRegister(dataReader.ReadUnsignedLEB128(0)); 2576 2577 TRACE_CFI(" cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", version: " 2578 "%u, augmentation: \"%s\", aligment: code: %" B_PRIu32 ", data: %" 2579 B_PRId32 ", return address reg: %" B_PRIu32 "\n", length, 2580 (uint64)cieOffset, version, cieAugmentation.String(), 2581 context.CodeAlignment(), context.DataAlignment(), 2582 context.ReturnAddressRegister()); 2583 2584 status_t error = cieAugmentation.Read(dataReader); 2585 if (error != B_OK) { 2586 TRACE_CFI(" cie: length: %" B_PRIu64 ", version: %u, augmentation: " 2587 "\"%s\" -- unsupported\n", length, version, 2588 cieAugmentation.String()); 2589 return error; 2590 } 2591 2592 if (dataReader.HasOverflow()) 2593 return B_BAD_DATA; 2594 2595 _cieRemaining = length -(dataReader.Offset() - lengthOffset); 2596 if (_cieRemaining < 0) 2597 return B_BAD_DATA; 2598 2599 return B_OK; 2600 } 2601 2602 2603 status_t 2604 DwarfFile::_ParseFrameInfoInstructions(CompilationUnit* unit, 2605 CfaContext& context, DataReader& dataReader, CIEAugmentation& augmentation) 2606 { 2607 while (dataReader.BytesRemaining() > 0) { 2608 TRACE_CFI(" [%2" B_PRId64 "]", dataReader.BytesRemaining()); 2609 2610 uint8 opcode = dataReader.Read<uint8>(0); 2611 if ((opcode >> 6) != 0) { 2612 uint32 operand = opcode & 0x3f; 2613 2614 switch (opcode >> 6) { 2615 case DW_CFA_advance_loc: 2616 { 2617 TRACE_CFI(" DW_CFA_advance_loc: %#" B_PRIx32 "\n", 2618 operand); 2619 2620 target_addr_t location = context.Location() 2621 + operand * context.CodeAlignment(); 2622 if (location > context.TargetLocation()) 2623 return B_OK; 2624 context.SetLocation(location); 2625 break; 2626 } 2627 case DW_CFA_offset: 2628 { 2629 uint64 offset = dataReader.ReadUnsignedLEB128(0); 2630 TRACE_CFI(" DW_CFA_offset: reg: %" B_PRIu32 ", offset: " 2631 "%" B_PRIu64 "\n", operand, offset); 2632 2633 if (CfaRule* rule = context.RegisterRule(operand)) { 2634 rule->SetToLocationOffset( 2635 offset * context.DataAlignment()); 2636 } 2637 break; 2638 } 2639 case DW_CFA_restore: 2640 { 2641 TRACE_CFI(" DW_CFA_restore: %#" B_PRIx32 "\n", operand); 2642 2643 context.RestoreRegisterRule(operand); 2644 break; 2645 } 2646 } 2647 } else { 2648 switch (opcode) { 2649 case DW_CFA_nop: 2650 { 2651 TRACE_CFI(" DW_CFA_nop\n"); 2652 break; 2653 } 2654 case DW_CFA_set_loc: 2655 { 2656 target_addr_t location = augmentation.ReadEncodedAddress( 2657 dataReader, fElfFile, fDebugFrameSection); 2658 2659 TRACE_CFI(" DW_CFA_set_loc: %#" B_PRIx64 "\n", location); 2660 2661 if (location < context.Location()) 2662 return B_BAD_VALUE; 2663 if (location > context.TargetLocation()) 2664 return B_OK; 2665 context.SetLocation(location); 2666 break; 2667 } 2668 case DW_CFA_advance_loc1: 2669 { 2670 uint32 delta = dataReader.Read<uint8>(0); 2671 2672 TRACE_CFI(" DW_CFA_advance_loc1: %#" B_PRIx32 "\n", 2673 delta); 2674 2675 target_addr_t location = context.Location() 2676 + delta * context.CodeAlignment(); 2677 if (location > context.TargetLocation()) 2678 return B_OK; 2679 context.SetLocation(location); 2680 break; 2681 } 2682 case DW_CFA_advance_loc2: 2683 { 2684 uint32 delta = dataReader.Read<uint16>(0); 2685 2686 TRACE_CFI(" DW_CFA_advance_loc2: %#" B_PRIx32 "\n", 2687 delta); 2688 2689 target_addr_t location = context.Location() 2690 + delta * context.CodeAlignment(); 2691 if (location > context.TargetLocation()) 2692 return B_OK; 2693 context.SetLocation(location); 2694 break; 2695 } 2696 case DW_CFA_advance_loc4: 2697 { 2698 uint32 delta = dataReader.Read<uint32>(0); 2699 2700 TRACE_CFI(" DW_CFA_advance_loc4: %#" B_PRIx32 "\n", 2701 delta); 2702 2703 target_addr_t location = context.Location() 2704 + delta * context.CodeAlignment(); 2705 if (location > context.TargetLocation()) 2706 return B_OK; 2707 context.SetLocation(location); 2708 break; 2709 } 2710 case DW_CFA_offset_extended: 2711 { 2712 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2713 uint64 offset = dataReader.ReadUnsignedLEB128(0); 2714 2715 TRACE_CFI(" DW_CFA_offset_extended: reg: %" B_PRIu32 ", " 2716 "offset: %" B_PRIu64 "\n", reg, offset); 2717 2718 if (CfaRule* rule = context.RegisterRule(reg)) { 2719 rule->SetToLocationOffset( 2720 offset * context.DataAlignment()); 2721 } 2722 break; 2723 } 2724 case DW_CFA_restore_extended: 2725 { 2726 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2727 2728 TRACE_CFI(" DW_CFA_restore_extended: %#" B_PRIx32 "\n", 2729 reg); 2730 2731 context.RestoreRegisterRule(reg); 2732 break; 2733 } 2734 case DW_CFA_undefined: 2735 { 2736 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2737 2738 TRACE_CFI(" DW_CFA_undefined: %" B_PRIu32 "\n", reg); 2739 2740 if (CfaRule* rule = context.RegisterRule(reg)) 2741 rule->SetToUndefined(); 2742 break; 2743 } 2744 case DW_CFA_same_value: 2745 { 2746 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2747 2748 TRACE_CFI(" DW_CFA_same_value: %" B_PRIu32 "\n", reg); 2749 2750 if (CfaRule* rule = context.RegisterRule(reg)) 2751 rule->SetToSameValue(); 2752 break; 2753 } 2754 case DW_CFA_register: 2755 { 2756 uint32 reg1 = dataReader.ReadUnsignedLEB128(0); 2757 uint32 reg2 = dataReader.ReadUnsignedLEB128(0); 2758 2759 TRACE_CFI(" DW_CFA_register: reg1: %" B_PRIu32 ", reg2: " 2760 "%" B_PRIu32 "\n", reg1, reg2); 2761 2762 if (CfaRule* rule = context.RegisterRule(reg1)) 2763 rule->SetToValueOffset(reg2); 2764 break; 2765 } 2766 case DW_CFA_remember_state: 2767 { 2768 TRACE_CFI(" DW_CFA_remember_state\n"); 2769 2770 status_t error = context.PushRuleSet(); 2771 if (error != B_OK) 2772 return error; 2773 break; 2774 } 2775 case DW_CFA_restore_state: 2776 { 2777 TRACE_CFI(" DW_CFA_restore_state\n"); 2778 2779 status_t error = context.PopRuleSet(); 2780 if (error != B_OK) 2781 return error; 2782 break; 2783 } 2784 case DW_CFA_def_cfa: 2785 { 2786 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2787 uint64 offset = dataReader.ReadUnsignedLEB128(0); 2788 2789 TRACE_CFI(" DW_CFA_def_cfa: reg: %" B_PRIu32 ", offset: " 2790 "%" B_PRIu64 "\n", reg, offset); 2791 2792 context.GetCfaCfaRule()->SetToRegisterOffset(reg, offset); 2793 break; 2794 } 2795 case DW_CFA_def_cfa_register: 2796 { 2797 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2798 2799 TRACE_CFI(" DW_CFA_def_cfa_register: %" B_PRIu32 "\n", 2800 reg); 2801 2802 if (context.GetCfaCfaRule()->Type() 2803 != CFA_CFA_RULE_REGISTER_OFFSET) { 2804 return B_BAD_DATA; 2805 } 2806 context.GetCfaCfaRule()->SetRegister(reg); 2807 break; 2808 } 2809 case DW_CFA_def_cfa_offset: 2810 { 2811 uint64 offset = dataReader.ReadUnsignedLEB128(0); 2812 2813 TRACE_CFI(" DW_CFA_def_cfa_offset: %" B_PRIu64 "\n", 2814 offset); 2815 2816 if (context.GetCfaCfaRule()->Type() 2817 != CFA_CFA_RULE_REGISTER_OFFSET) { 2818 return B_BAD_DATA; 2819 } 2820 context.GetCfaCfaRule()->SetOffset(offset); 2821 break; 2822 } 2823 case DW_CFA_def_cfa_expression: 2824 { 2825 uint64 blockLength = dataReader.ReadUnsignedLEB128(0); 2826 uint8* block = (uint8*)dataReader.Data(); 2827 dataReader.Skip(blockLength); 2828 2829 TRACE_CFI(" DW_CFA_def_cfa_expression: %p, %" B_PRIu64 2830 "\n", block, blockLength); 2831 2832 context.GetCfaCfaRule()->SetToExpression(block, 2833 blockLength); 2834 break; 2835 } 2836 case DW_CFA_expression: 2837 { 2838 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2839 uint64 blockLength = dataReader.ReadUnsignedLEB128(0); 2840 uint8* block = (uint8*)dataReader.Data(); 2841 dataReader.Skip(blockLength); 2842 2843 TRACE_CFI(" DW_CFA_expression: reg: %" B_PRIu32 ", " 2844 "block: %p, %" B_PRIu64 "\n", reg, block, blockLength); 2845 2846 if (CfaRule* rule = context.RegisterRule(reg)) 2847 rule->SetToLocationExpression(block, blockLength); 2848 break; 2849 } 2850 case DW_CFA_offset_extended_sf: 2851 { 2852 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2853 int64 offset = dataReader.ReadSignedLEB128(0); 2854 2855 TRACE_CFI(" DW_CFA_offset_extended: reg: %" B_PRIu32 ", " 2856 "offset: %" B_PRId64 "\n", reg, offset); 2857 2858 if (CfaRule* rule = context.RegisterRule(reg)) { 2859 rule->SetToLocationOffset( 2860 offset * (int32)context.DataAlignment()); 2861 } 2862 break; 2863 } 2864 case DW_CFA_def_cfa_sf: 2865 { 2866 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2867 int64 offset = dataReader.ReadSignedLEB128(0); 2868 2869 TRACE_CFI(" DW_CFA_def_cfa_sf: reg: %" B_PRIu32 ", " 2870 "offset: %" B_PRId64 "\n", reg, offset); 2871 2872 context.GetCfaCfaRule()->SetToRegisterOffset(reg, 2873 offset * (int32)context.DataAlignment()); 2874 break; 2875 } 2876 case DW_CFA_def_cfa_offset_sf: 2877 { 2878 int64 offset = dataReader.ReadSignedLEB128(0); 2879 2880 TRACE_CFI(" DW_CFA_def_cfa_offset: %" B_PRId64 "\n", 2881 offset); 2882 2883 if (context.GetCfaCfaRule()->Type() 2884 != CFA_CFA_RULE_REGISTER_OFFSET) { 2885 return B_BAD_DATA; 2886 } 2887 context.GetCfaCfaRule()->SetOffset( 2888 offset * (int32)context.DataAlignment()); 2889 break; 2890 } 2891 case DW_CFA_val_offset: 2892 { 2893 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2894 uint64 offset = dataReader.ReadUnsignedLEB128(0); 2895 2896 TRACE_CFI(" DW_CFA_val_offset: reg: %" B_PRIu32 ", " 2897 "offset: %" B_PRIu64 "\n", reg, offset); 2898 2899 if (CfaRule* rule = context.RegisterRule(reg)) { 2900 rule->SetToValueOffset( 2901 offset * context.DataAlignment()); 2902 } 2903 break; 2904 } 2905 case DW_CFA_val_offset_sf: 2906 { 2907 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2908 int64 offset = dataReader.ReadSignedLEB128(0); 2909 2910 TRACE_CFI(" DW_CFA_val_offset_sf: reg: %" B_PRIu32 ", " 2911 "offset: %" B_PRId64 "\n", reg, offset); 2912 2913 if (CfaRule* rule = context.RegisterRule(reg)) { 2914 rule->SetToValueOffset( 2915 offset * (int32)context.DataAlignment()); 2916 } 2917 break; 2918 } 2919 case DW_CFA_val_expression: 2920 { 2921 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2922 uint64 blockLength = dataReader.ReadUnsignedLEB128(0); 2923 uint8* block = (uint8*)dataReader.Data(); 2924 dataReader.Skip(blockLength); 2925 2926 TRACE_CFI(" DW_CFA_val_expression: reg: %" B_PRIu32 ", " 2927 "block: %p, %" B_PRIu64 "\n", reg, block, blockLength); 2928 2929 if (CfaRule* rule = context.RegisterRule(reg)) 2930 rule->SetToValueExpression(block, blockLength); 2931 break; 2932 } 2933 2934 // extensions 2935 case DW_CFA_MIPS_advance_loc8: 2936 { 2937 uint64 delta = dataReader.Read<uint64>(0); 2938 2939 TRACE_CFI(" DW_CFA_MIPS_advance_loc8: %#" B_PRIx64 "\n", 2940 delta); 2941 2942 target_addr_t location = context.Location() 2943 + delta * context.CodeAlignment(); 2944 if (location > context.TargetLocation()) 2945 return B_OK; 2946 context.SetLocation(location); 2947 break; 2948 } 2949 case DW_CFA_GNU_window_save: 2950 { 2951 // SPARC specific, no args 2952 TRACE_CFI(" DW_CFA_GNU_window_save\n"); 2953 2954 // TODO: Implement once we have SPARC support! 2955 break; 2956 } 2957 case DW_CFA_GNU_args_size: 2958 { 2959 // Updates the total size of arguments on the stack. 2960 TRACE_CFI_ONLY(uint64 size =) 2961 dataReader.ReadUnsignedLEB128(0); 2962 2963 TRACE_CFI(" DW_CFA_GNU_args_size: %" B_PRIu64 "\n", 2964 size); 2965 // TODO: Implement! 2966 break; 2967 } 2968 case DW_CFA_GNU_negative_offset_extended: 2969 { 2970 // obsolete 2971 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2972 int64 offset = dataReader.ReadSignedLEB128(0); 2973 2974 TRACE_CFI(" DW_CFA_GNU_negative_offset_extended: " 2975 "reg: %" B_PRIu32 ", offset: %" B_PRId64 "\n", reg, 2976 offset); 2977 2978 if (CfaRule* rule = context.RegisterRule(reg)) { 2979 rule->SetToLocationOffset( 2980 offset * (int32)context.DataAlignment()); 2981 } 2982 break; 2983 } 2984 2985 default: 2986 TRACE_CFI(" unknown opcode %u!\n", opcode); 2987 return B_BAD_DATA; 2988 } 2989 } 2990 } 2991 2992 return B_OK; 2993 } 2994 2995 2996 status_t 2997 DwarfFile::_ParsePublicTypesInfo(uint8 _addressSize, bool isBigEndian) 2998 { 2999 TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo()\n"); 3000 if (fDebugPublicTypesSection == NULL) { 3001 TRACE_PUBTYPES(" -> no public types section\n"); 3002 return B_ENTRY_NOT_FOUND; 3003 } 3004 3005 DataReader dataReader((uint8*)fDebugPublicTypesSection->Data(), 3006 fDebugPublicTypesSection->Size(), _addressSize, isBigEndian); 3007 3008 while (dataReader.BytesRemaining() > 0) { 3009 bool dwarf64; 3010 uint64 unitLength = dataReader.ReadInitialLength(dwarf64); 3011 3012 off_t unitLengthOffset = dataReader.Offset(); 3013 // the unitLength starts here 3014 3015 if (dataReader.HasOverflow()) 3016 return B_BAD_DATA; 3017 3018 if (unitLengthOffset + unitLength 3019 > (uint64)fDebugPublicTypesSection->Size()) { 3020 WARNING("Invalid public types set unit length.\n"); 3021 break; 3022 } 3023 3024 DataReader unitDataReader(dataReader.Data(), unitLength, _addressSize, isBigEndian); 3025 _ParsePublicTypesInfo(unitDataReader, dwarf64); 3026 3027 dataReader.SeekAbsolute(unitLengthOffset + unitLength); 3028 } 3029 3030 return B_OK; 3031 } 3032 3033 3034 status_t 3035 DwarfFile::_ParsePublicTypesInfo(DataReader& dataReader, bool dwarf64) 3036 { 3037 int version = dataReader.Read<uint16>(0); 3038 if (version != 2) { 3039 TRACE_PUBTYPES(" pubtypes version %d unsupported\n", version); 3040 return B_UNSUPPORTED; 3041 } 3042 3043 TRACE_PUBTYPES_ONLY(off_t debugInfoOffset =) dwarf64 3044 ? dataReader.Read<uint64>(0) 3045 : (uint64)dataReader.Read<uint32>(0); 3046 TRACE_PUBTYPES_ONLY(off_t debugInfoSize =) dwarf64 3047 ? dataReader.Read<uint64>(0) 3048 : (uint64)dataReader.Read<uint32>(0); 3049 3050 if (dataReader.HasOverflow()) 3051 return B_BAD_DATA; 3052 3053 TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo(): compilation unit debug " 3054 "info: (%" B_PRIdOFF ", %" B_PRIdOFF ")\n", debugInfoOffset, 3055 debugInfoSize); 3056 3057 while (dataReader.BytesRemaining() > 0) { 3058 off_t entryOffset = dwarf64 3059 ? dataReader.Read<uint64>(0) 3060 : (uint64)dataReader.Read<uint32>(0); 3061 if (entryOffset == 0) 3062 return B_OK; 3063 3064 TRACE_PUBTYPES_ONLY(const char* name =) dataReader.ReadString(); 3065 3066 TRACE_PUBTYPES(" \"%s\" -> %" B_PRIdOFF "\n", name, entryOffset); 3067 } 3068 3069 return B_OK; 3070 } 3071 3072 3073 status_t 3074 DwarfFile::_GetAbbreviationTable(off_t offset, AbbreviationTable*& _table) 3075 { 3076 // check, whether we've already loaded it 3077 for (AbbreviationTableList::Iterator it 3078 = fAbbreviationTables.GetIterator(); 3079 AbbreviationTable* table = it.Next();) { 3080 if (offset == table->Offset()) { 3081 _table = table; 3082 return B_OK; 3083 } 3084 } 3085 3086 // create a new table 3087 AbbreviationTable* table = new(std::nothrow) AbbreviationTable(offset); 3088 if (table == NULL) 3089 return B_NO_MEMORY; 3090 3091 status_t error = table->Init(fDebugAbbrevSection->Data(), 3092 fDebugAbbrevSection->Size()); 3093 if (error != B_OK) { 3094 delete table; 3095 return error; 3096 } 3097 3098 fAbbreviationTables.Add(table); 3099 _table = table; 3100 return B_OK; 3101 } 3102 3103 3104 DebugInfoEntry* 3105 DwarfFile::_ResolveReference(BaseUnit* unit, uint64 offset, 3106 uint8 refType) const 3107 { 3108 switch (refType) { 3109 case dwarf_reference_type_local: 3110 return unit->EntryForOffset(offset); 3111 break; 3112 case dwarf_reference_type_global: 3113 { 3114 CompilationUnit* unit = _GetContainingCompilationUnit(offset); 3115 if (unit == NULL) 3116 break; 3117 3118 offset -= unit->HeaderOffset(); 3119 DebugInfoEntry* entry = unit->EntryForOffset(offset); 3120 if (entry != NULL) 3121 return entry; 3122 break; 3123 } 3124 case dwarf_reference_type_signature: 3125 { 3126 TRACE_DIE("Resolving signature %#" B_PRIx64 "\n", offset); 3127 TypeUnitTableEntry* entry = fTypeUnits.Lookup(offset); 3128 if (entry != NULL && entry->unit != NULL) 3129 return entry->unit->TypeEntry(); 3130 break; 3131 } 3132 } 3133 3134 return NULL; 3135 } 3136 3137 3138 status_t 3139 DwarfFile::_GetLocationExpression(CompilationUnit* unit, 3140 const LocationDescription* location, target_addr_t instructionPointer, 3141 const void*& _expression, off_t& _length) const 3142 { 3143 if (!location->IsValid()) 3144 return B_BAD_VALUE; 3145 3146 if (location->IsExpression()) { 3147 _expression = location->expression.data; 3148 _length = location->expression.length; 3149 return B_OK; 3150 } 3151 3152 if (location->IsLocationList() && instructionPointer != 0) { 3153 return _FindLocationExpression(unit, location->listOffset, 3154 instructionPointer, _expression, _length); 3155 } 3156 3157 return B_BAD_VALUE; 3158 } 3159 3160 3161 status_t 3162 DwarfFile::_FindLocationExpression(CompilationUnit* unit, uint64 offset, 3163 target_addr_t address, const void*& _expression, off_t& _length) const 3164 { 3165 if (unit == NULL) 3166 return B_BAD_VALUE; 3167 3168 if (fDebugLocationSection == NULL) 3169 return B_ENTRY_NOT_FOUND; 3170 3171 if (offset < 0 || offset >= (uint64)fDebugLocationSection->Size()) 3172 return B_BAD_DATA; 3173 3174 target_addr_t baseAddress = unit->AddressRangeBase(); 3175 target_addr_t maxAddress = unit->MaxAddress(); 3176 3177 DataReader dataReader((uint8*)fDebugLocationSection->Data() + offset, 3178 fDebugLocationSection->Size() - offset, unit->AddressSize(), unit->IsBigEndian()); 3179 while (true) { 3180 target_addr_t start = dataReader.ReadAddress(0); 3181 target_addr_t end = dataReader.ReadAddress(0); 3182 if (dataReader.HasOverflow()) 3183 return B_BAD_DATA; 3184 3185 if (start == 0 && end == 0) 3186 return B_ENTRY_NOT_FOUND; 3187 3188 if (start == maxAddress) { 3189 baseAddress = end; 3190 continue; 3191 } 3192 3193 uint16 expressionLength = dataReader.Read<uint16>(0); 3194 const void* expression = dataReader.Data(); 3195 if (!dataReader.Skip(expressionLength)) 3196 return B_BAD_DATA; 3197 3198 if (start == end) 3199 continue; 3200 3201 start += baseAddress; 3202 end += baseAddress; 3203 3204 if (address >= start && address < end) { 3205 _expression = expression; 3206 _length = expressionLength; 3207 return B_OK; 3208 } 3209 } 3210 } 3211 3212 3213 status_t 3214 DwarfFile::_LocateDebugInfo(BString& _requiredExternalFileName, 3215 const char* locatedFilePath) 3216 { 3217 ElfFile* debugInfoFile = fElfFile; 3218 ElfSection* debugLinkSection = fElfFile->GetSection(".gnu_debuglink"); 3219 if (debugLinkSection != NULL) { 3220 AutoSectionPutter putter(fElfFile, debugLinkSection); 3221 3222 // the file specifies a debug link, look at its target instead 3223 // for debug information. 3224 // Format: null-terminated filename, as many 0 padding bytes as 3225 // needed to reach the next 32-bit address boundary, followed 3226 // by a 32-bit CRC 3227 3228 BString debugPath; 3229 if (locatedFilePath) 3230 debugPath = locatedFilePath; 3231 else { 3232 status_t result = _GetDebugInfoPath( 3233 (const char*)debugLinkSection->Data(), 3234 _requiredExternalFileName); 3235 if (result != B_OK) 3236 return result; 3237 debugPath = _requiredExternalFileName; 3238 } 3239 3240 if (fAlternateName != NULL) 3241 free(fAlternateName); 3242 3243 fAlternateName = strdup(debugPath.String()); 3244 3245 if (fAlternateName == NULL) 3246 return B_NO_MEMORY; 3247 3248 /* 3249 // TODO: validate CRC 3250 int32 debugCRC = *(int32*)((char*)debugLinkSection->Data() 3251 + debugLinkSection->Size() - sizeof(int32)); 3252 */ 3253 if (fAlternateElfFile == NULL) { 3254 fAlternateElfFile = new(std::nothrow) ElfFile; 3255 if (fAlternateElfFile == NULL) 3256 return B_NO_MEMORY; 3257 } 3258 3259 status_t result = fAlternateElfFile->Init(fAlternateName); 3260 if (result != B_OK) 3261 return result; 3262 3263 debugInfoFile = fAlternateElfFile; 3264 } 3265 3266 // get the interesting sections 3267 fDebugInfoSection = debugInfoFile->GetSection(".debug_info"); 3268 fDebugAbbrevSection = debugInfoFile->GetSection(".debug_abbrev"); 3269 if (fDebugInfoSection == NULL || fDebugAbbrevSection == NULL) { 3270 TRACE_DIE("DwarfManager::File::Load(\"%s\"): no " 3271 ".debug_info or .debug_abbrev.\n", fName); 3272 3273 // if we at least have an EH frame, use that for stack unwinding 3274 // if nothing else. 3275 fEHFrameSection = fElfFile->GetSection(".eh_frame"); 3276 if (fEHFrameSection == NULL) 3277 return B_ERROR; 3278 } 3279 3280 return B_OK; 3281 } 3282 3283 3284 status_t 3285 DwarfFile::_GetDebugInfoPath(const char* debugFileName, 3286 BString& _infoPath) const 3287 { 3288 // first, see if we have a relative match to our local directory 3289 BPath basePath; 3290 status_t result = basePath.SetTo(fName); 3291 if (result != B_OK) 3292 return result; 3293 basePath.GetParent(&basePath); 3294 if (strcmp(basePath.Leaf(), "lib") == 0 || strcmp(basePath.Leaf(), 3295 "add-ons") == 0) { 3296 _infoPath.SetToFormat("%s/../debug/%s", basePath.Path(), 3297 debugFileName); 3298 } else 3299 _infoPath.SetToFormat("%s/debug/%s", basePath.Path(), debugFileName); 3300 3301 BEntry entry(_infoPath.String()); 3302 result = entry.InitCheck(); 3303 if (result != B_OK && result != B_ENTRY_NOT_FOUND) 3304 return result; 3305 if (entry.Exists()) 3306 return B_OK; 3307 3308 // If the above search failed, check if our image is located in any 3309 // of the system installation paths, and attempt to locate the debug info 3310 // file in the corresponding well-known location 3311 BString pathSuffix; 3312 pathSuffix.SetToFormat("debug/%s", debugFileName); 3313 3314 BPathFinder finder(fName); 3315 result = finder.FindPath(B_FIND_PATH_DEVELOP_DIRECTORY, 3316 pathSuffix.String(), B_FIND_PATH_EXISTING_ONLY, basePath); 3317 if (result == B_OK) { 3318 _infoPath = basePath.Path(); 3319 return B_OK; 3320 } else { 3321 // if we failed to find a match, then it's up to the user to 3322 // locate it. As such, return the external info file name 3323 // for user interface purposes. 3324 _infoPath.SetTo(debugFileName); 3325 } 3326 3327 return B_ENTRY_NOT_FOUND; 3328 } 3329 3330 3331 TypeUnitTableEntry* 3332 DwarfFile::_GetTypeUnit(uint64 signature) const 3333 { 3334 return fTypeUnits.Lookup(signature); 3335 } 3336 3337 3338 CompilationUnit* 3339 DwarfFile::_GetContainingCompilationUnit(off_t refAddr) const 3340 { 3341 if (fCompilationUnits.IsEmpty()) 3342 return NULL; 3343 3344 // binary search 3345 int lower = 0; 3346 int upper = fCompilationUnits.CountItems() - 1; 3347 while (lower < upper) { 3348 int mid = (lower + upper + 1) / 2; 3349 if (fCompilationUnits.ItemAt(mid)->HeaderOffset() > refAddr) 3350 upper = mid - 1; 3351 else 3352 lower = mid; 3353 } 3354 3355 CompilationUnit* unit = fCompilationUnits.ItemAt(lower); 3356 return unit->ContainsAbsoluteOffset(refAddr) ? unit : NULL; 3357 } 3358 3359 3360 DwarfFile::FDELookupInfo* 3361 DwarfFile::_GetContainingFDEInfo(target_addr_t offset) const 3362 { 3363 FDELookupInfo* info = NULL; 3364 if (fDebugFrameSection != NULL) { 3365 info = _GetContainingFDEInfo(offset, fDebugFrameInfos); 3366 if (info != NULL) 3367 return info; 3368 } 3369 3370 return _GetContainingFDEInfo(offset, fEHFrameInfos); 3371 } 3372 3373 3374 DwarfFile::FDELookupInfo* 3375 DwarfFile::_GetContainingFDEInfo(target_addr_t offset, 3376 const FDEInfoList& infoList) const 3377 { 3378 // binary search 3379 int lower = 0; 3380 int upper = infoList.CountItems() - 1; 3381 if (upper < 0) 3382 return NULL; 3383 3384 while (lower < upper) { 3385 int mid = (lower + upper + 1) / 2; 3386 if (offset < infoList.ItemAt(mid)->start) 3387 upper = mid - 1; 3388 else 3389 lower = mid; 3390 } 3391 3392 FDELookupInfo* info = infoList.ItemAt(lower); 3393 return info->ContainsAddress(offset) ? info : NULL; 3394 } 3395