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, 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, 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 fDebugStringSection(NULL), 496 fDebugRangesSection(NULL), 497 fDebugLineSection(NULL), 498 fDebugFrameSection(NULL), 499 fEHFrameSection(NULL), 500 fDebugLocationSection(NULL), 501 fDebugPublicTypesSection(NULL), 502 fDebugTypesSection(NULL), 503 fCompilationUnits(20, true), 504 fTypeUnits(), 505 fDebugFrameInfos(100, true), 506 fEHFrameInfos(100, true), 507 fTypesSectionRequired(false), 508 fFinished(false), 509 fItaniumEHFrameFormat(false), 510 fFinishError(B_OK) 511 { 512 } 513 514 515 DwarfFile::~DwarfFile() 516 { 517 while (AbbreviationTable* table = fAbbreviationTables.RemoveHead()) 518 delete table; 519 520 if (fElfFile != NULL) { 521 ElfFile* debugInfoFile = fAlternateElfFile != NULL 522 ? fAlternateElfFile : fElfFile; 523 524 debugInfoFile->PutSection(fDebugInfoSection); 525 debugInfoFile->PutSection(fDebugAbbrevSection); 526 debugInfoFile->PutSection(fDebugStringSection); 527 debugInfoFile->PutSection(fDebugRangesSection); 528 debugInfoFile->PutSection(fDebugLineSection); 529 debugInfoFile->PutSection(fDebugFrameSection); 530 fElfFile->PutSection(fEHFrameSection); 531 debugInfoFile->PutSection(fDebugLocationSection); 532 debugInfoFile->PutSection(fDebugPublicTypesSection); 533 delete fElfFile; 534 delete fAlternateElfFile; 535 } 536 537 TypeUnitTableEntry* entry = fTypeUnits.Clear(true); 538 while (entry != NULL) { 539 TypeUnitTableEntry* nextEntry = entry->next; 540 delete entry; 541 entry = nextEntry; 542 } 543 544 free(fName); 545 free(fAlternateName); 546 } 547 548 549 status_t 550 DwarfFile::StartLoading(const char* fileName, BString& _requiredExternalFile) 551 { 552 fName = strdup(fileName); 553 if (fName == NULL) 554 return B_NO_MEMORY; 555 556 status_t error = fTypeUnits.Init(); 557 if (error != B_OK) 558 return error; 559 560 // load the ELF file 561 fElfFile = new(std::nothrow) ElfFile; 562 if (fElfFile == NULL) 563 return B_NO_MEMORY; 564 565 error = fElfFile->Init(fileName); 566 if (error != B_OK) 567 return error; 568 569 return _LocateDebugInfo(_requiredExternalFile); 570 } 571 572 573 status_t 574 DwarfFile::Load(uint8 addressSize, const BString& externalInfoFilePath) 575 { 576 status_t error = B_OK; 577 if (fDebugInfoSection == NULL) { 578 BString path; 579 error = _LocateDebugInfo(path, externalInfoFilePath.IsEmpty() 580 ? NULL : externalInfoFilePath.String()); 581 if (error != B_OK) 582 return error; 583 } 584 585 ElfFile* debugInfoFile = fAlternateElfFile != NULL 586 ? fAlternateElfFile : fElfFile; 587 588 // non mandatory sections 589 fDebugStringSection = debugInfoFile->GetSection(".debug_str"); 590 fDebugRangesSection = debugInfoFile->GetSection(".debug_ranges"); 591 fDebugLineSection = debugInfoFile->GetSection(".debug_line"); 592 fDebugFrameSection = debugInfoFile->GetSection(".debug_frame"); 593 594 if (fDebugFrameSection != NULL) { 595 error = _ParseFrameSection(fDebugFrameSection, addressSize, false, 596 fDebugFrameInfos); 597 if (error != B_OK) 598 return error; 599 } 600 601 // .eh_frame doesn't appear to get copied into separate debug 602 // info files properly, therefore always use it off the main 603 // executable image 604 if (fEHFrameSection == NULL) 605 fEHFrameSection = fElfFile->GetSection(".eh_frame"); 606 607 if (fEHFrameSection != NULL) { 608 error = _ParseFrameSection(fEHFrameSection, addressSize, true, 609 fEHFrameInfos); 610 if (error != B_OK) 611 return error; 612 } 613 614 fDebugLocationSection = debugInfoFile->GetSection(".debug_loc"); 615 fDebugPublicTypesSection = debugInfoFile->GetSection(".debug_pubtypes"); 616 617 if (fDebugInfoSection == NULL) { 618 fFinished = true; 619 return B_OK; 620 } 621 622 error = _ParseDebugInfoSection(); 623 if (error != B_OK) 624 return error; 625 626 if (fTypesSectionRequired) { 627 fDebugTypesSection = debugInfoFile->GetSection(".debug_types"); 628 if (fDebugTypesSection == NULL) { 629 WARNING(".debug_types section required but missing.\n"); 630 return B_BAD_DATA; 631 } 632 error = _ParseTypesSection(); 633 if (error != B_OK) 634 return error; 635 } 636 637 return B_OK; 638 } 639 640 641 status_t 642 DwarfFile::FinishLoading() 643 { 644 if (fFinished) 645 return B_OK; 646 if (fFinishError != B_OK) 647 return fFinishError; 648 649 status_t error; 650 for (TypeUnitTable::Iterator it = fTypeUnits.GetIterator(); 651 TypeUnitTableEntry* entry = it.Next();) { 652 error = _FinishUnit(entry->unit); 653 if (error != B_OK) 654 return fFinishError = error; 655 } 656 657 for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i); 658 i++) { 659 error = _FinishUnit(unit); 660 if (error != B_OK) 661 return fFinishError = error; 662 } 663 664 _ParsePublicTypesInfo(); 665 666 fFinished = true; 667 return B_OK; 668 } 669 670 671 int32 672 DwarfFile::CountCompilationUnits() const 673 { 674 return fCompilationUnits.CountItems(); 675 } 676 677 678 CompilationUnit* 679 DwarfFile::CompilationUnitAt(int32 index) const 680 { 681 return fCompilationUnits.ItemAt(index); 682 } 683 684 685 CompilationUnit* 686 DwarfFile::CompilationUnitForDIE(const DebugInfoEntry* entry) const 687 { 688 // find the root of the tree the entry lives in 689 while (entry != NULL && entry->Parent() != NULL) 690 entry = entry->Parent(); 691 692 // that should be the compilation unit entry 693 const DIECompileUnitBase* unitEntry 694 = dynamic_cast<const DIECompileUnitBase*>(entry); 695 if (unitEntry == NULL) 696 return NULL; 697 698 // find the compilation unit 699 for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i); 700 i++) { 701 if (unit->UnitEntry() == unitEntry) 702 return unit; 703 } 704 705 return NULL; 706 } 707 708 709 TargetAddressRangeList* 710 DwarfFile::ResolveRangeList(CompilationUnit* unit, uint64 offset) const 711 { 712 if (unit == NULL || fDebugRangesSection == NULL) 713 return NULL; 714 715 if (offset >= (uint64)fDebugRangesSection->Size()) 716 return NULL; 717 718 TargetAddressRangeList* ranges = new(std::nothrow) TargetAddressRangeList; 719 if (ranges == NULL) { 720 ERROR("Out of memory.\n"); 721 return NULL; 722 } 723 BReference<TargetAddressRangeList> rangesReference(ranges, true); 724 725 target_addr_t baseAddress = unit->AddressRangeBase(); 726 target_addr_t maxAddress = unit->MaxAddress(); 727 728 DataReader dataReader((uint8*)fDebugRangesSection->Data() + offset, 729 fDebugRangesSection->Size() - offset, unit->AddressSize()); 730 while (true) { 731 target_addr_t start = dataReader.ReadAddress(0); 732 target_addr_t end = dataReader.ReadAddress(0); 733 if (dataReader.HasOverflow()) 734 return NULL; 735 736 if (start == 0 && end == 0) 737 break; 738 if (start == maxAddress) { 739 baseAddress = end; 740 continue; 741 } 742 if (start == end) 743 continue; 744 745 if (!ranges->AddRange(baseAddress + start, end - start)) { 746 ERROR("Out of memory.\n"); 747 return NULL; 748 } 749 } 750 751 return rangesReference.Detach(); 752 } 753 754 755 status_t 756 DwarfFile::UnwindCallFrame(CompilationUnit* unit, uint8 addressSize, 757 DIESubprogram* subprogramEntry, target_addr_t location, 758 const DwarfTargetInterface* inputInterface, 759 DwarfTargetInterface* outputInterface, target_addr_t& _framePointer) 760 { 761 FDELookupInfo* info = _GetContainingFDEInfo(location); 762 if (info == NULL) 763 return B_ENTRY_NOT_FOUND; 764 765 return _UnwindCallFrame(unit, addressSize, subprogramEntry, location, info, 766 inputInterface, outputInterface, _framePointer); 767 } 768 769 770 status_t 771 DwarfFile::EvaluateExpression(CompilationUnit* unit, uint8 addressSize, 772 DIESubprogram* subprogramEntry, const void* expression, 773 off_t expressionLength, const DwarfTargetInterface* targetInterface, 774 target_addr_t instructionPointer, target_addr_t framePointer, 775 target_addr_t valueToPush, bool pushValue, target_addr_t& _result) 776 { 777 ExpressionEvaluationContext context(this, unit, addressSize, 778 subprogramEntry, targetInterface, instructionPointer, 0, false, 779 framePointer, 0); 780 DwarfExpressionEvaluator evaluator(&context); 781 782 if (pushValue && evaluator.Push(valueToPush) != B_OK) 783 return B_NO_MEMORY; 784 785 return evaluator.Evaluate(expression, expressionLength, _result); 786 } 787 788 789 status_t 790 DwarfFile::ResolveLocation(CompilationUnit* unit, uint8 addressSize, 791 DIESubprogram* subprogramEntry, const LocationDescription* location, 792 const DwarfTargetInterface* targetInterface, 793 target_addr_t instructionPointer, target_addr_t objectPointer, 794 bool hasObjectPointer, target_addr_t framePointer, 795 target_addr_t relocationDelta, ValueLocation& _result) 796 { 797 // get the expression 798 const void* expression; 799 off_t expressionLength; 800 status_t error = _GetLocationExpression(unit, location, instructionPointer, 801 expression, expressionLength); 802 if (error != B_OK) 803 return error; 804 805 // evaluate it 806 ExpressionEvaluationContext context(this, unit, addressSize, 807 subprogramEntry, targetInterface, instructionPointer, objectPointer, 808 hasObjectPointer, framePointer, relocationDelta); 809 DwarfExpressionEvaluator evaluator(&context); 810 return evaluator.EvaluateLocation(expression, expressionLength, 811 _result); 812 } 813 814 815 status_t 816 DwarfFile::EvaluateConstantValue(CompilationUnit* unit, uint8 addressSize, 817 DIESubprogram* subprogramEntry, const ConstantAttributeValue* value, 818 const DwarfTargetInterface* targetInterface, 819 target_addr_t instructionPointer, target_addr_t framePointer, 820 BVariant& _result) 821 { 822 if (!value->IsValid()) 823 return B_BAD_VALUE; 824 825 switch (value->attributeClass) { 826 case ATTRIBUTE_CLASS_CONSTANT: 827 _result.SetTo(value->constant); 828 return B_OK; 829 case ATTRIBUTE_CLASS_STRING: 830 _result.SetTo(value->string); 831 return B_OK; 832 case ATTRIBUTE_CLASS_BLOCK: 833 { 834 target_addr_t result; 835 status_t error = EvaluateExpression(unit, addressSize, 836 subprogramEntry, value->block.data, value->block.length, 837 targetInterface, instructionPointer, framePointer, 0, false, 838 result); 839 if (error != B_OK) 840 return error; 841 842 _result.SetTo(result); 843 return B_OK; 844 } 845 default: 846 return B_BAD_VALUE; 847 } 848 } 849 850 851 status_t 852 DwarfFile::EvaluateDynamicValue(CompilationUnit* unit, uint8 addressSize, 853 DIESubprogram* subprogramEntry, const DynamicAttributeValue* value, 854 const DwarfTargetInterface* targetInterface, 855 target_addr_t instructionPointer, target_addr_t framePointer, 856 BVariant& _result, DIEType** _type) 857 { 858 if (!value->IsValid()) 859 return B_BAD_VALUE; 860 861 DIEType* dummyType; 862 if (_type == NULL) 863 _type = &dummyType; 864 865 switch (value->attributeClass) { 866 case ATTRIBUTE_CLASS_CONSTANT: 867 _result.SetTo(value->constant); 868 *_type = NULL; 869 return B_OK; 870 871 case ATTRIBUTE_CLASS_REFERENCE: 872 { 873 // TODO: The specs are a bit fuzzy on this one: "the value is a 874 // reference to another entity whose value is the value of the 875 // attribute". Supposedly that also means e.g. if the referenced 876 // entity is a variable, we should read the value of that variable. 877 // ATM we only check for the types that can have a DW_AT_const_value 878 // attribute and evaluate it, if present. 879 DebugInfoEntry* entry = value->reference; 880 if (entry == NULL) 881 return B_BAD_VALUE; 882 883 const ConstantAttributeValue* constantValue = NULL; 884 DIEType* type = NULL; 885 886 switch (entry->Tag()) { 887 case DW_TAG_constant: 888 { 889 DIEConstant* constantEntry 890 = dynamic_cast<DIEConstant*>(entry); 891 constantValue = constantEntry->ConstValue(); 892 type = constantEntry->GetType(); 893 break; 894 } 895 case DW_TAG_enumerator: 896 constantValue = dynamic_cast<DIEEnumerator*>(entry) 897 ->ConstValue(); 898 if (DIEEnumerationType* enumerationType 899 = dynamic_cast<DIEEnumerationType*>( 900 entry->Parent())) { 901 type = enumerationType->GetType(); 902 } 903 break; 904 case DW_TAG_formal_parameter: 905 { 906 DIEFormalParameter* parameterEntry 907 = dynamic_cast<DIEFormalParameter*>(entry); 908 constantValue = parameterEntry->ConstValue(); 909 type = parameterEntry->GetType(); 910 break; 911 } 912 case DW_TAG_template_value_parameter: 913 { 914 DIETemplateValueParameter* parameterEntry 915 = dynamic_cast<DIETemplateValueParameter*>(entry); 916 constantValue = parameterEntry->ConstValue(); 917 type = parameterEntry->GetType(); 918 break; 919 } 920 case DW_TAG_variable: 921 { 922 DIEVariable* variableEntry 923 = dynamic_cast<DIEVariable*>(entry); 924 constantValue = variableEntry->ConstValue(); 925 type = variableEntry->GetType(); 926 break; 927 } 928 default: 929 return B_BAD_VALUE; 930 } 931 932 if (constantValue == NULL || !constantValue->IsValid()) 933 return B_BAD_VALUE; 934 935 status_t error = EvaluateConstantValue(unit, addressSize, 936 subprogramEntry, constantValue, targetInterface, 937 instructionPointer, framePointer, _result); 938 if (error != B_OK) 939 return error; 940 941 *_type = type; 942 return B_OK; 943 } 944 945 case ATTRIBUTE_CLASS_BLOCK: 946 { 947 target_addr_t result; 948 status_t error = EvaluateExpression(unit, addressSize, 949 subprogramEntry, value->block.data, value->block.length, 950 targetInterface, instructionPointer, framePointer, 0, false, 951 result); 952 if (error != B_OK) 953 return error; 954 955 _result.SetTo(result); 956 *_type = NULL; 957 return B_OK; 958 } 959 960 default: 961 return B_BAD_VALUE; 962 } 963 } 964 965 966 status_t 967 DwarfFile::_ParseDebugInfoSection() 968 { 969 // iterate through the debug info section 970 DataReader dataReader(fDebugInfoSection->Data(), 971 fDebugInfoSection->Size(), 4); 972 // address size doesn't matter here 973 while (dataReader.HasData()) { 974 off_t unitHeaderOffset = dataReader.Offset(); 975 bool dwarf64; 976 uint64 unitLength = dataReader.ReadInitialLength(dwarf64); 977 978 off_t unitLengthOffset = dataReader.Offset(); 979 // the unitLength starts here 980 981 if (unitLengthOffset + unitLength 982 > (uint64)fDebugInfoSection->Size()) { 983 WARNING("\"%s\": Invalid compilation unit length.\n", fName); 984 break; 985 } 986 987 int version = dataReader.Read<uint16>(0); 988 off_t abbrevOffset = dwarf64 989 ? dataReader.Read<uint64>(0) 990 : dataReader.Read<uint32>(0); 991 uint8 addressSize = dataReader.Read<uint8>(0); 992 993 if (dataReader.HasOverflow()) { 994 WARNING("\"%s\": Unexpected end of data in compilation unit " 995 "header.\n", fName); 996 break; 997 } 998 999 TRACE_DIE("DWARF%d compilation unit: version %d, length: %" B_PRIu64 1000 ", abbrevOffset: %" B_PRIdOFF ", address size: %d\n", 1001 dwarf64 ? 64 : 32, version, unitLength, abbrevOffset, addressSize); 1002 1003 if (version < 2 || version > 4) { 1004 WARNING("\"%s\": Unsupported compilation unit version: %d\n", 1005 fName, version); 1006 break; 1007 } 1008 1009 if (addressSize != 4 && addressSize != 8) { 1010 WARNING("\"%s\": Unsupported address size: %d\n", fName, 1011 addressSize); 1012 break; 1013 } 1014 dataReader.SetAddressSize(addressSize); 1015 1016 off_t unitContentOffset = dataReader.Offset(); 1017 1018 // create a compilation unit object 1019 CompilationUnit* unit = new(std::nothrow) CompilationUnit( 1020 unitHeaderOffset, unitContentOffset, 1021 unitLength + (unitLengthOffset - unitHeaderOffset), 1022 abbrevOffset, addressSize, dwarf64); 1023 if (unit == NULL || !fCompilationUnits.AddItem(unit)) { 1024 delete unit; 1025 return B_NO_MEMORY; 1026 } 1027 1028 // parse the debug info for the unit 1029 status_t error = _ParseCompilationUnit(unit); 1030 if (error != B_OK) 1031 return error; 1032 1033 dataReader.SeekAbsolute(unitLengthOffset + unitLength); 1034 } 1035 1036 return B_OK; 1037 } 1038 1039 1040 status_t 1041 DwarfFile::_ParseTypesSection() 1042 { 1043 DataReader dataReader(fDebugTypesSection->Data(), 1044 fDebugTypesSection->Size(), 4); 1045 while (dataReader.HasData()) { 1046 off_t unitHeaderOffset = dataReader.Offset(); 1047 bool dwarf64; 1048 uint64 unitLength = dataReader.ReadInitialLength(dwarf64); 1049 1050 off_t unitLengthOffset = dataReader.Offset(); 1051 // the unitLength starts here 1052 1053 if (unitLengthOffset + unitLength 1054 > (uint64)fDebugTypesSection->Size()) { 1055 WARNING("Invalid type unit length, offset %#" B_PRIx64 ".\n", 1056 unitHeaderOffset); 1057 break; 1058 } 1059 1060 int version = dataReader.Read<uint16>(0); 1061 off_t abbrevOffset = dwarf64 1062 ? dataReader.Read<uint64>(0) 1063 : dataReader.Read<uint32>(0); 1064 uint8 addressSize = dataReader.Read<uint8>(0); 1065 1066 if (dataReader.HasOverflow()) { 1067 WARNING("Unexpected end of data in type unit header at %#" 1068 B_PRIx64 ".\n", unitHeaderOffset); 1069 break; 1070 } 1071 1072 dataReader.SetAddressSize(addressSize); 1073 1074 uint64 signature = dataReader.Read<uint64>(0); 1075 1076 off_t typeOffset = dwarf64 1077 ? dataReader.Read<uint64>(0) 1078 : dataReader.Read<uint32>(0); 1079 1080 off_t unitContentOffset = dataReader.Offset(); 1081 1082 TRACE_DIE("DWARF%d type unit: version %d, length: %" B_PRIu64 1083 ", abbrevOffset: %" B_PRIdOFF ", address size: %d, " 1084 "signature: %#" B_PRIx64 ", type offset: %" B_PRIu64 "\n", 1085 dwarf64 ? 64 : 32, version, unitLength, abbrevOffset, addressSize, 1086 signature, typeOffset); 1087 1088 if (version > 4) { 1089 WARNING("\"%s\": Unsupported type unit version: %d\n", 1090 fName, version); 1091 break; 1092 } 1093 1094 if (addressSize != 4 && addressSize != 8) { 1095 WARNING("\"%s\": Unsupported address size: %d\n", fName, 1096 addressSize); 1097 break; 1098 } 1099 1100 // create a type unit object 1101 TypeUnit* unit = new(std::nothrow) TypeUnit( 1102 unitHeaderOffset, unitContentOffset, 1103 unitLength + (unitLengthOffset - unitHeaderOffset), 1104 abbrevOffset, typeOffset, addressSize, signature, dwarf64); 1105 if (unit == NULL) 1106 return B_NO_MEMORY; 1107 1108 // parse the debug info for the unit 1109 status_t error = _ParseTypeUnit(unit); 1110 if (error != B_OK) 1111 return error; 1112 1113 // TODO: it should theoretically never happen that we get a duplicate, 1114 // but it wouldn't hurt to check since that situation would potentially 1115 // be problematic. 1116 if (fTypeUnits.Lookup(signature) == NULL) { 1117 TypeUnitTableEntry* entry = new(std::nothrow) 1118 TypeUnitTableEntry(signature, unit); 1119 if (entry == NULL) 1120 return B_NO_MEMORY; 1121 1122 fTypeUnits.Insert(entry); 1123 } 1124 1125 dataReader.SeekAbsolute(unitLengthOffset + unitLength); 1126 } 1127 1128 return B_OK; 1129 } 1130 1131 1132 status_t 1133 DwarfFile::_ParseFrameSection(ElfSection* section, uint8 addressSize, 1134 bool ehFrame, FDEInfoList& infos) 1135 { 1136 if (ehFrame) { 1137 fItaniumEHFrameFormat = section->IsWritable(); 1138 // Crude heuristic for recognizing GCC 4 (Itanium ABI) style 1139 // .eh_frame sections. The ones generated by GCC 2 are writable, 1140 // the ones generated by GCC 4 aren't. 1141 } 1142 1143 DataReader dataReader((uint8*)section->Data(), 1144 section->Size(), addressSize); 1145 1146 while (dataReader.BytesRemaining() > 0) { 1147 // length 1148 bool dwarf64; 1149 off_t entryOffset = dataReader.Offset(); 1150 uint64 length = dataReader.ReadInitialLength(dwarf64); 1151 1152 TRACE_CFI("DwarfFile::_ParseFrameSection(): offset: %" B_PRIdOFF 1153 ", length: %" B_PRId64 "\n", entryOffset, length); 1154 1155 if (length > (uint64)dataReader.BytesRemaining()) 1156 return B_BAD_DATA; 1157 off_t lengthOffset = dataReader.Offset(); 1158 1159 // CIE ID/CIE pointer 1160 uint64 cieID = dwarf64 1161 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0); 1162 1163 // In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does. 1164 if (ehFrame 1165 ? cieID == 0 1166 : (dwarf64 1167 ? cieID == 0xffffffffffffffffULL 1168 : cieID == 0xffffffff)) { 1169 // this is a CIE -- skip it 1170 } else { 1171 // this is a FDE 1172 uint64 initialLocationOffset = dataReader.Offset(); 1173 // In .eh_frame the CIE offset is a relative back offset. 1174 if (ehFrame) { 1175 if (cieID > (uint64)lengthOffset) { 1176 TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max " 1177 "possible: %" B_PRIu64 "\n", cieID, lengthOffset); 1178 break; 1179 } 1180 // convert to a section relative offset 1181 cieID = lengthOffset - cieID; 1182 } 1183 1184 1185 CfaContext context; 1186 CIEAugmentation cieAugmentation; 1187 // when using .eh_frame format, we need to parse the CIE's 1188 // augmentation up front in order to know how the FDE's addresses 1189 // will be represented 1190 DataReader cieReader; 1191 off_t cieRemaining; 1192 status_t error = _ParseCIEHeader(section, ehFrame, NULL, 1193 addressSize, context, cieID, cieAugmentation, cieReader, 1194 cieRemaining); 1195 if (error != B_OK) 1196 return error; 1197 if (cieReader.HasOverflow()) 1198 return B_BAD_DATA; 1199 if (cieRemaining < 0) 1200 return B_BAD_DATA; 1201 1202 target_addr_t initialLocation = cieAugmentation.ReadEncodedAddress( 1203 dataReader, fElfFile, section); 1204 target_addr_t addressRange = cieAugmentation.ReadEncodedAddress( 1205 dataReader, fElfFile, section, true); 1206 1207 if (dataReader.HasOverflow()) 1208 return B_BAD_DATA; 1209 1210 if ((cieAugmentation.FDEAddressType() 1211 & CFI_ADDRESS_TYPE_PC_RELATIVE) != 0) { 1212 initialLocation += initialLocationOffset; 1213 } 1214 1215 // for unknown reasons, the debug frame sections generated by gcc 1216 // sometimes contain duplicates at different offsets within the 1217 // section. In such a case, simply skip the duplicates. 1218 FDELookupInfo* temp = _GetContainingFDEInfo(initialLocation, 1219 infos); 1220 if (temp == NULL) { 1221 FDELookupInfo* info = new(std::nothrow)FDELookupInfo( 1222 initialLocation, initialLocation + addressRange - 1, 1223 entryOffset, cieID, ehFrame); 1224 if (info == NULL) 1225 return B_NO_MEMORY; 1226 1227 ObjectDeleter<FDELookupInfo> infoDeleter(info); 1228 if (!infos.BinaryInsert(info, FDELookupInfo::CompareFDEInfos)) 1229 return B_NO_MEMORY; 1230 1231 infoDeleter.Detach(); 1232 } 1233 } 1234 1235 dataReader.SeekAbsolute(lengthOffset + length); 1236 } 1237 1238 return B_OK; 1239 } 1240 1241 1242 status_t 1243 DwarfFile::_ParseCompilationUnit(CompilationUnit* unit) 1244 { 1245 AbbreviationTable* abbreviationTable; 1246 status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(), 1247 abbreviationTable); 1248 if (error != B_OK) 1249 return error; 1250 1251 unit->SetAbbreviationTable(abbreviationTable); 1252 1253 DataReader dataReader( 1254 (const uint8*)fDebugInfoSection->Data() + unit->ContentOffset(), 1255 unit->ContentSize(), unit->AddressSize()); 1256 1257 DebugInfoEntry* entry; 1258 bool endOfEntryList; 1259 error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry, 1260 endOfEntryList); 1261 if (error != B_OK) 1262 return error; 1263 1264 DIECompileUnitBase* unitEntry = dynamic_cast<DIECompileUnitBase*>(entry); 1265 if (unitEntry == NULL) { 1266 WARNING("No compilation unit entry in .debug_info section.\n"); 1267 return B_BAD_DATA; 1268 } 1269 1270 unit->SetUnitEntry(unitEntry); 1271 1272 TRACE_DIE_ONLY( 1273 TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n", 1274 dataReader.BytesRemaining()); 1275 if (dataReader.HasData()) { 1276 TRACE_DIE(" "); 1277 while (dataReader.HasData()) 1278 TRACE_DIE("%02x", dataReader.Read<uint8>(0)); 1279 TRACE_DIE("\n"); 1280 } 1281 ) 1282 return B_OK; 1283 } 1284 1285 1286 status_t 1287 DwarfFile::_ParseTypeUnit(TypeUnit* unit) 1288 { 1289 AbbreviationTable* abbreviationTable; 1290 status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(), 1291 abbreviationTable); 1292 if (error != B_OK) 1293 return error; 1294 1295 unit->SetAbbreviationTable(abbreviationTable); 1296 1297 DataReader dataReader( 1298 (const uint8*)fDebugTypesSection->Data() + unit->ContentOffset(), 1299 unit->ContentSize(), unit->AddressSize()); 1300 1301 DebugInfoEntry* entry; 1302 bool endOfEntryList; 1303 error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry, 1304 endOfEntryList); 1305 if (error != B_OK) 1306 return error; 1307 1308 DIETypeUnit* unitEntry = dynamic_cast<DIETypeUnit*>(entry); 1309 if (unitEntry == NULL) { 1310 WARNING("No type unit entry in .debug_types section.\n"); 1311 return B_BAD_DATA; 1312 } 1313 1314 unit->SetUnitEntry(unitEntry); 1315 DebugInfoEntry* typeEntry = unit->EntryForOffset(unit->TypeOffset()); 1316 if (typeEntry == NULL) { 1317 WARNING("No type found for type unit %p at specified offset %" 1318 B_PRId64 ".\n", unit, unit->TypeOffset()); 1319 return B_BAD_DATA; 1320 } 1321 unit->SetTypeEntry(typeEntry); 1322 1323 TRACE_DIE_ONLY( 1324 TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n", 1325 dataReader.BytesRemaining()); 1326 if (dataReader.HasData()) { 1327 TRACE_DIE(" "); 1328 while (dataReader.HasData()) 1329 TRACE_DIE("%02x", dataReader.Read<uint8>(0)); 1330 TRACE_DIE("\n"); 1331 } 1332 ) 1333 return B_OK; 1334 } 1335 1336 1337 status_t 1338 DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader, 1339 BaseUnit* unit, AbbreviationTable* abbreviationTable, 1340 DebugInfoEntry*& _entry, bool& _endOfEntryList, int level) 1341 { 1342 off_t entryOffset = dataReader.Offset() 1343 + unit->RelativeContentOffset(); 1344 1345 uint32 code = dataReader.ReadUnsignedLEB128(0); 1346 if (code == 0) { 1347 if (dataReader.HasOverflow()) { 1348 WARNING("Unexpected end of .debug_info section.\n"); 1349 return B_BAD_DATA; 1350 } 1351 _entry = NULL; 1352 _endOfEntryList = true; 1353 return B_OK; 1354 } 1355 1356 // get the corresponding abbreviation entry 1357 AbbreviationEntry abbreviationEntry; 1358 if (!abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry)) { 1359 WARNING("No abbreviation entry for code %" B_PRIx32 "\n", code); 1360 return B_BAD_DATA; 1361 } 1362 1363 DebugInfoEntry* entry; 1364 status_t error = fDebugInfoFactory.CreateDebugInfoEntry( 1365 abbreviationEntry.Tag(), entry); 1366 if (error != B_OK) { 1367 WARNING("Failed to generate entry for tag %" B_PRIu32 ", code %" 1368 B_PRIu32 "\n", abbreviationEntry.Tag(), code); 1369 return error; 1370 } 1371 1372 ObjectDeleter<DebugInfoEntry> entryDeleter(entry); 1373 1374 TRACE_DIE("%*sentry %p at %" B_PRIdOFF ": %" B_PRIu32 ", tag: %s (%" 1375 B_PRIu32 "), children: %d\n", level * 2, "", entry, entryOffset, 1376 abbreviationEntry.Code(), get_entry_tag_name(abbreviationEntry.Tag()), 1377 abbreviationEntry.Tag(), abbreviationEntry.HasChildren()); 1378 1379 error = unit->AddDebugInfoEntry(entry, entryOffset); 1380 1381 if (error != B_OK) 1382 return error; 1383 1384 // parse the attributes (supply NULL entry to avoid adding them yet) 1385 error = _ParseEntryAttributes(dataReader, unit, NULL, abbreviationEntry); 1386 if (error != B_OK) 1387 return error; 1388 1389 // parse children, if the entry has any 1390 if (abbreviationEntry.HasChildren()) { 1391 while (true) { 1392 DebugInfoEntry* childEntry; 1393 bool endOfEntryList; 1394 status_t error = _ParseDebugInfoEntry(dataReader, 1395 unit, abbreviationTable, childEntry, endOfEntryList, level + 1); 1396 if (error != B_OK) 1397 return error; 1398 1399 // add the child to our entry 1400 if (childEntry != NULL) { 1401 if (entry != NULL) { 1402 error = entry->AddChild(childEntry); 1403 if (error == B_OK) { 1404 childEntry->SetParent(entry); 1405 } else if (error == ENTRY_NOT_HANDLED) { 1406 error = B_OK; 1407 TRACE_DIE("%*s -> child unhandled\n", level * 2, ""); 1408 } 1409 1410 if (error != B_OK) { 1411 delete childEntry; 1412 return error; 1413 } 1414 } else 1415 delete childEntry; 1416 } 1417 1418 if (endOfEntryList) 1419 break; 1420 } 1421 } 1422 1423 entryDeleter.Detach(); 1424 _entry = entry; 1425 _endOfEntryList = false; 1426 return B_OK; 1427 } 1428 1429 1430 status_t 1431 DwarfFile::_FinishUnit(BaseUnit* unit) 1432 { 1433 CompilationUnit* compilationUnit = dynamic_cast<CompilationUnit*>(unit); 1434 bool isTypeUnit = compilationUnit == NULL; 1435 TRACE_DIE("\nfinishing %s unit %p\n", 1436 isTypeUnit ? "type" : "compilation", unit); 1437 1438 1439 AbbreviationTable* abbreviationTable = unit->GetAbbreviationTable(); 1440 1441 ElfSection* section = isTypeUnit 1442 ? fDebugTypesSection : fDebugInfoSection; 1443 DataReader dataReader( 1444 (const uint8*)section->Data() + unit->HeaderOffset(), 1445 unit->TotalSize(), unit->AddressSize()); 1446 1447 DebugInfoEntryInitInfo entryInitInfo; 1448 1449 int entryCount = unit->CountEntries(); 1450 for (int i = 0; i < entryCount; i++) { 1451 // get the entry 1452 DebugInfoEntry* entry; 1453 off_t offset; 1454 unit->GetEntryAt(i, entry, offset); 1455 1456 TRACE_DIE("entry %p at %" B_PRIdOFF "\n", entry, offset); 1457 1458 // seek the reader to the entry 1459 dataReader.SeekAbsolute(offset); 1460 1461 // read the entry code 1462 uint32 code = dataReader.ReadUnsignedLEB128(0); 1463 1464 // get the respective abbreviation entry 1465 AbbreviationEntry abbreviationEntry; 1466 abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry); 1467 1468 // initialization before setting the attributes 1469 status_t error = entry->InitAfterHierarchy(entryInitInfo); 1470 if (error != B_OK) { 1471 WARNING("Init after hierarchy failed!\n"); 1472 return error; 1473 } 1474 1475 // parse the attributes -- this time pass the entry, so that the 1476 // attribute get set on it 1477 error = _ParseEntryAttributes(dataReader, unit, entry, 1478 abbreviationEntry); 1479 if (error != B_OK) 1480 return error; 1481 1482 // initialization after setting the attributes 1483 error = entry->InitAfterAttributes(entryInitInfo); 1484 if (error != B_OK) { 1485 WARNING("Init after attributes failed!\n"); 1486 return error; 1487 } 1488 } 1489 1490 // set the compilation unit's source language 1491 unit->SetSourceLanguage(entryInitInfo.languageInfo); 1492 1493 if (isTypeUnit) 1494 return B_OK; 1495 1496 // resolve the compilation unit's address range list 1497 if (TargetAddressRangeList* ranges = ResolveRangeList(compilationUnit, 1498 compilationUnit->UnitEntry()->AddressRangesOffset())) { 1499 compilationUnit->SetAddressRanges(ranges); 1500 ranges->ReleaseReference(); 1501 } 1502 1503 // add compilation dir to directory list 1504 const char* compilationDir = compilationUnit->UnitEntry() 1505 ->CompilationDir(); 1506 if (!compilationUnit->AddDirectory(compilationDir != NULL 1507 ? compilationDir : ".")) { 1508 return B_NO_MEMORY; 1509 } 1510 1511 // parse line info header 1512 if (fDebugLineSection != NULL) 1513 _ParseLineInfo(compilationUnit); 1514 1515 return B_OK; 1516 } 1517 1518 1519 status_t 1520 DwarfFile::_ParseEntryAttributes(DataReader& dataReader, 1521 BaseUnit* unit, DebugInfoEntry* entry, AbbreviationEntry& abbreviationEntry) 1522 { 1523 uint32 attributeName; 1524 uint32 attributeForm; 1525 while (abbreviationEntry.GetNextAttribute(attributeName, 1526 attributeForm)) { 1527 // resolve attribute form indirection 1528 if (attributeForm == DW_FORM_indirect) 1529 attributeForm = dataReader.ReadUnsignedLEB128(0); 1530 1531 // prepare an AttributeValue 1532 AttributeValue attributeValue; 1533 attributeValue.attributeForm = attributeForm; 1534 bool isSigned = false; 1535 1536 // Read the attribute value according to the attribute's form. For 1537 // the forms that don't map to a single attribute class only or 1538 // those that need additional processing, we read a temporary value 1539 // first. 1540 uint64 value = 0; 1541 off_t blockLength = 0; 1542 off_t valueOffset = dataReader.Offset() + unit->ContentOffset(); 1543 uint8 refType = dwarf_reference_type_local; 1544 1545 switch (attributeForm) { 1546 case DW_FORM_addr: 1547 value = dataReader.ReadAddress(0); 1548 break; 1549 case DW_FORM_block2: 1550 blockLength = dataReader.Read<uint16>(0); 1551 break; 1552 case DW_FORM_block4: 1553 blockLength = dataReader.Read<uint32>(0); 1554 break; 1555 case DW_FORM_data2: 1556 value = dataReader.Read<uint16>(0); 1557 break; 1558 case DW_FORM_data4: 1559 value = dataReader.Read<uint32>(0); 1560 break; 1561 case DW_FORM_data8: 1562 value = dataReader.Read<uint64>(0); 1563 break; 1564 case DW_FORM_string: 1565 attributeValue.SetToString(dataReader.ReadString()); 1566 break; 1567 case DW_FORM_block: 1568 case DW_FORM_exprloc: 1569 blockLength = dataReader.ReadUnsignedLEB128(0); 1570 break; 1571 case DW_FORM_block1: 1572 blockLength = dataReader.Read<uint8>(0); 1573 break; 1574 case DW_FORM_data1: 1575 value = dataReader.Read<uint8>(0); 1576 break; 1577 case DW_FORM_flag: 1578 attributeValue.SetToFlag(dataReader.Read<uint8>(0) != 0); 1579 break; 1580 case DW_FORM_sdata: 1581 value = dataReader.ReadSignedLEB128(0); 1582 isSigned = true; 1583 break; 1584 case DW_FORM_strp: 1585 { 1586 if (fDebugStringSection != NULL) { 1587 uint64 offset = unit->IsDwarf64() 1588 ? dataReader.Read<uint64>(0) 1589 : dataReader.Read<uint32>(0); 1590 if (offset >= fDebugStringSection->Size()) { 1591 WARNING("Invalid DW_FORM_strp offset: %" B_PRIu64 "\n", 1592 offset); 1593 return B_BAD_DATA; 1594 } 1595 attributeValue.SetToString( 1596 (const char*)fDebugStringSection->Data() + offset); 1597 } else { 1598 WARNING("Invalid DW_FORM_strp: no string section!\n"); 1599 return B_BAD_DATA; 1600 } 1601 break; 1602 } 1603 case DW_FORM_udata: 1604 value = dataReader.ReadUnsignedLEB128(0); 1605 break; 1606 case DW_FORM_ref_addr: 1607 value = unit->IsDwarf64() 1608 ? dataReader.Read<uint64>(0) 1609 : (uint64)dataReader.Read<uint32>(0); 1610 refType = dwarf_reference_type_global; 1611 break; 1612 case DW_FORM_ref1: 1613 value = dataReader.Read<uint8>(0); 1614 break; 1615 case DW_FORM_ref2: 1616 value = dataReader.Read<uint16>(0); 1617 break; 1618 case DW_FORM_ref4: 1619 value = dataReader.Read<uint32>(0); 1620 break; 1621 case DW_FORM_ref8: 1622 value = dataReader.Read<uint64>(0); 1623 break; 1624 case DW_FORM_ref_udata: 1625 value = dataReader.ReadUnsignedLEB128(0); 1626 break; 1627 case DW_FORM_flag_present: 1628 attributeValue.SetToFlag(true); 1629 break; 1630 case DW_FORM_ref_sig8: 1631 fTypesSectionRequired = true; 1632 value = dataReader.Read<uint64>(0); 1633 refType = dwarf_reference_type_signature; 1634 break; 1635 case DW_FORM_sec_offset: 1636 value = unit->IsDwarf64() 1637 ? dataReader.Read<uint64>(0) 1638 : (uint64)dataReader.Read<uint32>(0); 1639 break; 1640 case DW_FORM_indirect: 1641 default: 1642 WARNING("Unsupported attribute form: %" B_PRIu32 "\n", 1643 attributeForm); 1644 return B_BAD_DATA; 1645 } 1646 1647 // get the attribute class -- skip the attribute, if we can't handle 1648 // it 1649 uint8 attributeClass = get_attribute_class(attributeName, 1650 attributeForm); 1651 1652 if (attributeClass == ATTRIBUTE_CLASS_UNKNOWN) { 1653 TRACE_DIE("skipping attribute with unrecognized class: %s (%#" 1654 B_PRIx32 ") %s (%#" B_PRIx32 ")\n", 1655 get_attribute_name_name(attributeName), attributeName, 1656 get_attribute_form_name(attributeForm), attributeForm); 1657 continue; 1658 } 1659 1660 // set the attribute value according to the attribute's class 1661 switch (attributeClass) { 1662 case ATTRIBUTE_CLASS_ADDRESS: 1663 attributeValue.SetToAddress(value); 1664 break; 1665 case ATTRIBUTE_CLASS_BLOCK: 1666 attributeValue.SetToBlock(dataReader.Data(), blockLength); 1667 dataReader.Skip(blockLength); 1668 break; 1669 case ATTRIBUTE_CLASS_CONSTANT: 1670 attributeValue.SetToConstant(value, isSigned); 1671 break; 1672 case ATTRIBUTE_CLASS_LINEPTR: 1673 attributeValue.SetToLinePointer(value); 1674 break; 1675 case ATTRIBUTE_CLASS_LOCLISTPTR: 1676 attributeValue.SetToLocationListPointer(value); 1677 break; 1678 case ATTRIBUTE_CLASS_MACPTR: 1679 attributeValue.SetToMacroPointer(value); 1680 break; 1681 case ATTRIBUTE_CLASS_RANGELISTPTR: 1682 attributeValue.SetToRangeListPointer(value); 1683 break; 1684 case ATTRIBUTE_CLASS_REFERENCE: 1685 if (entry != NULL) { 1686 attributeValue.SetToReference(_ResolveReference( 1687 unit, value, refType)); 1688 if (attributeValue.reference == NULL) { 1689 // gcc 2 apparently somtimes produces DW_AT_sibling 1690 // attributes pointing to the end of the sibling list. 1691 // Just ignore those. 1692 if (attributeName == DW_AT_sibling) 1693 continue; 1694 1695 WARNING("Failed to resolve reference on entry %p: " 1696 "(%#" B_PRIx64 ") %s (%#" B_PRIx32 ") %s " 1697 "(%#" B_PRIx32 "): value: %#" B_PRIx64 "\n", 1698 entry, 1699 valueOffset, 1700 get_attribute_name_name(attributeName), 1701 attributeName, 1702 get_attribute_form_name(attributeForm), 1703 attributeForm, value); 1704 return B_ENTRY_NOT_FOUND; 1705 } 1706 } 1707 break; 1708 case ATTRIBUTE_CLASS_FLAG: 1709 case ATTRIBUTE_CLASS_STRING: 1710 // already set 1711 break; 1712 } 1713 1714 if (dataReader.HasOverflow()) { 1715 WARNING("Unexpected end of .debug_info section.\n"); 1716 return B_BAD_DATA; 1717 } 1718 1719 TRACE_DIE_ONLY( 1720 char buffer[1024]; 1721 TRACE_DIE(" attr (%#" B_PRIx64 ") %s %s (%d): %s\n", 1722 valueOffset, 1723 get_attribute_name_name(attributeName), 1724 get_attribute_form_name(attributeForm), attributeClass, 1725 attributeValue.ToString(buffer, sizeof(buffer))); 1726 ) 1727 1728 // add the attribute 1729 if (entry != NULL) { 1730 DebugInfoEntrySetter attributeSetter 1731 = get_attribute_name_setter(attributeName); 1732 if (attributeSetter != 0) { 1733 status_t error = (entry->*attributeSetter)(attributeName, 1734 attributeValue); 1735 1736 if (error == ATTRIBUTE_NOT_HANDLED) { 1737 error = B_OK; 1738 TRACE_DIE(" -> unhandled\n"); 1739 } 1740 1741 if (error != B_OK) { 1742 WARNING("Failed to set attribute: name: %s, form: %s: %s\n", 1743 get_attribute_name_name(attributeName), 1744 get_attribute_form_name(attributeForm), 1745 strerror(error)); 1746 } 1747 } else 1748 TRACE_DIE(" -> no attribute setter!\n"); 1749 } 1750 } 1751 1752 return B_OK; 1753 } 1754 1755 1756 status_t 1757 DwarfFile::_ParseLineInfo(CompilationUnit* unit) 1758 { 1759 off_t offset = unit->UnitEntry()->StatementListOffset(); 1760 1761 TRACE_LINES("DwarfFile::_ParseLineInfo(%p), offset: %" B_PRIdOFF "\n", unit, 1762 offset); 1763 1764 DataReader dataReader((uint8*)fDebugLineSection->Data() + offset, 1765 fDebugLineSection->Size() - offset, unit->AddressSize()); 1766 1767 // unit length 1768 bool dwarf64; 1769 uint64 unitLength = dataReader.ReadInitialLength(dwarf64); 1770 if (unitLength > (uint64)dataReader.BytesRemaining()) 1771 return B_BAD_DATA; 1772 off_t unitOffset = dataReader.Offset(); 1773 1774 // version (uhalf) 1775 uint16 version = dataReader.Read<uint16>(0); 1776 1777 // header_length (4/8) 1778 uint64 headerLength = dwarf64 1779 ? dataReader.Read<uint64>(0) : (uint64)dataReader.Read<uint32>(0); 1780 off_t headerOffset = dataReader.Offset(); 1781 1782 if ((uint64)dataReader.BytesRemaining() < headerLength) 1783 return B_BAD_DATA; 1784 1785 // minimum instruction length 1786 uint8 minInstructionLength = dataReader.Read<uint8>(0); 1787 1788 // default is statement 1789 bool defaultIsStatement = dataReader.Read<uint8>(0) != 0; 1790 1791 // line_base (sbyte) 1792 int8 lineBase = (int8)dataReader.Read<uint8>(0); 1793 1794 // line_range (ubyte) 1795 uint8 lineRange = dataReader.Read<uint8>(0); 1796 1797 // opcode_base (ubyte) 1798 uint8 opcodeBase = dataReader.Read<uint8>(0); 1799 1800 // standard_opcode_lengths (ubyte[]) 1801 const uint8* standardOpcodeLengths = (const uint8*)dataReader.Data(); 1802 dataReader.Skip(opcodeBase - 1); 1803 1804 if (dataReader.HasOverflow()) 1805 return B_BAD_DATA; 1806 1807 if (version != 2 && version != 3) 1808 return B_UNSUPPORTED; 1809 1810 TRACE_LINES(" unitLength: %" B_PRIu64 "\n", unitLength); 1811 TRACE_LINES(" version: %u\n", version); 1812 TRACE_LINES(" headerLength: %" B_PRIu64 "\n", headerLength); 1813 TRACE_LINES(" minInstructionLength: %u\n", minInstructionLength); 1814 TRACE_LINES(" defaultIsStatement: %d\n", defaultIsStatement); 1815 TRACE_LINES(" lineBase: %d\n", lineBase); 1816 TRACE_LINES(" lineRange: %u\n", lineRange); 1817 TRACE_LINES(" opcodeBase: %u\n", opcodeBase); 1818 1819 // include directories 1820 TRACE_LINES(" include directories:\n"); 1821 while (const char* directory = dataReader.ReadString()) { 1822 if (*directory == '\0') 1823 break; 1824 TRACE_LINES(" \"%s\"\n", directory); 1825 1826 if (!unit->AddDirectory(directory)) 1827 return B_NO_MEMORY; 1828 } 1829 1830 // file names 1831 TRACE_LINES(" files:\n"); 1832 while (const char* file = dataReader.ReadString()) { 1833 if (*file == '\0') 1834 break; 1835 uint64 dirIndex = dataReader.ReadUnsignedLEB128(0); 1836 TRACE_LINES_ONLY(uint64 modificationTime =) 1837 dataReader.ReadUnsignedLEB128(0); 1838 TRACE_LINES_ONLY(uint64 fileLength =) 1839 dataReader.ReadUnsignedLEB128(0); 1840 1841 if (dataReader.HasOverflow()) 1842 return B_BAD_DATA; 1843 1844 TRACE_LINES(" \"%s\", dir index: %" B_PRIu64 ", mtime: %" B_PRIu64 1845 ", length: %" B_PRIu64 "\n", file, dirIndex, modificationTime, 1846 fileLength); 1847 1848 if (!unit->AddFile(file, dirIndex)) 1849 return B_NO_MEMORY; 1850 } 1851 1852 off_t readerOffset = dataReader.Offset(); 1853 if ((uint64)readerOffset > readerOffset + headerLength) 1854 return B_BAD_DATA; 1855 off_t offsetToProgram = headerOffset + headerLength - readerOffset; 1856 1857 const uint8* program = (uint8*)dataReader.Data() + offsetToProgram; 1858 size_t programSize = unitLength - (readerOffset - unitOffset); 1859 1860 return unit->GetLineNumberProgram().Init(program, programSize, 1861 minInstructionLength, defaultIsStatement, lineBase, lineRange, 1862 opcodeBase, standardOpcodeLengths); 1863 } 1864 1865 1866 status_t 1867 DwarfFile::_UnwindCallFrame(CompilationUnit* unit, uint8 addressSize, 1868 DIESubprogram* subprogramEntry, target_addr_t location, 1869 const FDELookupInfo* info, const DwarfTargetInterface* inputInterface, 1870 DwarfTargetInterface* outputInterface, target_addr_t& _framePointer) 1871 { 1872 ElfSection* currentFrameSection = (info->ehFrame) 1873 ? fEHFrameSection : fDebugFrameSection; 1874 1875 TRACE_CFI("DwarfFile::_UnwindCallFrame(%#" B_PRIx64 ")\n", location); 1876 1877 DataReader dataReader((uint8*)currentFrameSection->Data(), 1878 currentFrameSection->Size(), unit != NULL 1879 ? unit->AddressSize() : addressSize); 1880 dataReader.SeekAbsolute(info->fdeOffset); 1881 1882 bool dwarf64; 1883 uint64 length = dataReader.ReadInitialLength(dwarf64); 1884 uint64 lengthOffset = dataReader.Offset(); 1885 1886 CfaContext context; 1887 CIEAugmentation cieAugmentation; 1888 // when using .eh_frame format, we need to parse the CIE's 1889 // augmentation up front in order to know how the FDE's addresses 1890 // will be represented 1891 DataReader cieReader; 1892 off_t cieRemaining; 1893 status_t error = _ParseCIEHeader(currentFrameSection, 1894 info->ehFrame, unit, addressSize, context, info->cieOffset, 1895 cieAugmentation, cieReader, cieRemaining); 1896 if (error != B_OK) 1897 return error; 1898 if (cieReader.HasOverflow()) 1899 return B_BAD_DATA; 1900 if (cieRemaining < 0) 1901 return B_BAD_DATA; 1902 1903 // skip CIE ID, initial offset and range, since we already know those 1904 // from FDELookupInfo. 1905 dwarf64 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0); 1906 cieAugmentation.ReadEncodedAddress(dataReader, fElfFile, 1907 currentFrameSection); 1908 cieAugmentation.ReadEncodedAddress(dataReader, fElfFile, 1909 currentFrameSection, true); 1910 1911 TRACE_CFI(" found fde: length: %" B_PRIu64 " (%" B_PRIdOFF 1912 "), CIE offset: %#" B_PRIx64 ", location: %#" B_PRIx64 ", " 1913 "range: %#" B_PRIx64 "\n", length, dataReader.BytesRemaining(), 1914 info->cieOffset, info->start, info->end - info->start); 1915 1916 context.SetLocation(location, info->start); 1917 uint32 registerCount = outputInterface->CountRegisters(); 1918 error = context.Init(registerCount); 1919 if (error != B_OK) 1920 return error; 1921 1922 error = outputInterface->InitRegisterRules(context); 1923 if (error != B_OK) 1924 return error; 1925 1926 // process the CIE's frame info instructions 1927 cieReader = cieReader.RestrictedReader(cieRemaining); 1928 error = _ParseFrameInfoInstructions(unit, context, 1929 cieReader, cieAugmentation); 1930 if (error != B_OK) 1931 return error; 1932 1933 // read the FDE augmentation data (if any) 1934 FDEAugmentation fdeAugmentation; 1935 error = cieAugmentation.ReadFDEData(dataReader, 1936 fdeAugmentation); 1937 if (error != B_OK) { 1938 TRACE_CFI(" failed to read FDE augmentation data!\n"); 1939 return error; 1940 } 1941 1942 error = context.SaveInitialRuleSet(); 1943 if (error != B_OK) 1944 return error; 1945 1946 uint64 remaining = lengthOffset + length - dataReader.Offset(); 1947 if (remaining < 0) 1948 return B_BAD_DATA; 1949 1950 DataReader restrictedReader = 1951 dataReader.RestrictedReader(remaining); 1952 error = _ParseFrameInfoInstructions(unit, context, 1953 restrictedReader, cieAugmentation); 1954 if (error != B_OK) 1955 return error; 1956 1957 TRACE_CFI(" found row!\n"); 1958 1959 // apply the rules of the final row 1960 // get the frameAddress first 1961 target_addr_t frameAddress; 1962 CfaCfaRule* cfaCfaRule = context.GetCfaCfaRule(); 1963 switch (cfaCfaRule->Type()) { 1964 case CFA_CFA_RULE_REGISTER_OFFSET: 1965 { 1966 BVariant value; 1967 if (!inputInterface->GetRegisterValue( 1968 cfaCfaRule->Register(), value) 1969 || !value.IsNumber()) { 1970 return B_UNSUPPORTED; 1971 } 1972 frameAddress = value.ToUInt64() + cfaCfaRule->Offset(); 1973 break; 1974 } 1975 case CFA_CFA_RULE_EXPRESSION: 1976 { 1977 error = EvaluateExpression(unit, addressSize, 1978 subprogramEntry, 1979 cfaCfaRule->Expression().block, 1980 cfaCfaRule->Expression().size, 1981 inputInterface, location, 0, 0, false, 1982 frameAddress); 1983 if (error != B_OK) 1984 return error; 1985 break; 1986 } 1987 case CFA_CFA_RULE_UNDEFINED: 1988 default: 1989 return B_BAD_VALUE; 1990 } 1991 1992 TRACE_CFI(" frame address: %#" B_PRIx64 "\n", frameAddress); 1993 1994 // apply the register rules 1995 for (uint32 i = 0; i < registerCount; i++) { 1996 TRACE_CFI(" reg %" B_PRIu32 "\n", i); 1997 1998 uint32 valueType = outputInterface->RegisterValueType(i); 1999 if (valueType == 0) 2000 continue; 2001 2002 CfaRule* rule = context.RegisterRule(i); 2003 if (rule == NULL) 2004 continue; 2005 2006 // apply the rule 2007 switch (rule->Type()) { 2008 case CFA_RULE_SAME_VALUE: 2009 { 2010 TRACE_CFI(" -> CFA_RULE_SAME_VALUE\n"); 2011 2012 BVariant value; 2013 if (inputInterface->GetRegisterValue(i, value)) 2014 outputInterface->SetRegisterValue(i, value); 2015 break; 2016 } 2017 case CFA_RULE_LOCATION_OFFSET: 2018 { 2019 TRACE_CFI(" -> CFA_RULE_LOCATION_OFFSET: %" 2020 B_PRId64 "\n", rule->Offset()); 2021 2022 BVariant value; 2023 if (inputInterface->ReadValueFromMemory( 2024 frameAddress + rule->Offset(), valueType, 2025 value)) { 2026 outputInterface->SetRegisterValue(i, value); 2027 } 2028 break; 2029 } 2030 case CFA_RULE_VALUE_OFFSET: 2031 TRACE_CFI(" -> CFA_RULE_VALUE_OFFSET\n"); 2032 2033 outputInterface->SetRegisterValue(i, 2034 frameAddress + rule->Offset()); 2035 break; 2036 case CFA_RULE_REGISTER: 2037 { 2038 TRACE_CFI(" -> CFA_RULE_REGISTER\n"); 2039 2040 BVariant value; 2041 if (inputInterface->GetRegisterValue( 2042 rule->Register(), value)) { 2043 outputInterface->SetRegisterValue(i, value); 2044 } 2045 break; 2046 } 2047 case CFA_RULE_LOCATION_EXPRESSION: 2048 { 2049 TRACE_CFI(" -> CFA_RULE_LOCATION_EXPRESSION\n"); 2050 2051 target_addr_t address; 2052 error = EvaluateExpression(unit, addressSize, 2053 subprogramEntry, 2054 rule->Expression().block, 2055 rule->Expression().size, 2056 inputInterface, location, frameAddress, 2057 frameAddress, true, address); 2058 BVariant value; 2059 if (error == B_OK 2060 && inputInterface->ReadValueFromMemory(address, 2061 valueType, value)) { 2062 outputInterface->SetRegisterValue(i, value); 2063 } 2064 break; 2065 } 2066 case CFA_RULE_VALUE_EXPRESSION: 2067 { 2068 TRACE_CFI(" -> CFA_RULE_VALUE_EXPRESSION\n"); 2069 2070 target_addr_t value; 2071 error = EvaluateExpression(unit, addressSize, 2072 subprogramEntry, 2073 rule->Expression().block, 2074 rule->Expression().size, 2075 inputInterface, location, frameAddress, 2076 frameAddress, true, value); 2077 if (error == B_OK) 2078 outputInterface->SetRegisterValue(i, value); 2079 break; 2080 } 2081 case CFA_RULE_UNDEFINED: 2082 TRACE_CFI(" -> CFA_RULE_UNDEFINED\n"); 2083 default: 2084 break; 2085 } 2086 } 2087 2088 _framePointer = frameAddress; 2089 2090 return B_OK; 2091 } 2092 2093 2094 status_t 2095 DwarfFile::_ParseCIEHeader(ElfSection* debugFrameSection, 2096 bool usingEHFrameSection, CompilationUnit* unit, uint8 addressSize, 2097 CfaContext& context, off_t cieOffset, CIEAugmentation& cieAugmentation, 2098 DataReader& dataReader, off_t& _cieRemaining) 2099 { 2100 if (cieOffset < 0 || (uint64)cieOffset >= debugFrameSection->Size()) 2101 return B_BAD_DATA; 2102 2103 dataReader.SetTo((uint8*)debugFrameSection->Data() + cieOffset, 2104 debugFrameSection->Size() - cieOffset, unit != NULL 2105 ? unit->AddressSize() : addressSize); 2106 2107 // length 2108 bool dwarf64; 2109 uint64 length = dataReader.ReadInitialLength(dwarf64); 2110 if (length > (uint64)dataReader.BytesRemaining()) 2111 return B_BAD_DATA; 2112 2113 off_t lengthOffset = dataReader.Offset(); 2114 2115 // CIE ID/CIE pointer 2116 uint64 cieID = dwarf64 2117 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0); 2118 if (usingEHFrameSection) { 2119 if (cieID != 0) 2120 return B_BAD_DATA; 2121 } else { 2122 if (dwarf64 ? cieID != 0xffffffffffffffffULL : cieID != 0xffffffff) 2123 return B_BAD_DATA; 2124 } 2125 2126 uint8 version = dataReader.Read<uint8>(0); 2127 if (version != 1) { 2128 TRACE_CFI(" cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", " 2129 "version: %u -- unsupported\n", length, (uint64)cieOffset, version); 2130 return B_UNSUPPORTED; 2131 } 2132 2133 // read the augmentation string 2134 cieAugmentation.Init(dataReader); 2135 2136 // in the cause of augmentation string "eh", 2137 // the exception table pointer is located immediately before the 2138 // code/data alignment values. We have no use for it so simply skip. 2139 if (strcmp(cieAugmentation.String(), "eh") == 0) 2140 dataReader.Skip(dwarf64 ? sizeof(uint64) : sizeof(uint32)); 2141 2142 context.SetCodeAlignment(dataReader.ReadUnsignedLEB128(0)); 2143 context.SetDataAlignment(dataReader.ReadSignedLEB128(0)); 2144 context.SetReturnAddressRegister(dataReader.ReadUnsignedLEB128(0)); 2145 2146 TRACE_CFI(" cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", version: " 2147 "%u, augmentation: \"%s\", aligment: code: %" B_PRIu32 ", data: %" 2148 B_PRId32 ", return address reg: %" B_PRIu32 "\n", length, 2149 (uint64)cieOffset, version, cieAugmentation.String(), 2150 context.CodeAlignment(), context.DataAlignment(), 2151 context.ReturnAddressRegister()); 2152 2153 status_t error = cieAugmentation.Read(dataReader); 2154 if (error != B_OK) { 2155 TRACE_CFI(" cie: length: %" B_PRIu64 ", version: %u, augmentation: " 2156 "\"%s\" -- unsupported\n", length, version, 2157 cieAugmentation.String()); 2158 return error; 2159 } 2160 2161 if (dataReader.HasOverflow()) 2162 return B_BAD_DATA; 2163 2164 _cieRemaining = length -(dataReader.Offset() - lengthOffset); 2165 if (_cieRemaining < 0) 2166 return B_BAD_DATA; 2167 2168 return B_OK; 2169 } 2170 2171 2172 status_t 2173 DwarfFile::_ParseFrameInfoInstructions(CompilationUnit* unit, 2174 CfaContext& context, DataReader& dataReader, CIEAugmentation& augmentation) 2175 { 2176 while (dataReader.BytesRemaining() > 0) { 2177 TRACE_CFI(" [%2" B_PRId64 "]", dataReader.BytesRemaining()); 2178 2179 uint8 opcode = dataReader.Read<uint8>(0); 2180 if ((opcode >> 6) != 0) { 2181 uint32 operand = opcode & 0x3f; 2182 2183 switch (opcode >> 6) { 2184 case DW_CFA_advance_loc: 2185 { 2186 TRACE_CFI(" DW_CFA_advance_loc: %#" B_PRIx32 "\n", 2187 operand); 2188 2189 target_addr_t location = context.Location() 2190 + operand * context.CodeAlignment(); 2191 if (location > context.TargetLocation()) 2192 return B_OK; 2193 context.SetLocation(location); 2194 break; 2195 } 2196 case DW_CFA_offset: 2197 { 2198 uint64 offset = dataReader.ReadUnsignedLEB128(0); 2199 TRACE_CFI(" DW_CFA_offset: reg: %" B_PRIu32 ", offset: " 2200 "%" B_PRIu64 "\n", operand, offset); 2201 2202 if (CfaRule* rule = context.RegisterRule(operand)) { 2203 rule->SetToLocationOffset( 2204 offset * context.DataAlignment()); 2205 } 2206 break; 2207 } 2208 case DW_CFA_restore: 2209 { 2210 TRACE_CFI(" DW_CFA_restore: %#" B_PRIx32 "\n", operand); 2211 2212 context.RestoreRegisterRule(operand); 2213 break; 2214 } 2215 } 2216 } else { 2217 switch (opcode) { 2218 case DW_CFA_nop: 2219 { 2220 TRACE_CFI(" DW_CFA_nop\n"); 2221 break; 2222 } 2223 case DW_CFA_set_loc: 2224 { 2225 target_addr_t location = augmentation.ReadEncodedAddress( 2226 dataReader, fElfFile, fDebugFrameSection); 2227 2228 TRACE_CFI(" DW_CFA_set_loc: %#" B_PRIx64 "\n", location); 2229 2230 if (location < context.Location()) 2231 return B_BAD_VALUE; 2232 if (location > context.TargetLocation()) 2233 return B_OK; 2234 context.SetLocation(location); 2235 break; 2236 } 2237 case DW_CFA_advance_loc1: 2238 { 2239 uint32 delta = dataReader.Read<uint8>(0); 2240 2241 TRACE_CFI(" DW_CFA_advance_loc1: %#" B_PRIx32 "\n", 2242 delta); 2243 2244 target_addr_t location = context.Location() 2245 + delta * context.CodeAlignment(); 2246 if (location > context.TargetLocation()) 2247 return B_OK; 2248 context.SetLocation(location); 2249 break; 2250 } 2251 case DW_CFA_advance_loc2: 2252 { 2253 uint32 delta = dataReader.Read<uint16>(0); 2254 2255 TRACE_CFI(" DW_CFA_advance_loc2: %#" B_PRIx32 "\n", 2256 delta); 2257 2258 target_addr_t location = context.Location() 2259 + delta * context.CodeAlignment(); 2260 if (location > context.TargetLocation()) 2261 return B_OK; 2262 context.SetLocation(location); 2263 break; 2264 } 2265 case DW_CFA_advance_loc4: 2266 { 2267 uint32 delta = dataReader.Read<uint32>(0); 2268 2269 TRACE_CFI(" DW_CFA_advance_loc4: %#" B_PRIx32 "\n", 2270 delta); 2271 2272 target_addr_t location = context.Location() 2273 + delta * context.CodeAlignment(); 2274 if (location > context.TargetLocation()) 2275 return B_OK; 2276 context.SetLocation(location); 2277 break; 2278 } 2279 case DW_CFA_offset_extended: 2280 { 2281 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2282 uint64 offset = dataReader.ReadUnsignedLEB128(0); 2283 2284 TRACE_CFI(" DW_CFA_offset_extended: reg: %" B_PRIu32 ", " 2285 "offset: %" B_PRIu64 "\n", reg, offset); 2286 2287 if (CfaRule* rule = context.RegisterRule(reg)) { 2288 rule->SetToLocationOffset( 2289 offset * context.DataAlignment()); 2290 } 2291 break; 2292 } 2293 case DW_CFA_restore_extended: 2294 { 2295 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2296 2297 TRACE_CFI(" DW_CFA_restore_extended: %#" B_PRIx32 "\n", 2298 reg); 2299 2300 context.RestoreRegisterRule(reg); 2301 break; 2302 } 2303 case DW_CFA_undefined: 2304 { 2305 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2306 2307 TRACE_CFI(" DW_CFA_undefined: %" B_PRIu32 "\n", reg); 2308 2309 if (CfaRule* rule = context.RegisterRule(reg)) 2310 rule->SetToUndefined(); 2311 break; 2312 } 2313 case DW_CFA_same_value: 2314 { 2315 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2316 2317 TRACE_CFI(" DW_CFA_same_value: %" B_PRIu32 "\n", reg); 2318 2319 if (CfaRule* rule = context.RegisterRule(reg)) 2320 rule->SetToSameValue(); 2321 break; 2322 } 2323 case DW_CFA_register: 2324 { 2325 uint32 reg1 = dataReader.ReadUnsignedLEB128(0); 2326 uint32 reg2 = dataReader.ReadUnsignedLEB128(0); 2327 2328 TRACE_CFI(" DW_CFA_register: reg1: %" B_PRIu32 ", reg2: " 2329 "%" B_PRIu32 "\n", reg1, reg2); 2330 2331 if (CfaRule* rule = context.RegisterRule(reg1)) 2332 rule->SetToValueOffset(reg2); 2333 break; 2334 } 2335 case DW_CFA_remember_state: 2336 { 2337 TRACE_CFI(" DW_CFA_remember_state\n"); 2338 2339 status_t error = context.PushRuleSet(); 2340 if (error != B_OK) 2341 return error; 2342 break; 2343 } 2344 case DW_CFA_restore_state: 2345 { 2346 TRACE_CFI(" DW_CFA_restore_state\n"); 2347 2348 status_t error = context.PopRuleSet(); 2349 if (error != B_OK) 2350 return error; 2351 break; 2352 } 2353 case DW_CFA_def_cfa: 2354 { 2355 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2356 uint64 offset = dataReader.ReadUnsignedLEB128(0); 2357 2358 TRACE_CFI(" DW_CFA_def_cfa: reg: %" B_PRIu32 ", offset: " 2359 "%" B_PRIu64 "\n", reg, offset); 2360 2361 context.GetCfaCfaRule()->SetToRegisterOffset(reg, offset); 2362 break; 2363 } 2364 case DW_CFA_def_cfa_register: 2365 { 2366 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2367 2368 TRACE_CFI(" DW_CFA_def_cfa_register: %" B_PRIu32 "\n", 2369 reg); 2370 2371 if (context.GetCfaCfaRule()->Type() 2372 != CFA_CFA_RULE_REGISTER_OFFSET) { 2373 return B_BAD_DATA; 2374 } 2375 context.GetCfaCfaRule()->SetRegister(reg); 2376 break; 2377 } 2378 case DW_CFA_def_cfa_offset: 2379 { 2380 uint64 offset = dataReader.ReadUnsignedLEB128(0); 2381 2382 TRACE_CFI(" DW_CFA_def_cfa_offset: %" B_PRIu64 "\n", 2383 offset); 2384 2385 if (context.GetCfaCfaRule()->Type() 2386 != CFA_CFA_RULE_REGISTER_OFFSET) { 2387 return B_BAD_DATA; 2388 } 2389 context.GetCfaCfaRule()->SetOffset(offset); 2390 break; 2391 } 2392 case DW_CFA_def_cfa_expression: 2393 { 2394 uint64 blockLength = dataReader.ReadUnsignedLEB128(0); 2395 uint8* block = (uint8*)dataReader.Data(); 2396 dataReader.Skip(blockLength); 2397 2398 TRACE_CFI(" DW_CFA_def_cfa_expression: %p, %" B_PRIu64 2399 "\n", block, blockLength); 2400 2401 context.GetCfaCfaRule()->SetToExpression(block, 2402 blockLength); 2403 break; 2404 } 2405 case DW_CFA_expression: 2406 { 2407 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2408 uint64 blockLength = dataReader.ReadUnsignedLEB128(0); 2409 uint8* block = (uint8*)dataReader.Data(); 2410 dataReader.Skip(blockLength); 2411 2412 TRACE_CFI(" DW_CFA_expression: reg: %" B_PRIu32 ", " 2413 "block: %p, %" B_PRIu64 "\n", reg, block, blockLength); 2414 2415 if (CfaRule* rule = context.RegisterRule(reg)) 2416 rule->SetToLocationExpression(block, blockLength); 2417 break; 2418 } 2419 case DW_CFA_offset_extended_sf: 2420 { 2421 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2422 int64 offset = dataReader.ReadSignedLEB128(0); 2423 2424 TRACE_CFI(" DW_CFA_offset_extended: reg: %" B_PRIu32 ", " 2425 "offset: %" B_PRId64 "\n", reg, offset); 2426 2427 if (CfaRule* rule = context.RegisterRule(reg)) { 2428 rule->SetToLocationOffset( 2429 offset * (int32)context.DataAlignment()); 2430 } 2431 break; 2432 } 2433 case DW_CFA_def_cfa_sf: 2434 { 2435 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2436 int64 offset = dataReader.ReadSignedLEB128(0); 2437 2438 TRACE_CFI(" DW_CFA_def_cfa_sf: reg: %" B_PRIu32 ", " 2439 "offset: %" B_PRId64 "\n", reg, offset); 2440 2441 context.GetCfaCfaRule()->SetToRegisterOffset(reg, 2442 offset * (int32)context.DataAlignment()); 2443 break; 2444 } 2445 case DW_CFA_def_cfa_offset_sf: 2446 { 2447 int64 offset = dataReader.ReadSignedLEB128(0); 2448 2449 TRACE_CFI(" DW_CFA_def_cfa_offset: %" B_PRId64 "\n", 2450 offset); 2451 2452 if (context.GetCfaCfaRule()->Type() 2453 != CFA_CFA_RULE_REGISTER_OFFSET) { 2454 return B_BAD_DATA; 2455 } 2456 context.GetCfaCfaRule()->SetOffset( 2457 offset * (int32)context.DataAlignment()); 2458 break; 2459 } 2460 case DW_CFA_val_offset: 2461 { 2462 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2463 uint64 offset = dataReader.ReadUnsignedLEB128(0); 2464 2465 TRACE_CFI(" DW_CFA_val_offset: reg: %" B_PRIu32 ", " 2466 "offset: %" B_PRIu64 "\n", reg, offset); 2467 2468 if (CfaRule* rule = context.RegisterRule(reg)) { 2469 rule->SetToValueOffset( 2470 offset * context.DataAlignment()); 2471 } 2472 break; 2473 } 2474 case DW_CFA_val_offset_sf: 2475 { 2476 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2477 int64 offset = dataReader.ReadSignedLEB128(0); 2478 2479 TRACE_CFI(" DW_CFA_val_offset_sf: reg: %" B_PRIu32 ", " 2480 "offset: %" B_PRId64 "\n", reg, offset); 2481 2482 if (CfaRule* rule = context.RegisterRule(reg)) { 2483 rule->SetToValueOffset( 2484 offset * (int32)context.DataAlignment()); 2485 } 2486 break; 2487 } 2488 case DW_CFA_val_expression: 2489 { 2490 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2491 uint64 blockLength = dataReader.ReadUnsignedLEB128(0); 2492 uint8* block = (uint8*)dataReader.Data(); 2493 dataReader.Skip(blockLength); 2494 2495 TRACE_CFI(" DW_CFA_val_expression: reg: %" B_PRIu32 ", " 2496 "block: %p, %" B_PRIu64 "\n", reg, block, blockLength); 2497 2498 if (CfaRule* rule = context.RegisterRule(reg)) 2499 rule->SetToValueExpression(block, blockLength); 2500 break; 2501 } 2502 2503 // extensions 2504 case DW_CFA_MIPS_advance_loc8: 2505 { 2506 uint64 delta = dataReader.Read<uint64>(0); 2507 2508 TRACE_CFI(" DW_CFA_MIPS_advance_loc8: %#" B_PRIx64 "\n", 2509 delta); 2510 2511 target_addr_t location = context.Location() 2512 + delta * context.CodeAlignment(); 2513 if (location > context.TargetLocation()) 2514 return B_OK; 2515 context.SetLocation(location); 2516 break; 2517 } 2518 case DW_CFA_GNU_window_save: 2519 { 2520 // SPARC specific, no args 2521 TRACE_CFI(" DW_CFA_GNU_window_save\n"); 2522 2523 // TODO: Implement once we have SPARC support! 2524 break; 2525 } 2526 case DW_CFA_GNU_args_size: 2527 { 2528 // Updates the total size of arguments on the stack. 2529 TRACE_CFI_ONLY(uint64 size =) 2530 dataReader.ReadUnsignedLEB128(0); 2531 2532 TRACE_CFI(" DW_CFA_GNU_args_size: %" B_PRIu64 "\n", 2533 size); 2534 // TODO: Implement! 2535 break; 2536 } 2537 case DW_CFA_GNU_negative_offset_extended: 2538 { 2539 // obsolete 2540 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2541 int64 offset = dataReader.ReadSignedLEB128(0); 2542 2543 TRACE_CFI(" DW_CFA_GNU_negative_offset_extended: " 2544 "reg: %" B_PRIu32 ", offset: %" B_PRId64 "\n", reg, 2545 offset); 2546 2547 if (CfaRule* rule = context.RegisterRule(reg)) { 2548 rule->SetToLocationOffset( 2549 offset * (int32)context.DataAlignment()); 2550 } 2551 break; 2552 } 2553 2554 default: 2555 TRACE_CFI(" unknown opcode %u!\n", opcode); 2556 return B_BAD_DATA; 2557 } 2558 } 2559 } 2560 2561 return B_OK; 2562 } 2563 2564 2565 status_t 2566 DwarfFile::_ParsePublicTypesInfo() 2567 { 2568 TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo()\n"); 2569 if (fDebugPublicTypesSection == NULL) { 2570 TRACE_PUBTYPES(" -> no public types section\n"); 2571 return B_ENTRY_NOT_FOUND; 2572 } 2573 2574 DataReader dataReader((uint8*)fDebugPublicTypesSection->Data(), 2575 fDebugPublicTypesSection->Size(), 4); 2576 // address size doesn't matter at this point 2577 2578 while (dataReader.BytesRemaining() > 0) { 2579 bool dwarf64; 2580 uint64 unitLength = dataReader.ReadInitialLength(dwarf64); 2581 2582 off_t unitLengthOffset = dataReader.Offset(); 2583 // the unitLength starts here 2584 2585 if (dataReader.HasOverflow()) 2586 return B_BAD_DATA; 2587 2588 if (unitLengthOffset + unitLength 2589 > (uint64)fDebugPublicTypesSection->Size()) { 2590 WARNING("Invalid public types set unit length.\n"); 2591 break; 2592 } 2593 2594 DataReader unitDataReader(dataReader.Data(), unitLength, 4); 2595 // address size doesn't matter 2596 _ParsePublicTypesInfo(unitDataReader, dwarf64); 2597 2598 dataReader.SeekAbsolute(unitLengthOffset + unitLength); 2599 } 2600 2601 return B_OK; 2602 } 2603 2604 2605 status_t 2606 DwarfFile::_ParsePublicTypesInfo(DataReader& dataReader, bool dwarf64) 2607 { 2608 int version = dataReader.Read<uint16>(0); 2609 if (version != 2) { 2610 TRACE_PUBTYPES(" pubtypes version %d unsupported\n", version); 2611 return B_UNSUPPORTED; 2612 } 2613 2614 TRACE_PUBTYPES_ONLY(off_t debugInfoOffset =) dwarf64 2615 ? dataReader.Read<uint64>(0) 2616 : (uint64)dataReader.Read<uint32>(0); 2617 TRACE_PUBTYPES_ONLY(off_t debugInfoSize =) dwarf64 2618 ? dataReader.Read<uint64>(0) 2619 : (uint64)dataReader.Read<uint32>(0); 2620 2621 if (dataReader.HasOverflow()) 2622 return B_BAD_DATA; 2623 2624 TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo(): compilation unit debug " 2625 "info: (%" B_PRIdOFF ", %" B_PRIdOFF ")\n", debugInfoOffset, 2626 debugInfoSize); 2627 2628 while (dataReader.BytesRemaining() > 0) { 2629 off_t entryOffset = dwarf64 2630 ? dataReader.Read<uint64>(0) 2631 : (uint64)dataReader.Read<uint32>(0); 2632 if (entryOffset == 0) 2633 return B_OK; 2634 2635 TRACE_PUBTYPES_ONLY(const char* name =) dataReader.ReadString(); 2636 2637 TRACE_PUBTYPES(" \"%s\" -> %" B_PRIdOFF "\n", name, entryOffset); 2638 } 2639 2640 return B_OK; 2641 } 2642 2643 2644 status_t 2645 DwarfFile::_GetAbbreviationTable(off_t offset, AbbreviationTable*& _table) 2646 { 2647 // check, whether we've already loaded it 2648 for (AbbreviationTableList::Iterator it 2649 = fAbbreviationTables.GetIterator(); 2650 AbbreviationTable* table = it.Next();) { 2651 if (offset == table->Offset()) { 2652 _table = table; 2653 return B_OK; 2654 } 2655 } 2656 2657 // create a new table 2658 AbbreviationTable* table = new(std::nothrow) AbbreviationTable(offset); 2659 if (table == NULL) 2660 return B_NO_MEMORY; 2661 2662 status_t error = table->Init(fDebugAbbrevSection->Data(), 2663 fDebugAbbrevSection->Size()); 2664 if (error != B_OK) { 2665 delete table; 2666 return error; 2667 } 2668 2669 fAbbreviationTables.Add(table); 2670 _table = table; 2671 return B_OK; 2672 } 2673 2674 2675 DebugInfoEntry* 2676 DwarfFile::_ResolveReference(BaseUnit* unit, uint64 offset, 2677 uint8 refType) const 2678 { 2679 switch (refType) { 2680 case dwarf_reference_type_local: 2681 return unit->EntryForOffset(offset); 2682 break; 2683 case dwarf_reference_type_global: 2684 { 2685 CompilationUnit* unit = _GetContainingCompilationUnit(offset); 2686 if (unit == NULL) 2687 break; 2688 2689 offset -= unit->HeaderOffset(); 2690 DebugInfoEntry* entry = unit->EntryForOffset(offset); 2691 if (entry != NULL) 2692 return entry; 2693 break; 2694 } 2695 case dwarf_reference_type_signature: 2696 { 2697 TRACE_DIE("Resolving signature %#" B_PRIx64 "\n", offset); 2698 TypeUnitTableEntry* entry = fTypeUnits.Lookup(offset); 2699 if (entry != NULL && entry->unit != NULL) 2700 return entry->unit->TypeEntry(); 2701 break; 2702 } 2703 } 2704 2705 return NULL; 2706 } 2707 2708 2709 status_t 2710 DwarfFile::_GetLocationExpression(CompilationUnit* unit, 2711 const LocationDescription* location, target_addr_t instructionPointer, 2712 const void*& _expression, off_t& _length) const 2713 { 2714 if (!location->IsValid()) 2715 return B_BAD_VALUE; 2716 2717 if (location->IsExpression()) { 2718 _expression = location->expression.data; 2719 _length = location->expression.length; 2720 return B_OK; 2721 } 2722 2723 if (location->IsLocationList() && instructionPointer != 0) { 2724 return _FindLocationExpression(unit, location->listOffset, 2725 instructionPointer, _expression, _length); 2726 } 2727 2728 return B_BAD_VALUE; 2729 } 2730 2731 2732 status_t 2733 DwarfFile::_FindLocationExpression(CompilationUnit* unit, uint64 offset, 2734 target_addr_t address, const void*& _expression, off_t& _length) const 2735 { 2736 if (unit == NULL) 2737 return B_BAD_VALUE; 2738 2739 if (fDebugLocationSection == NULL) 2740 return B_ENTRY_NOT_FOUND; 2741 2742 if (offset < 0 || offset >= (uint64)fDebugLocationSection->Size()) 2743 return B_BAD_DATA; 2744 2745 target_addr_t baseAddress = unit->AddressRangeBase(); 2746 target_addr_t maxAddress = unit->MaxAddress(); 2747 2748 DataReader dataReader((uint8*)fDebugLocationSection->Data() + offset, 2749 fDebugLocationSection->Size() - offset, unit->AddressSize()); 2750 while (true) { 2751 target_addr_t start = dataReader.ReadAddress(0); 2752 target_addr_t end = dataReader.ReadAddress(0); 2753 if (dataReader.HasOverflow()) 2754 return B_BAD_DATA; 2755 2756 if (start == 0 && end == 0) 2757 return B_ENTRY_NOT_FOUND; 2758 2759 if (start == maxAddress) { 2760 baseAddress = end; 2761 continue; 2762 } 2763 2764 uint16 expressionLength = dataReader.Read<uint16>(0); 2765 const void* expression = dataReader.Data(); 2766 if (!dataReader.Skip(expressionLength)) 2767 return B_BAD_DATA; 2768 2769 if (start == end) 2770 continue; 2771 2772 start += baseAddress; 2773 end += baseAddress; 2774 2775 if (address >= start && address < end) { 2776 _expression = expression; 2777 _length = expressionLength; 2778 return B_OK; 2779 } 2780 } 2781 } 2782 2783 2784 status_t 2785 DwarfFile::_LocateDebugInfo(BString& _requiredExternalFileName, 2786 const char* locatedFilePath) 2787 { 2788 ElfFile* debugInfoFile = fElfFile; 2789 ElfSection* debugLinkSection = fElfFile->GetSection(".gnu_debuglink"); 2790 if (debugLinkSection != NULL) { 2791 AutoSectionPutter putter(fElfFile, debugLinkSection); 2792 2793 // the file specifies a debug link, look at its target instead 2794 // for debug information. 2795 // Format: null-terminated filename, as many 0 padding bytes as 2796 // needed to reach the next 32-bit address boundary, followed 2797 // by a 32-bit CRC 2798 2799 BString debugPath; 2800 if (locatedFilePath) 2801 debugPath = locatedFilePath; 2802 else { 2803 status_t result = _GetDebugInfoPath( 2804 (const char*)debugLinkSection->Data(), 2805 _requiredExternalFileName); 2806 if (result != B_OK) 2807 return result; 2808 debugPath = _requiredExternalFileName; 2809 } 2810 2811 if (fAlternateName != NULL) 2812 free(fAlternateName); 2813 2814 fAlternateName = strdup(debugPath.String()); 2815 2816 if (fAlternateName == NULL) 2817 return B_NO_MEMORY; 2818 2819 /* 2820 // TODO: validate CRC 2821 int32 debugCRC = *(int32*)((char*)debugLinkSection->Data() 2822 + debugLinkSection->Size() - sizeof(int32)); 2823 */ 2824 if (fAlternateElfFile == NULL) { 2825 fAlternateElfFile = new(std::nothrow) ElfFile; 2826 if (fAlternateElfFile == NULL) 2827 return B_NO_MEMORY; 2828 } 2829 2830 status_t result = fAlternateElfFile->Init(fAlternateName); 2831 if (result != B_OK) 2832 return result; 2833 2834 debugInfoFile = fAlternateElfFile; 2835 } 2836 2837 // get the interesting sections 2838 fDebugInfoSection = debugInfoFile->GetSection(".debug_info"); 2839 fDebugAbbrevSection = debugInfoFile->GetSection(".debug_abbrev"); 2840 if (fDebugInfoSection == NULL || fDebugAbbrevSection == NULL) { 2841 WARNING("DwarfManager::File::Load(\"%s\"): no " 2842 ".debug_info or .debug_abbrev.\n", fName); 2843 2844 // if we at least have an EH frame, use that for stack unwinding 2845 // if nothing else. 2846 fEHFrameSection = fElfFile->GetSection(".eh_frame"); 2847 if (fEHFrameSection == NULL) 2848 return B_ERROR; 2849 } 2850 2851 return B_OK; 2852 } 2853 2854 2855 status_t 2856 DwarfFile::_GetDebugInfoPath(const char* debugFileName, 2857 BString& _infoPath) const 2858 { 2859 // first, see if we have a relative match to our local directory 2860 BPath basePath; 2861 status_t result = basePath.SetTo(fName); 2862 if (result != B_OK) 2863 return result; 2864 basePath.GetParent(&basePath); 2865 if (strcmp(basePath.Leaf(), "lib") == 0 || strcmp(basePath.Leaf(), 2866 "add-ons") == 0) { 2867 _infoPath.SetToFormat("%s/../debug/%s", basePath.Path(), 2868 debugFileName); 2869 } else 2870 _infoPath.SetToFormat("%s/debug/%s", basePath.Path(), debugFileName); 2871 2872 BEntry entry(_infoPath.String()); 2873 result = entry.InitCheck(); 2874 if (result != B_OK && result != B_ENTRY_NOT_FOUND) 2875 return result; 2876 if (entry.Exists()) 2877 return B_OK; 2878 2879 // If the above search failed, check if our image is located in any 2880 // of the system installation paths, and attempt to locate the debug info 2881 // file in the corresponding well-known location 2882 BString pathSuffix; 2883 pathSuffix.SetToFormat("debug/%s", debugFileName); 2884 2885 BPathFinder finder(fName); 2886 result = finder.FindPath(B_FIND_PATH_DEVELOP_DIRECTORY, 2887 pathSuffix.String(), B_FIND_PATH_EXISTING_ONLY, basePath); 2888 if (result == B_OK) { 2889 _infoPath = basePath.Path(); 2890 return B_OK; 2891 } else { 2892 // if we failed to find a match, then it's up to the user to 2893 // locate it. As such, return the external info file name 2894 // for user interface purposes. 2895 _infoPath.SetTo(debugFileName); 2896 } 2897 2898 return B_ENTRY_NOT_FOUND; 2899 } 2900 2901 2902 TypeUnitTableEntry* 2903 DwarfFile::_GetTypeUnit(uint64 signature) const 2904 { 2905 return fTypeUnits.Lookup(signature); 2906 } 2907 2908 2909 CompilationUnit* 2910 DwarfFile::_GetContainingCompilationUnit(off_t refAddr) const 2911 { 2912 if (fCompilationUnits.IsEmpty()) 2913 return NULL; 2914 2915 // binary search 2916 int lower = 0; 2917 int upper = fCompilationUnits.CountItems() - 1; 2918 while (lower < upper) { 2919 int mid = (lower + upper + 1) / 2; 2920 if (fCompilationUnits.ItemAt(mid)->HeaderOffset() > refAddr) 2921 upper = mid - 1; 2922 else 2923 lower = mid; 2924 } 2925 2926 CompilationUnit* unit = fCompilationUnits.ItemAt(lower); 2927 return unit->ContainsAbsoluteOffset(refAddr) ? unit : NULL; 2928 } 2929 2930 2931 DwarfFile::FDELookupInfo* 2932 DwarfFile::_GetContainingFDEInfo(target_addr_t offset) const 2933 { 2934 FDELookupInfo* info = NULL; 2935 if (fDebugFrameSection != NULL) { 2936 info = _GetContainingFDEInfo(offset, fDebugFrameInfos); 2937 if (info != NULL) 2938 return info; 2939 } 2940 2941 return _GetContainingFDEInfo(offset, fEHFrameInfos); 2942 } 2943 2944 2945 DwarfFile::FDELookupInfo* 2946 DwarfFile::_GetContainingFDEInfo(target_addr_t offset, 2947 const FDEInfoList& infoList) const 2948 { 2949 // binary search 2950 int lower = 0; 2951 int upper = infoList.CountItems() - 1; 2952 if (upper < 0) 2953 return NULL; 2954 2955 while (lower < upper) { 2956 int mid = (lower + upper + 1) / 2; 2957 if (offset < infoList.ItemAt(mid)->start) 2958 upper = mid - 1; 2959 else 2960 lower = mid; 2961 } 2962 2963 FDELookupInfo* info = infoList.ItemAt(lower); 2964 return info->ContainsAddress(offset) ? info : NULL; 2965 } 2966