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 // If the length is 0, it means a terminator of the CIE. 1160 // Then just skip this .debug_frame/.eh_frame section. 1161 if (length == 0) 1162 return B_OK; 1163 1164 // CIE ID/CIE pointer 1165 uint64 cieID = dwarf64 1166 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0); 1167 1168 // In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does. 1169 if (ehFrame 1170 ? cieID == 0 1171 : (dwarf64 1172 ? cieID == 0xffffffffffffffffULL 1173 : cieID == 0xffffffff)) { 1174 // this is a CIE -- skip it 1175 } else { 1176 // this is a FDE 1177 uint64 initialLocationOffset = dataReader.Offset(); 1178 // In .eh_frame the CIE offset is a relative back offset. 1179 if (ehFrame) { 1180 if (cieID > (uint64)lengthOffset) { 1181 TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max " 1182 "possible: %" B_PRIu64 "\n", cieID, lengthOffset); 1183 break; 1184 } 1185 // convert to a section relative offset 1186 cieID = lengthOffset - cieID; 1187 } 1188 1189 1190 CfaContext context; 1191 CIEAugmentation cieAugmentation; 1192 // when using .eh_frame format, we need to parse the CIE's 1193 // augmentation up front in order to know how the FDE's addresses 1194 // will be represented 1195 DataReader cieReader; 1196 off_t cieRemaining; 1197 status_t error = _ParseCIEHeader(section, ehFrame, NULL, 1198 addressSize, context, cieID, cieAugmentation, cieReader, 1199 cieRemaining); 1200 if (error != B_OK) 1201 return error; 1202 if (cieReader.HasOverflow()) 1203 return B_BAD_DATA; 1204 if (cieRemaining < 0) 1205 return B_BAD_DATA; 1206 1207 target_addr_t initialLocation = cieAugmentation.ReadEncodedAddress( 1208 dataReader, fElfFile, section); 1209 target_addr_t addressRange = cieAugmentation.ReadEncodedAddress( 1210 dataReader, fElfFile, section, true); 1211 1212 if (dataReader.HasOverflow()) 1213 return B_BAD_DATA; 1214 1215 if ((cieAugmentation.FDEAddressType() 1216 & CFI_ADDRESS_TYPE_PC_RELATIVE) != 0) { 1217 initialLocation += initialLocationOffset; 1218 } 1219 1220 // for unknown reasons, the debug frame sections generated by gcc 1221 // sometimes contain duplicates at different offsets within the 1222 // section. In such a case, simply skip the duplicates. 1223 FDELookupInfo* temp = _GetContainingFDEInfo(initialLocation, 1224 infos); 1225 if (temp == NULL) { 1226 FDELookupInfo* info = new(std::nothrow)FDELookupInfo( 1227 initialLocation, initialLocation + addressRange - 1, 1228 entryOffset, cieID, ehFrame); 1229 if (info == NULL) 1230 return B_NO_MEMORY; 1231 1232 ObjectDeleter<FDELookupInfo> infoDeleter(info); 1233 if (!infos.BinaryInsert(info, FDELookupInfo::CompareFDEInfos)) 1234 return B_NO_MEMORY; 1235 1236 infoDeleter.Detach(); 1237 } 1238 } 1239 1240 dataReader.SeekAbsolute(lengthOffset + length); 1241 } 1242 1243 return B_OK; 1244 } 1245 1246 1247 status_t 1248 DwarfFile::_ParseCompilationUnit(CompilationUnit* unit) 1249 { 1250 AbbreviationTable* abbreviationTable; 1251 status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(), 1252 abbreviationTable); 1253 if (error != B_OK) 1254 return error; 1255 1256 unit->SetAbbreviationTable(abbreviationTable); 1257 1258 DataReader dataReader( 1259 (const uint8*)fDebugInfoSection->Data() + unit->ContentOffset(), 1260 unit->ContentSize(), unit->AddressSize()); 1261 1262 DebugInfoEntry* entry; 1263 bool endOfEntryList; 1264 error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry, 1265 endOfEntryList); 1266 if (error != B_OK) 1267 return error; 1268 1269 DIECompileUnitBase* unitEntry = dynamic_cast<DIECompileUnitBase*>(entry); 1270 if (unitEntry == NULL) { 1271 WARNING("No compilation unit entry in .debug_info section.\n"); 1272 return B_BAD_DATA; 1273 } 1274 1275 unit->SetUnitEntry(unitEntry); 1276 1277 TRACE_DIE_ONLY( 1278 TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n", 1279 dataReader.BytesRemaining()); 1280 if (dataReader.HasData()) { 1281 TRACE_DIE(" "); 1282 while (dataReader.HasData()) 1283 TRACE_DIE("%02x", dataReader.Read<uint8>(0)); 1284 TRACE_DIE("\n"); 1285 } 1286 ) 1287 return B_OK; 1288 } 1289 1290 1291 status_t 1292 DwarfFile::_ParseTypeUnit(TypeUnit* unit) 1293 { 1294 AbbreviationTable* abbreviationTable; 1295 status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(), 1296 abbreviationTable); 1297 if (error != B_OK) 1298 return error; 1299 1300 unit->SetAbbreviationTable(abbreviationTable); 1301 1302 DataReader dataReader( 1303 (const uint8*)fDebugTypesSection->Data() + unit->ContentOffset(), 1304 unit->ContentSize(), unit->AddressSize()); 1305 1306 DebugInfoEntry* entry; 1307 bool endOfEntryList; 1308 error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry, 1309 endOfEntryList); 1310 if (error != B_OK) 1311 return error; 1312 1313 DIETypeUnit* unitEntry = dynamic_cast<DIETypeUnit*>(entry); 1314 if (unitEntry == NULL) { 1315 WARNING("No type unit entry in .debug_types section.\n"); 1316 return B_BAD_DATA; 1317 } 1318 1319 unit->SetUnitEntry(unitEntry); 1320 DebugInfoEntry* typeEntry = unit->EntryForOffset(unit->TypeOffset()); 1321 if (typeEntry == NULL) { 1322 WARNING("No type found for type unit %p at specified offset %" 1323 B_PRId64 ".\n", unit, unit->TypeOffset()); 1324 return B_BAD_DATA; 1325 } 1326 unit->SetTypeEntry(typeEntry); 1327 1328 TRACE_DIE_ONLY( 1329 TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n", 1330 dataReader.BytesRemaining()); 1331 if (dataReader.HasData()) { 1332 TRACE_DIE(" "); 1333 while (dataReader.HasData()) 1334 TRACE_DIE("%02x", dataReader.Read<uint8>(0)); 1335 TRACE_DIE("\n"); 1336 } 1337 ) 1338 return B_OK; 1339 } 1340 1341 1342 status_t 1343 DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader, 1344 BaseUnit* unit, AbbreviationTable* abbreviationTable, 1345 DebugInfoEntry*& _entry, bool& _endOfEntryList, int level) 1346 { 1347 off_t entryOffset = dataReader.Offset() 1348 + unit->RelativeContentOffset(); 1349 1350 uint32 code = dataReader.ReadUnsignedLEB128(0); 1351 if (code == 0) { 1352 if (dataReader.HasOverflow()) { 1353 WARNING("Unexpected end of .debug_info section.\n"); 1354 return B_BAD_DATA; 1355 } 1356 _entry = NULL; 1357 _endOfEntryList = true; 1358 return B_OK; 1359 } 1360 1361 // get the corresponding abbreviation entry 1362 AbbreviationEntry abbreviationEntry; 1363 if (!abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry)) { 1364 WARNING("No abbreviation entry for code %" B_PRIx32 "\n", code); 1365 return B_BAD_DATA; 1366 } 1367 1368 DebugInfoEntry* entry; 1369 status_t error = fDebugInfoFactory.CreateDebugInfoEntry( 1370 abbreviationEntry.Tag(), entry); 1371 if (error != B_OK) { 1372 WARNING("Failed to generate entry for tag %" B_PRIu32 ", code %" 1373 B_PRIu32 "\n", abbreviationEntry.Tag(), code); 1374 return error; 1375 } 1376 1377 ObjectDeleter<DebugInfoEntry> entryDeleter(entry); 1378 1379 TRACE_DIE("%*sentry %p at %" B_PRIdOFF ": %" B_PRIu32 ", tag: %s (%" 1380 B_PRIu32 "), children: %d\n", level * 2, "", entry, entryOffset, 1381 abbreviationEntry.Code(), get_entry_tag_name(abbreviationEntry.Tag()), 1382 abbreviationEntry.Tag(), abbreviationEntry.HasChildren()); 1383 1384 error = unit->AddDebugInfoEntry(entry, entryOffset); 1385 1386 if (error != B_OK) 1387 return error; 1388 1389 // parse the attributes (supply NULL entry to avoid adding them yet) 1390 error = _ParseEntryAttributes(dataReader, unit, NULL, abbreviationEntry); 1391 if (error != B_OK) 1392 return error; 1393 1394 // parse children, if the entry has any 1395 if (abbreviationEntry.HasChildren()) { 1396 while (true) { 1397 DebugInfoEntry* childEntry; 1398 bool endOfEntryList; 1399 status_t error = _ParseDebugInfoEntry(dataReader, 1400 unit, abbreviationTable, childEntry, endOfEntryList, level + 1); 1401 if (error != B_OK) 1402 return error; 1403 1404 // add the child to our entry 1405 if (childEntry != NULL) { 1406 if (entry != NULL) { 1407 error = entry->AddChild(childEntry); 1408 if (error == B_OK) { 1409 childEntry->SetParent(entry); 1410 } else if (error == ENTRY_NOT_HANDLED) { 1411 error = B_OK; 1412 TRACE_DIE("%*s -> child unhandled\n", level * 2, ""); 1413 } 1414 1415 if (error != B_OK) { 1416 delete childEntry; 1417 return error; 1418 } 1419 } else 1420 delete childEntry; 1421 } 1422 1423 if (endOfEntryList) 1424 break; 1425 } 1426 } 1427 1428 entryDeleter.Detach(); 1429 _entry = entry; 1430 _endOfEntryList = false; 1431 return B_OK; 1432 } 1433 1434 1435 status_t 1436 DwarfFile::_FinishUnit(BaseUnit* unit) 1437 { 1438 CompilationUnit* compilationUnit = dynamic_cast<CompilationUnit*>(unit); 1439 bool isTypeUnit = compilationUnit == NULL; 1440 TRACE_DIE("\nfinishing %s unit %p\n", 1441 isTypeUnit ? "type" : "compilation", unit); 1442 1443 1444 AbbreviationTable* abbreviationTable = unit->GetAbbreviationTable(); 1445 1446 ElfSection* section = isTypeUnit 1447 ? fDebugTypesSection : fDebugInfoSection; 1448 DataReader dataReader( 1449 (const uint8*)section->Data() + unit->HeaderOffset(), 1450 unit->TotalSize(), unit->AddressSize()); 1451 1452 DebugInfoEntryInitInfo entryInitInfo; 1453 1454 int entryCount = unit->CountEntries(); 1455 for (int i = 0; i < entryCount; i++) { 1456 // get the entry 1457 DebugInfoEntry* entry; 1458 off_t offset; 1459 unit->GetEntryAt(i, entry, offset); 1460 1461 TRACE_DIE("entry %p at %" B_PRIdOFF "\n", entry, offset); 1462 1463 // seek the reader to the entry 1464 dataReader.SeekAbsolute(offset); 1465 1466 // read the entry code 1467 uint32 code = dataReader.ReadUnsignedLEB128(0); 1468 1469 // get the respective abbreviation entry 1470 AbbreviationEntry abbreviationEntry; 1471 abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry); 1472 1473 // initialization before setting the attributes 1474 status_t error = entry->InitAfterHierarchy(entryInitInfo); 1475 if (error != B_OK) { 1476 WARNING("Init after hierarchy failed!\n"); 1477 return error; 1478 } 1479 1480 // parse the attributes -- this time pass the entry, so that the 1481 // attribute get set on it 1482 error = _ParseEntryAttributes(dataReader, unit, entry, 1483 abbreviationEntry); 1484 if (error != B_OK) 1485 return error; 1486 1487 // initialization after setting the attributes 1488 error = entry->InitAfterAttributes(entryInitInfo); 1489 if (error != B_OK) { 1490 WARNING("Init after attributes failed!\n"); 1491 return error; 1492 } 1493 } 1494 1495 // set the compilation unit's source language 1496 unit->SetSourceLanguage(entryInitInfo.languageInfo); 1497 1498 if (isTypeUnit) 1499 return B_OK; 1500 1501 // resolve the compilation unit's address range list 1502 if (TargetAddressRangeList* ranges = ResolveRangeList(compilationUnit, 1503 compilationUnit->UnitEntry()->AddressRangesOffset())) { 1504 compilationUnit->SetAddressRanges(ranges); 1505 ranges->ReleaseReference(); 1506 } 1507 1508 // add compilation dir to directory list 1509 const char* compilationDir = compilationUnit->UnitEntry() 1510 ->CompilationDir(); 1511 if (!compilationUnit->AddDirectory(compilationDir != NULL 1512 ? compilationDir : ".")) { 1513 return B_NO_MEMORY; 1514 } 1515 1516 // parse line info header 1517 if (fDebugLineSection != NULL) 1518 _ParseLineInfo(compilationUnit); 1519 1520 return B_OK; 1521 } 1522 1523 1524 status_t 1525 DwarfFile::_ParseEntryAttributes(DataReader& dataReader, 1526 BaseUnit* unit, DebugInfoEntry* entry, AbbreviationEntry& abbreviationEntry) 1527 { 1528 uint32 attributeName; 1529 uint32 attributeForm; 1530 while (abbreviationEntry.GetNextAttribute(attributeName, 1531 attributeForm)) { 1532 // resolve attribute form indirection 1533 if (attributeForm == DW_FORM_indirect) 1534 attributeForm = dataReader.ReadUnsignedLEB128(0); 1535 1536 // prepare an AttributeValue 1537 AttributeValue attributeValue; 1538 attributeValue.attributeForm = attributeForm; 1539 bool isSigned = false; 1540 1541 // Read the attribute value according to the attribute's form. For 1542 // the forms that don't map to a single attribute class only or 1543 // those that need additional processing, we read a temporary value 1544 // first. 1545 uint64 value = 0; 1546 off_t blockLength = 0; 1547 off_t valueOffset = dataReader.Offset() + unit->ContentOffset(); 1548 uint8 refType = dwarf_reference_type_local; 1549 1550 switch (attributeForm) { 1551 case DW_FORM_addr: 1552 value = dataReader.ReadAddress(0); 1553 break; 1554 case DW_FORM_block2: 1555 blockLength = dataReader.Read<uint16>(0); 1556 break; 1557 case DW_FORM_block4: 1558 blockLength = dataReader.Read<uint32>(0); 1559 break; 1560 case DW_FORM_data2: 1561 value = dataReader.Read<uint16>(0); 1562 break; 1563 case DW_FORM_data4: 1564 value = dataReader.Read<uint32>(0); 1565 break; 1566 case DW_FORM_data8: 1567 value = dataReader.Read<uint64>(0); 1568 break; 1569 case DW_FORM_string: 1570 attributeValue.SetToString(dataReader.ReadString()); 1571 break; 1572 case DW_FORM_block: 1573 case DW_FORM_exprloc: 1574 blockLength = dataReader.ReadUnsignedLEB128(0); 1575 break; 1576 case DW_FORM_block1: 1577 blockLength = dataReader.Read<uint8>(0); 1578 break; 1579 case DW_FORM_data1: 1580 value = dataReader.Read<uint8>(0); 1581 break; 1582 case DW_FORM_flag: 1583 attributeValue.SetToFlag(dataReader.Read<uint8>(0) != 0); 1584 break; 1585 case DW_FORM_sdata: 1586 value = dataReader.ReadSignedLEB128(0); 1587 isSigned = true; 1588 break; 1589 case DW_FORM_strp: 1590 { 1591 if (fDebugStringSection != NULL) { 1592 uint64 offset = unit->IsDwarf64() 1593 ? dataReader.Read<uint64>(0) 1594 : dataReader.Read<uint32>(0); 1595 if (offset >= fDebugStringSection->Size()) { 1596 WARNING("Invalid DW_FORM_strp offset: %" B_PRIu64 "\n", 1597 offset); 1598 return B_BAD_DATA; 1599 } 1600 attributeValue.SetToString( 1601 (const char*)fDebugStringSection->Data() + offset); 1602 } else { 1603 WARNING("Invalid DW_FORM_strp: no string section!\n"); 1604 return B_BAD_DATA; 1605 } 1606 break; 1607 } 1608 case DW_FORM_udata: 1609 value = dataReader.ReadUnsignedLEB128(0); 1610 break; 1611 case DW_FORM_ref_addr: 1612 value = unit->IsDwarf64() 1613 ? dataReader.Read<uint64>(0) 1614 : (uint64)dataReader.Read<uint32>(0); 1615 refType = dwarf_reference_type_global; 1616 break; 1617 case DW_FORM_ref1: 1618 value = dataReader.Read<uint8>(0); 1619 break; 1620 case DW_FORM_ref2: 1621 value = dataReader.Read<uint16>(0); 1622 break; 1623 case DW_FORM_ref4: 1624 value = dataReader.Read<uint32>(0); 1625 break; 1626 case DW_FORM_ref8: 1627 value = dataReader.Read<uint64>(0); 1628 break; 1629 case DW_FORM_ref_udata: 1630 value = dataReader.ReadUnsignedLEB128(0); 1631 break; 1632 case DW_FORM_flag_present: 1633 attributeValue.SetToFlag(true); 1634 break; 1635 case DW_FORM_ref_sig8: 1636 fTypesSectionRequired = true; 1637 value = dataReader.Read<uint64>(0); 1638 refType = dwarf_reference_type_signature; 1639 break; 1640 case DW_FORM_sec_offset: 1641 value = unit->IsDwarf64() 1642 ? dataReader.Read<uint64>(0) 1643 : (uint64)dataReader.Read<uint32>(0); 1644 break; 1645 case DW_FORM_indirect: 1646 default: 1647 WARNING("Unsupported attribute form: %" B_PRIu32 "\n", 1648 attributeForm); 1649 return B_BAD_DATA; 1650 } 1651 1652 // get the attribute class -- skip the attribute, if we can't handle 1653 // it 1654 uint8 attributeClass = get_attribute_class(attributeName, 1655 attributeForm); 1656 1657 if (attributeClass == ATTRIBUTE_CLASS_UNKNOWN) { 1658 TRACE_DIE("skipping attribute with unrecognized class: %s (%#" 1659 B_PRIx32 ") %s (%#" B_PRIx32 ")\n", 1660 get_attribute_name_name(attributeName), attributeName, 1661 get_attribute_form_name(attributeForm), attributeForm); 1662 continue; 1663 } 1664 1665 // set the attribute value according to the attribute's class 1666 switch (attributeClass) { 1667 case ATTRIBUTE_CLASS_ADDRESS: 1668 attributeValue.SetToAddress(value); 1669 break; 1670 case ATTRIBUTE_CLASS_BLOCK: 1671 attributeValue.SetToBlock(dataReader.Data(), blockLength); 1672 dataReader.Skip(blockLength); 1673 break; 1674 case ATTRIBUTE_CLASS_CONSTANT: 1675 attributeValue.SetToConstant(value, isSigned); 1676 break; 1677 case ATTRIBUTE_CLASS_LINEPTR: 1678 attributeValue.SetToLinePointer(value); 1679 break; 1680 case ATTRIBUTE_CLASS_LOCLISTPTR: 1681 attributeValue.SetToLocationListPointer(value); 1682 break; 1683 case ATTRIBUTE_CLASS_MACPTR: 1684 attributeValue.SetToMacroPointer(value); 1685 break; 1686 case ATTRIBUTE_CLASS_RANGELISTPTR: 1687 attributeValue.SetToRangeListPointer(value); 1688 break; 1689 case ATTRIBUTE_CLASS_REFERENCE: 1690 if (entry != NULL) { 1691 attributeValue.SetToReference(_ResolveReference( 1692 unit, value, refType)); 1693 if (attributeValue.reference == NULL) { 1694 // gcc 2 apparently somtimes produces DW_AT_sibling 1695 // attributes pointing to the end of the sibling list. 1696 // Just ignore those. 1697 if (attributeName == DW_AT_sibling) 1698 continue; 1699 1700 WARNING("Failed to resolve reference on entry %p: " 1701 "(%#" B_PRIx64 ") %s (%#" B_PRIx32 ") %s " 1702 "(%#" B_PRIx32 "): value: %#" B_PRIx64 "\n", 1703 entry, 1704 valueOffset, 1705 get_attribute_name_name(attributeName), 1706 attributeName, 1707 get_attribute_form_name(attributeForm), 1708 attributeForm, value); 1709 return B_ENTRY_NOT_FOUND; 1710 } 1711 } 1712 break; 1713 case ATTRIBUTE_CLASS_FLAG: 1714 case ATTRIBUTE_CLASS_STRING: 1715 // already set 1716 break; 1717 } 1718 1719 if (dataReader.HasOverflow()) { 1720 WARNING("Unexpected end of .debug_info section.\n"); 1721 return B_BAD_DATA; 1722 } 1723 1724 TRACE_DIE_ONLY( 1725 char buffer[1024]; 1726 TRACE_DIE(" attr (%#" B_PRIx64 ") %s %s (%d): %s\n", 1727 valueOffset, 1728 get_attribute_name_name(attributeName), 1729 get_attribute_form_name(attributeForm), attributeClass, 1730 attributeValue.ToString(buffer, sizeof(buffer))); 1731 ) 1732 1733 // add the attribute 1734 if (entry != NULL) { 1735 DebugInfoEntrySetter attributeSetter 1736 = get_attribute_name_setter(attributeName); 1737 if (attributeSetter != 0) { 1738 status_t error = (entry->*attributeSetter)(attributeName, 1739 attributeValue); 1740 1741 if (error == ATTRIBUTE_NOT_HANDLED) { 1742 error = B_OK; 1743 TRACE_DIE(" -> unhandled\n"); 1744 } 1745 1746 if (error != B_OK) { 1747 WARNING("Failed to set attribute: name: %s, form: %s: %s\n", 1748 get_attribute_name_name(attributeName), 1749 get_attribute_form_name(attributeForm), 1750 strerror(error)); 1751 } 1752 } else 1753 TRACE_DIE(" -> no attribute setter!\n"); 1754 } 1755 } 1756 1757 return B_OK; 1758 } 1759 1760 1761 status_t 1762 DwarfFile::_ParseLineInfo(CompilationUnit* unit) 1763 { 1764 off_t offset = unit->UnitEntry()->StatementListOffset(); 1765 1766 TRACE_LINES("DwarfFile::_ParseLineInfo(%p), offset: %" B_PRIdOFF "\n", unit, 1767 offset); 1768 1769 DataReader dataReader((uint8*)fDebugLineSection->Data() + offset, 1770 fDebugLineSection->Size() - offset, unit->AddressSize()); 1771 1772 // unit length 1773 bool dwarf64; 1774 uint64 unitLength = dataReader.ReadInitialLength(dwarf64); 1775 if (unitLength > (uint64)dataReader.BytesRemaining()) 1776 return B_BAD_DATA; 1777 off_t unitOffset = dataReader.Offset(); 1778 1779 // version (uhalf) 1780 uint16 version = dataReader.Read<uint16>(0); 1781 1782 // header_length (4/8) 1783 uint64 headerLength = dwarf64 1784 ? dataReader.Read<uint64>(0) : (uint64)dataReader.Read<uint32>(0); 1785 off_t headerOffset = dataReader.Offset(); 1786 1787 if ((uint64)dataReader.BytesRemaining() < headerLength) 1788 return B_BAD_DATA; 1789 1790 // minimum instruction length 1791 uint8 minInstructionLength = dataReader.Read<uint8>(0); 1792 1793 // default is statement 1794 bool defaultIsStatement = dataReader.Read<uint8>(0) != 0; 1795 1796 // line_base (sbyte) 1797 int8 lineBase = (int8)dataReader.Read<uint8>(0); 1798 1799 // line_range (ubyte) 1800 uint8 lineRange = dataReader.Read<uint8>(0); 1801 1802 // opcode_base (ubyte) 1803 uint8 opcodeBase = dataReader.Read<uint8>(0); 1804 1805 // standard_opcode_lengths (ubyte[]) 1806 const uint8* standardOpcodeLengths = (const uint8*)dataReader.Data(); 1807 dataReader.Skip(opcodeBase - 1); 1808 1809 if (dataReader.HasOverflow()) 1810 return B_BAD_DATA; 1811 1812 if (version != 2 && version != 3) 1813 return B_UNSUPPORTED; 1814 1815 TRACE_LINES(" unitLength: %" B_PRIu64 "\n", unitLength); 1816 TRACE_LINES(" version: %u\n", version); 1817 TRACE_LINES(" headerLength: %" B_PRIu64 "\n", headerLength); 1818 TRACE_LINES(" minInstructionLength: %u\n", minInstructionLength); 1819 TRACE_LINES(" defaultIsStatement: %d\n", defaultIsStatement); 1820 TRACE_LINES(" lineBase: %d\n", lineBase); 1821 TRACE_LINES(" lineRange: %u\n", lineRange); 1822 TRACE_LINES(" opcodeBase: %u\n", opcodeBase); 1823 1824 // include directories 1825 TRACE_LINES(" include directories:\n"); 1826 while (const char* directory = dataReader.ReadString()) { 1827 if (*directory == '\0') 1828 break; 1829 TRACE_LINES(" \"%s\"\n", directory); 1830 1831 if (!unit->AddDirectory(directory)) 1832 return B_NO_MEMORY; 1833 } 1834 1835 // file names 1836 TRACE_LINES(" files:\n"); 1837 while (const char* file = dataReader.ReadString()) { 1838 if (*file == '\0') 1839 break; 1840 uint64 dirIndex = dataReader.ReadUnsignedLEB128(0); 1841 TRACE_LINES_ONLY(uint64 modificationTime =) 1842 dataReader.ReadUnsignedLEB128(0); 1843 TRACE_LINES_ONLY(uint64 fileLength =) 1844 dataReader.ReadUnsignedLEB128(0); 1845 1846 if (dataReader.HasOverflow()) 1847 return B_BAD_DATA; 1848 1849 TRACE_LINES(" \"%s\", dir index: %" B_PRIu64 ", mtime: %" B_PRIu64 1850 ", length: %" B_PRIu64 "\n", file, dirIndex, modificationTime, 1851 fileLength); 1852 1853 if (!unit->AddFile(file, dirIndex)) 1854 return B_NO_MEMORY; 1855 } 1856 1857 off_t readerOffset = dataReader.Offset(); 1858 if ((uint64)readerOffset > readerOffset + headerLength) 1859 return B_BAD_DATA; 1860 off_t offsetToProgram = headerOffset + headerLength - readerOffset; 1861 1862 const uint8* program = (uint8*)dataReader.Data() + offsetToProgram; 1863 size_t programSize = unitLength - (readerOffset - unitOffset); 1864 1865 return unit->GetLineNumberProgram().Init(program, programSize, 1866 minInstructionLength, defaultIsStatement, lineBase, lineRange, 1867 opcodeBase, standardOpcodeLengths); 1868 } 1869 1870 1871 status_t 1872 DwarfFile::_UnwindCallFrame(CompilationUnit* unit, uint8 addressSize, 1873 DIESubprogram* subprogramEntry, target_addr_t location, 1874 const FDELookupInfo* info, const DwarfTargetInterface* inputInterface, 1875 DwarfTargetInterface* outputInterface, target_addr_t& _framePointer) 1876 { 1877 ElfSection* currentFrameSection = (info->ehFrame) 1878 ? fEHFrameSection : fDebugFrameSection; 1879 1880 TRACE_CFI("DwarfFile::_UnwindCallFrame(%#" B_PRIx64 ")\n", location); 1881 1882 DataReader dataReader((uint8*)currentFrameSection->Data(), 1883 currentFrameSection->Size(), unit != NULL 1884 ? unit->AddressSize() : addressSize); 1885 dataReader.SeekAbsolute(info->fdeOffset); 1886 1887 bool dwarf64; 1888 uint64 length = dataReader.ReadInitialLength(dwarf64); 1889 uint64 lengthOffset = dataReader.Offset(); 1890 1891 CfaContext context; 1892 CIEAugmentation cieAugmentation; 1893 // when using .eh_frame format, we need to parse the CIE's 1894 // augmentation up front in order to know how the FDE's addresses 1895 // will be represented 1896 DataReader cieReader; 1897 off_t cieRemaining; 1898 status_t error = _ParseCIEHeader(currentFrameSection, 1899 info->ehFrame, unit, addressSize, context, info->cieOffset, 1900 cieAugmentation, cieReader, cieRemaining); 1901 if (error != B_OK) 1902 return error; 1903 if (cieReader.HasOverflow()) 1904 return B_BAD_DATA; 1905 if (cieRemaining < 0) 1906 return B_BAD_DATA; 1907 1908 // skip CIE ID, initial offset and range, since we already know those 1909 // from FDELookupInfo. 1910 dwarf64 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0); 1911 cieAugmentation.ReadEncodedAddress(dataReader, fElfFile, 1912 currentFrameSection); 1913 cieAugmentation.ReadEncodedAddress(dataReader, fElfFile, 1914 currentFrameSection, true); 1915 1916 TRACE_CFI(" found fde: length: %" B_PRIu64 " (%" B_PRIdOFF 1917 "), CIE offset: %#" B_PRIx64 ", location: %#" B_PRIx64 ", " 1918 "range: %#" B_PRIx64 "\n", length, dataReader.BytesRemaining(), 1919 info->cieOffset, info->start, info->end - info->start); 1920 1921 context.SetLocation(location, info->start); 1922 uint32 registerCount = outputInterface->CountRegisters(); 1923 error = context.Init(registerCount); 1924 if (error != B_OK) 1925 return error; 1926 1927 error = outputInterface->InitRegisterRules(context); 1928 if (error != B_OK) 1929 return error; 1930 1931 // process the CIE's frame info instructions 1932 cieReader = cieReader.RestrictedReader(cieRemaining); 1933 error = _ParseFrameInfoInstructions(unit, context, 1934 cieReader, cieAugmentation); 1935 if (error != B_OK) 1936 return error; 1937 1938 // read the FDE augmentation data (if any) 1939 FDEAugmentation fdeAugmentation; 1940 error = cieAugmentation.ReadFDEData(dataReader, 1941 fdeAugmentation); 1942 if (error != B_OK) { 1943 TRACE_CFI(" failed to read FDE augmentation data!\n"); 1944 return error; 1945 } 1946 1947 error = context.SaveInitialRuleSet(); 1948 if (error != B_OK) 1949 return error; 1950 1951 uint64 remaining = lengthOffset + length - dataReader.Offset(); 1952 if (remaining < 0) 1953 return B_BAD_DATA; 1954 1955 DataReader restrictedReader = 1956 dataReader.RestrictedReader(remaining); 1957 error = _ParseFrameInfoInstructions(unit, context, 1958 restrictedReader, cieAugmentation); 1959 if (error != B_OK) 1960 return error; 1961 1962 TRACE_CFI(" found row!\n"); 1963 1964 // apply the rules of the final row 1965 // get the frameAddress first 1966 target_addr_t frameAddress; 1967 CfaCfaRule* cfaCfaRule = context.GetCfaCfaRule(); 1968 switch (cfaCfaRule->Type()) { 1969 case CFA_CFA_RULE_REGISTER_OFFSET: 1970 { 1971 BVariant value; 1972 if (!inputInterface->GetRegisterValue( 1973 cfaCfaRule->Register(), value) 1974 || !value.IsNumber()) { 1975 return B_UNSUPPORTED; 1976 } 1977 frameAddress = value.ToUInt64() + cfaCfaRule->Offset(); 1978 break; 1979 } 1980 case CFA_CFA_RULE_EXPRESSION: 1981 { 1982 error = EvaluateExpression(unit, addressSize, 1983 subprogramEntry, 1984 cfaCfaRule->Expression().block, 1985 cfaCfaRule->Expression().size, 1986 inputInterface, location, 0, 0, false, 1987 frameAddress); 1988 if (error != B_OK) 1989 return error; 1990 break; 1991 } 1992 case CFA_CFA_RULE_UNDEFINED: 1993 default: 1994 return B_BAD_VALUE; 1995 } 1996 1997 TRACE_CFI(" frame address: %#" B_PRIx64 "\n", frameAddress); 1998 1999 // apply the register rules 2000 for (uint32 i = 0; i < registerCount; i++) { 2001 TRACE_CFI(" reg %" B_PRIu32 "\n", i); 2002 2003 uint32 valueType = outputInterface->RegisterValueType(i); 2004 if (valueType == 0) 2005 continue; 2006 2007 CfaRule* rule = context.RegisterRule(i); 2008 if (rule == NULL) 2009 continue; 2010 2011 // apply the rule 2012 switch (rule->Type()) { 2013 case CFA_RULE_SAME_VALUE: 2014 { 2015 TRACE_CFI(" -> CFA_RULE_SAME_VALUE\n"); 2016 2017 BVariant value; 2018 if (inputInterface->GetRegisterValue(i, value)) 2019 outputInterface->SetRegisterValue(i, value); 2020 break; 2021 } 2022 case CFA_RULE_LOCATION_OFFSET: 2023 { 2024 TRACE_CFI(" -> CFA_RULE_LOCATION_OFFSET: %" 2025 B_PRId64 "\n", rule->Offset()); 2026 2027 BVariant value; 2028 if (inputInterface->ReadValueFromMemory( 2029 frameAddress + rule->Offset(), valueType, 2030 value)) { 2031 outputInterface->SetRegisterValue(i, value); 2032 } 2033 break; 2034 } 2035 case CFA_RULE_VALUE_OFFSET: 2036 TRACE_CFI(" -> CFA_RULE_VALUE_OFFSET\n"); 2037 2038 outputInterface->SetRegisterValue(i, 2039 frameAddress + rule->Offset()); 2040 break; 2041 case CFA_RULE_REGISTER: 2042 { 2043 TRACE_CFI(" -> CFA_RULE_REGISTER\n"); 2044 2045 BVariant value; 2046 if (inputInterface->GetRegisterValue( 2047 rule->Register(), value)) { 2048 outputInterface->SetRegisterValue(i, value); 2049 } 2050 break; 2051 } 2052 case CFA_RULE_LOCATION_EXPRESSION: 2053 { 2054 TRACE_CFI(" -> CFA_RULE_LOCATION_EXPRESSION\n"); 2055 2056 target_addr_t address; 2057 error = EvaluateExpression(unit, addressSize, 2058 subprogramEntry, 2059 rule->Expression().block, 2060 rule->Expression().size, 2061 inputInterface, location, frameAddress, 2062 frameAddress, true, address); 2063 BVariant value; 2064 if (error == B_OK 2065 && inputInterface->ReadValueFromMemory(address, 2066 valueType, value)) { 2067 outputInterface->SetRegisterValue(i, value); 2068 } 2069 break; 2070 } 2071 case CFA_RULE_VALUE_EXPRESSION: 2072 { 2073 TRACE_CFI(" -> CFA_RULE_VALUE_EXPRESSION\n"); 2074 2075 target_addr_t value; 2076 error = EvaluateExpression(unit, addressSize, 2077 subprogramEntry, 2078 rule->Expression().block, 2079 rule->Expression().size, 2080 inputInterface, location, frameAddress, 2081 frameAddress, true, value); 2082 if (error == B_OK) 2083 outputInterface->SetRegisterValue(i, value); 2084 break; 2085 } 2086 case CFA_RULE_UNDEFINED: 2087 TRACE_CFI(" -> CFA_RULE_UNDEFINED\n"); 2088 default: 2089 break; 2090 } 2091 } 2092 2093 _framePointer = frameAddress; 2094 2095 return B_OK; 2096 } 2097 2098 2099 status_t 2100 DwarfFile::_ParseCIEHeader(ElfSection* debugFrameSection, 2101 bool usingEHFrameSection, CompilationUnit* unit, uint8 addressSize, 2102 CfaContext& context, off_t cieOffset, CIEAugmentation& cieAugmentation, 2103 DataReader& dataReader, off_t& _cieRemaining) 2104 { 2105 if (cieOffset < 0 || (uint64)cieOffset >= debugFrameSection->Size()) 2106 return B_BAD_DATA; 2107 2108 dataReader.SetTo((uint8*)debugFrameSection->Data() + cieOffset, 2109 debugFrameSection->Size() - cieOffset, unit != NULL 2110 ? unit->AddressSize() : addressSize); 2111 2112 // length 2113 bool dwarf64; 2114 uint64 length = dataReader.ReadInitialLength(dwarf64); 2115 if (length > (uint64)dataReader.BytesRemaining()) 2116 return B_BAD_DATA; 2117 2118 off_t lengthOffset = dataReader.Offset(); 2119 2120 // CIE ID/CIE pointer 2121 uint64 cieID = dwarf64 2122 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0); 2123 if (usingEHFrameSection) { 2124 if (cieID != 0) 2125 return B_BAD_DATA; 2126 } else { 2127 if (dwarf64 ? cieID != 0xffffffffffffffffULL : cieID != 0xffffffff) 2128 return B_BAD_DATA; 2129 } 2130 2131 uint8 version = dataReader.Read<uint8>(0); 2132 if (version != 1) { 2133 TRACE_CFI(" cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", " 2134 "version: %u -- unsupported\n", length, (uint64)cieOffset, version); 2135 return B_UNSUPPORTED; 2136 } 2137 2138 // read the augmentation string 2139 cieAugmentation.Init(dataReader); 2140 2141 // in the cause of augmentation string "eh", 2142 // the exception table pointer is located immediately before the 2143 // code/data alignment values. We have no use for it so simply skip. 2144 if (strcmp(cieAugmentation.String(), "eh") == 0) 2145 dataReader.Skip(dwarf64 ? sizeof(uint64) : sizeof(uint32)); 2146 2147 context.SetCodeAlignment(dataReader.ReadUnsignedLEB128(0)); 2148 context.SetDataAlignment(dataReader.ReadSignedLEB128(0)); 2149 context.SetReturnAddressRegister(dataReader.ReadUnsignedLEB128(0)); 2150 2151 TRACE_CFI(" cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", version: " 2152 "%u, augmentation: \"%s\", aligment: code: %" B_PRIu32 ", data: %" 2153 B_PRId32 ", return address reg: %" B_PRIu32 "\n", length, 2154 (uint64)cieOffset, version, cieAugmentation.String(), 2155 context.CodeAlignment(), context.DataAlignment(), 2156 context.ReturnAddressRegister()); 2157 2158 status_t error = cieAugmentation.Read(dataReader); 2159 if (error != B_OK) { 2160 TRACE_CFI(" cie: length: %" B_PRIu64 ", version: %u, augmentation: " 2161 "\"%s\" -- unsupported\n", length, version, 2162 cieAugmentation.String()); 2163 return error; 2164 } 2165 2166 if (dataReader.HasOverflow()) 2167 return B_BAD_DATA; 2168 2169 _cieRemaining = length -(dataReader.Offset() - lengthOffset); 2170 if (_cieRemaining < 0) 2171 return B_BAD_DATA; 2172 2173 return B_OK; 2174 } 2175 2176 2177 status_t 2178 DwarfFile::_ParseFrameInfoInstructions(CompilationUnit* unit, 2179 CfaContext& context, DataReader& dataReader, CIEAugmentation& augmentation) 2180 { 2181 while (dataReader.BytesRemaining() > 0) { 2182 TRACE_CFI(" [%2" B_PRId64 "]", dataReader.BytesRemaining()); 2183 2184 uint8 opcode = dataReader.Read<uint8>(0); 2185 if ((opcode >> 6) != 0) { 2186 uint32 operand = opcode & 0x3f; 2187 2188 switch (opcode >> 6) { 2189 case DW_CFA_advance_loc: 2190 { 2191 TRACE_CFI(" DW_CFA_advance_loc: %#" B_PRIx32 "\n", 2192 operand); 2193 2194 target_addr_t location = context.Location() 2195 + operand * context.CodeAlignment(); 2196 if (location > context.TargetLocation()) 2197 return B_OK; 2198 context.SetLocation(location); 2199 break; 2200 } 2201 case DW_CFA_offset: 2202 { 2203 uint64 offset = dataReader.ReadUnsignedLEB128(0); 2204 TRACE_CFI(" DW_CFA_offset: reg: %" B_PRIu32 ", offset: " 2205 "%" B_PRIu64 "\n", operand, offset); 2206 2207 if (CfaRule* rule = context.RegisterRule(operand)) { 2208 rule->SetToLocationOffset( 2209 offset * context.DataAlignment()); 2210 } 2211 break; 2212 } 2213 case DW_CFA_restore: 2214 { 2215 TRACE_CFI(" DW_CFA_restore: %#" B_PRIx32 "\n", operand); 2216 2217 context.RestoreRegisterRule(operand); 2218 break; 2219 } 2220 } 2221 } else { 2222 switch (opcode) { 2223 case DW_CFA_nop: 2224 { 2225 TRACE_CFI(" DW_CFA_nop\n"); 2226 break; 2227 } 2228 case DW_CFA_set_loc: 2229 { 2230 target_addr_t location = augmentation.ReadEncodedAddress( 2231 dataReader, fElfFile, fDebugFrameSection); 2232 2233 TRACE_CFI(" DW_CFA_set_loc: %#" B_PRIx64 "\n", location); 2234 2235 if (location < context.Location()) 2236 return B_BAD_VALUE; 2237 if (location > context.TargetLocation()) 2238 return B_OK; 2239 context.SetLocation(location); 2240 break; 2241 } 2242 case DW_CFA_advance_loc1: 2243 { 2244 uint32 delta = dataReader.Read<uint8>(0); 2245 2246 TRACE_CFI(" DW_CFA_advance_loc1: %#" B_PRIx32 "\n", 2247 delta); 2248 2249 target_addr_t location = context.Location() 2250 + delta * context.CodeAlignment(); 2251 if (location > context.TargetLocation()) 2252 return B_OK; 2253 context.SetLocation(location); 2254 break; 2255 } 2256 case DW_CFA_advance_loc2: 2257 { 2258 uint32 delta = dataReader.Read<uint16>(0); 2259 2260 TRACE_CFI(" DW_CFA_advance_loc2: %#" B_PRIx32 "\n", 2261 delta); 2262 2263 target_addr_t location = context.Location() 2264 + delta * context.CodeAlignment(); 2265 if (location > context.TargetLocation()) 2266 return B_OK; 2267 context.SetLocation(location); 2268 break; 2269 } 2270 case DW_CFA_advance_loc4: 2271 { 2272 uint32 delta = dataReader.Read<uint32>(0); 2273 2274 TRACE_CFI(" DW_CFA_advance_loc4: %#" B_PRIx32 "\n", 2275 delta); 2276 2277 target_addr_t location = context.Location() 2278 + delta * context.CodeAlignment(); 2279 if (location > context.TargetLocation()) 2280 return B_OK; 2281 context.SetLocation(location); 2282 break; 2283 } 2284 case DW_CFA_offset_extended: 2285 { 2286 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2287 uint64 offset = dataReader.ReadUnsignedLEB128(0); 2288 2289 TRACE_CFI(" DW_CFA_offset_extended: reg: %" B_PRIu32 ", " 2290 "offset: %" B_PRIu64 "\n", reg, offset); 2291 2292 if (CfaRule* rule = context.RegisterRule(reg)) { 2293 rule->SetToLocationOffset( 2294 offset * context.DataAlignment()); 2295 } 2296 break; 2297 } 2298 case DW_CFA_restore_extended: 2299 { 2300 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2301 2302 TRACE_CFI(" DW_CFA_restore_extended: %#" B_PRIx32 "\n", 2303 reg); 2304 2305 context.RestoreRegisterRule(reg); 2306 break; 2307 } 2308 case DW_CFA_undefined: 2309 { 2310 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2311 2312 TRACE_CFI(" DW_CFA_undefined: %" B_PRIu32 "\n", reg); 2313 2314 if (CfaRule* rule = context.RegisterRule(reg)) 2315 rule->SetToUndefined(); 2316 break; 2317 } 2318 case DW_CFA_same_value: 2319 { 2320 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2321 2322 TRACE_CFI(" DW_CFA_same_value: %" B_PRIu32 "\n", reg); 2323 2324 if (CfaRule* rule = context.RegisterRule(reg)) 2325 rule->SetToSameValue(); 2326 break; 2327 } 2328 case DW_CFA_register: 2329 { 2330 uint32 reg1 = dataReader.ReadUnsignedLEB128(0); 2331 uint32 reg2 = dataReader.ReadUnsignedLEB128(0); 2332 2333 TRACE_CFI(" DW_CFA_register: reg1: %" B_PRIu32 ", reg2: " 2334 "%" B_PRIu32 "\n", reg1, reg2); 2335 2336 if (CfaRule* rule = context.RegisterRule(reg1)) 2337 rule->SetToValueOffset(reg2); 2338 break; 2339 } 2340 case DW_CFA_remember_state: 2341 { 2342 TRACE_CFI(" DW_CFA_remember_state\n"); 2343 2344 status_t error = context.PushRuleSet(); 2345 if (error != B_OK) 2346 return error; 2347 break; 2348 } 2349 case DW_CFA_restore_state: 2350 { 2351 TRACE_CFI(" DW_CFA_restore_state\n"); 2352 2353 status_t error = context.PopRuleSet(); 2354 if (error != B_OK) 2355 return error; 2356 break; 2357 } 2358 case DW_CFA_def_cfa: 2359 { 2360 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2361 uint64 offset = dataReader.ReadUnsignedLEB128(0); 2362 2363 TRACE_CFI(" DW_CFA_def_cfa: reg: %" B_PRIu32 ", offset: " 2364 "%" B_PRIu64 "\n", reg, offset); 2365 2366 context.GetCfaCfaRule()->SetToRegisterOffset(reg, offset); 2367 break; 2368 } 2369 case DW_CFA_def_cfa_register: 2370 { 2371 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2372 2373 TRACE_CFI(" DW_CFA_def_cfa_register: %" B_PRIu32 "\n", 2374 reg); 2375 2376 if (context.GetCfaCfaRule()->Type() 2377 != CFA_CFA_RULE_REGISTER_OFFSET) { 2378 return B_BAD_DATA; 2379 } 2380 context.GetCfaCfaRule()->SetRegister(reg); 2381 break; 2382 } 2383 case DW_CFA_def_cfa_offset: 2384 { 2385 uint64 offset = dataReader.ReadUnsignedLEB128(0); 2386 2387 TRACE_CFI(" DW_CFA_def_cfa_offset: %" B_PRIu64 "\n", 2388 offset); 2389 2390 if (context.GetCfaCfaRule()->Type() 2391 != CFA_CFA_RULE_REGISTER_OFFSET) { 2392 return B_BAD_DATA; 2393 } 2394 context.GetCfaCfaRule()->SetOffset(offset); 2395 break; 2396 } 2397 case DW_CFA_def_cfa_expression: 2398 { 2399 uint64 blockLength = dataReader.ReadUnsignedLEB128(0); 2400 uint8* block = (uint8*)dataReader.Data(); 2401 dataReader.Skip(blockLength); 2402 2403 TRACE_CFI(" DW_CFA_def_cfa_expression: %p, %" B_PRIu64 2404 "\n", block, blockLength); 2405 2406 context.GetCfaCfaRule()->SetToExpression(block, 2407 blockLength); 2408 break; 2409 } 2410 case DW_CFA_expression: 2411 { 2412 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2413 uint64 blockLength = dataReader.ReadUnsignedLEB128(0); 2414 uint8* block = (uint8*)dataReader.Data(); 2415 dataReader.Skip(blockLength); 2416 2417 TRACE_CFI(" DW_CFA_expression: reg: %" B_PRIu32 ", " 2418 "block: %p, %" B_PRIu64 "\n", reg, block, blockLength); 2419 2420 if (CfaRule* rule = context.RegisterRule(reg)) 2421 rule->SetToLocationExpression(block, blockLength); 2422 break; 2423 } 2424 case DW_CFA_offset_extended_sf: 2425 { 2426 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2427 int64 offset = dataReader.ReadSignedLEB128(0); 2428 2429 TRACE_CFI(" DW_CFA_offset_extended: reg: %" B_PRIu32 ", " 2430 "offset: %" B_PRId64 "\n", reg, offset); 2431 2432 if (CfaRule* rule = context.RegisterRule(reg)) { 2433 rule->SetToLocationOffset( 2434 offset * (int32)context.DataAlignment()); 2435 } 2436 break; 2437 } 2438 case DW_CFA_def_cfa_sf: 2439 { 2440 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2441 int64 offset = dataReader.ReadSignedLEB128(0); 2442 2443 TRACE_CFI(" DW_CFA_def_cfa_sf: reg: %" B_PRIu32 ", " 2444 "offset: %" B_PRId64 "\n", reg, offset); 2445 2446 context.GetCfaCfaRule()->SetToRegisterOffset(reg, 2447 offset * (int32)context.DataAlignment()); 2448 break; 2449 } 2450 case DW_CFA_def_cfa_offset_sf: 2451 { 2452 int64 offset = dataReader.ReadSignedLEB128(0); 2453 2454 TRACE_CFI(" DW_CFA_def_cfa_offset: %" B_PRId64 "\n", 2455 offset); 2456 2457 if (context.GetCfaCfaRule()->Type() 2458 != CFA_CFA_RULE_REGISTER_OFFSET) { 2459 return B_BAD_DATA; 2460 } 2461 context.GetCfaCfaRule()->SetOffset( 2462 offset * (int32)context.DataAlignment()); 2463 break; 2464 } 2465 case DW_CFA_val_offset: 2466 { 2467 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2468 uint64 offset = dataReader.ReadUnsignedLEB128(0); 2469 2470 TRACE_CFI(" DW_CFA_val_offset: reg: %" B_PRIu32 ", " 2471 "offset: %" B_PRIu64 "\n", reg, offset); 2472 2473 if (CfaRule* rule = context.RegisterRule(reg)) { 2474 rule->SetToValueOffset( 2475 offset * context.DataAlignment()); 2476 } 2477 break; 2478 } 2479 case DW_CFA_val_offset_sf: 2480 { 2481 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2482 int64 offset = dataReader.ReadSignedLEB128(0); 2483 2484 TRACE_CFI(" DW_CFA_val_offset_sf: reg: %" B_PRIu32 ", " 2485 "offset: %" B_PRId64 "\n", reg, offset); 2486 2487 if (CfaRule* rule = context.RegisterRule(reg)) { 2488 rule->SetToValueOffset( 2489 offset * (int32)context.DataAlignment()); 2490 } 2491 break; 2492 } 2493 case DW_CFA_val_expression: 2494 { 2495 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2496 uint64 blockLength = dataReader.ReadUnsignedLEB128(0); 2497 uint8* block = (uint8*)dataReader.Data(); 2498 dataReader.Skip(blockLength); 2499 2500 TRACE_CFI(" DW_CFA_val_expression: reg: %" B_PRIu32 ", " 2501 "block: %p, %" B_PRIu64 "\n", reg, block, blockLength); 2502 2503 if (CfaRule* rule = context.RegisterRule(reg)) 2504 rule->SetToValueExpression(block, blockLength); 2505 break; 2506 } 2507 2508 // extensions 2509 case DW_CFA_MIPS_advance_loc8: 2510 { 2511 uint64 delta = dataReader.Read<uint64>(0); 2512 2513 TRACE_CFI(" DW_CFA_MIPS_advance_loc8: %#" B_PRIx64 "\n", 2514 delta); 2515 2516 target_addr_t location = context.Location() 2517 + delta * context.CodeAlignment(); 2518 if (location > context.TargetLocation()) 2519 return B_OK; 2520 context.SetLocation(location); 2521 break; 2522 } 2523 case DW_CFA_GNU_window_save: 2524 { 2525 // SPARC specific, no args 2526 TRACE_CFI(" DW_CFA_GNU_window_save\n"); 2527 2528 // TODO: Implement once we have SPARC support! 2529 break; 2530 } 2531 case DW_CFA_GNU_args_size: 2532 { 2533 // Updates the total size of arguments on the stack. 2534 TRACE_CFI_ONLY(uint64 size =) 2535 dataReader.ReadUnsignedLEB128(0); 2536 2537 TRACE_CFI(" DW_CFA_GNU_args_size: %" B_PRIu64 "\n", 2538 size); 2539 // TODO: Implement! 2540 break; 2541 } 2542 case DW_CFA_GNU_negative_offset_extended: 2543 { 2544 // obsolete 2545 uint32 reg = dataReader.ReadUnsignedLEB128(0); 2546 int64 offset = dataReader.ReadSignedLEB128(0); 2547 2548 TRACE_CFI(" DW_CFA_GNU_negative_offset_extended: " 2549 "reg: %" B_PRIu32 ", offset: %" B_PRId64 "\n", reg, 2550 offset); 2551 2552 if (CfaRule* rule = context.RegisterRule(reg)) { 2553 rule->SetToLocationOffset( 2554 offset * (int32)context.DataAlignment()); 2555 } 2556 break; 2557 } 2558 2559 default: 2560 TRACE_CFI(" unknown opcode %u!\n", opcode); 2561 return B_BAD_DATA; 2562 } 2563 } 2564 } 2565 2566 return B_OK; 2567 } 2568 2569 2570 status_t 2571 DwarfFile::_ParsePublicTypesInfo() 2572 { 2573 TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo()\n"); 2574 if (fDebugPublicTypesSection == NULL) { 2575 TRACE_PUBTYPES(" -> no public types section\n"); 2576 return B_ENTRY_NOT_FOUND; 2577 } 2578 2579 DataReader dataReader((uint8*)fDebugPublicTypesSection->Data(), 2580 fDebugPublicTypesSection->Size(), 4); 2581 // address size doesn't matter at this point 2582 2583 while (dataReader.BytesRemaining() > 0) { 2584 bool dwarf64; 2585 uint64 unitLength = dataReader.ReadInitialLength(dwarf64); 2586 2587 off_t unitLengthOffset = dataReader.Offset(); 2588 // the unitLength starts here 2589 2590 if (dataReader.HasOverflow()) 2591 return B_BAD_DATA; 2592 2593 if (unitLengthOffset + unitLength 2594 > (uint64)fDebugPublicTypesSection->Size()) { 2595 WARNING("Invalid public types set unit length.\n"); 2596 break; 2597 } 2598 2599 DataReader unitDataReader(dataReader.Data(), unitLength, 4); 2600 // address size doesn't matter 2601 _ParsePublicTypesInfo(unitDataReader, dwarf64); 2602 2603 dataReader.SeekAbsolute(unitLengthOffset + unitLength); 2604 } 2605 2606 return B_OK; 2607 } 2608 2609 2610 status_t 2611 DwarfFile::_ParsePublicTypesInfo(DataReader& dataReader, bool dwarf64) 2612 { 2613 int version = dataReader.Read<uint16>(0); 2614 if (version != 2) { 2615 TRACE_PUBTYPES(" pubtypes version %d unsupported\n", version); 2616 return B_UNSUPPORTED; 2617 } 2618 2619 TRACE_PUBTYPES_ONLY(off_t debugInfoOffset =) dwarf64 2620 ? dataReader.Read<uint64>(0) 2621 : (uint64)dataReader.Read<uint32>(0); 2622 TRACE_PUBTYPES_ONLY(off_t debugInfoSize =) dwarf64 2623 ? dataReader.Read<uint64>(0) 2624 : (uint64)dataReader.Read<uint32>(0); 2625 2626 if (dataReader.HasOverflow()) 2627 return B_BAD_DATA; 2628 2629 TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo(): compilation unit debug " 2630 "info: (%" B_PRIdOFF ", %" B_PRIdOFF ")\n", debugInfoOffset, 2631 debugInfoSize); 2632 2633 while (dataReader.BytesRemaining() > 0) { 2634 off_t entryOffset = dwarf64 2635 ? dataReader.Read<uint64>(0) 2636 : (uint64)dataReader.Read<uint32>(0); 2637 if (entryOffset == 0) 2638 return B_OK; 2639 2640 TRACE_PUBTYPES_ONLY(const char* name =) dataReader.ReadString(); 2641 2642 TRACE_PUBTYPES(" \"%s\" -> %" B_PRIdOFF "\n", name, entryOffset); 2643 } 2644 2645 return B_OK; 2646 } 2647 2648 2649 status_t 2650 DwarfFile::_GetAbbreviationTable(off_t offset, AbbreviationTable*& _table) 2651 { 2652 // check, whether we've already loaded it 2653 for (AbbreviationTableList::Iterator it 2654 = fAbbreviationTables.GetIterator(); 2655 AbbreviationTable* table = it.Next();) { 2656 if (offset == table->Offset()) { 2657 _table = table; 2658 return B_OK; 2659 } 2660 } 2661 2662 // create a new table 2663 AbbreviationTable* table = new(std::nothrow) AbbreviationTable(offset); 2664 if (table == NULL) 2665 return B_NO_MEMORY; 2666 2667 status_t error = table->Init(fDebugAbbrevSection->Data(), 2668 fDebugAbbrevSection->Size()); 2669 if (error != B_OK) { 2670 delete table; 2671 return error; 2672 } 2673 2674 fAbbreviationTables.Add(table); 2675 _table = table; 2676 return B_OK; 2677 } 2678 2679 2680 DebugInfoEntry* 2681 DwarfFile::_ResolveReference(BaseUnit* unit, uint64 offset, 2682 uint8 refType) const 2683 { 2684 switch (refType) { 2685 case dwarf_reference_type_local: 2686 return unit->EntryForOffset(offset); 2687 break; 2688 case dwarf_reference_type_global: 2689 { 2690 CompilationUnit* unit = _GetContainingCompilationUnit(offset); 2691 if (unit == NULL) 2692 break; 2693 2694 offset -= unit->HeaderOffset(); 2695 DebugInfoEntry* entry = unit->EntryForOffset(offset); 2696 if (entry != NULL) 2697 return entry; 2698 break; 2699 } 2700 case dwarf_reference_type_signature: 2701 { 2702 TRACE_DIE("Resolving signature %#" B_PRIx64 "\n", offset); 2703 TypeUnitTableEntry* entry = fTypeUnits.Lookup(offset); 2704 if (entry != NULL && entry->unit != NULL) 2705 return entry->unit->TypeEntry(); 2706 break; 2707 } 2708 } 2709 2710 return NULL; 2711 } 2712 2713 2714 status_t 2715 DwarfFile::_GetLocationExpression(CompilationUnit* unit, 2716 const LocationDescription* location, target_addr_t instructionPointer, 2717 const void*& _expression, off_t& _length) const 2718 { 2719 if (!location->IsValid()) 2720 return B_BAD_VALUE; 2721 2722 if (location->IsExpression()) { 2723 _expression = location->expression.data; 2724 _length = location->expression.length; 2725 return B_OK; 2726 } 2727 2728 if (location->IsLocationList() && instructionPointer != 0) { 2729 return _FindLocationExpression(unit, location->listOffset, 2730 instructionPointer, _expression, _length); 2731 } 2732 2733 return B_BAD_VALUE; 2734 } 2735 2736 2737 status_t 2738 DwarfFile::_FindLocationExpression(CompilationUnit* unit, uint64 offset, 2739 target_addr_t address, const void*& _expression, off_t& _length) const 2740 { 2741 if (unit == NULL) 2742 return B_BAD_VALUE; 2743 2744 if (fDebugLocationSection == NULL) 2745 return B_ENTRY_NOT_FOUND; 2746 2747 if (offset < 0 || offset >= (uint64)fDebugLocationSection->Size()) 2748 return B_BAD_DATA; 2749 2750 target_addr_t baseAddress = unit->AddressRangeBase(); 2751 target_addr_t maxAddress = unit->MaxAddress(); 2752 2753 DataReader dataReader((uint8*)fDebugLocationSection->Data() + offset, 2754 fDebugLocationSection->Size() - offset, unit->AddressSize()); 2755 while (true) { 2756 target_addr_t start = dataReader.ReadAddress(0); 2757 target_addr_t end = dataReader.ReadAddress(0); 2758 if (dataReader.HasOverflow()) 2759 return B_BAD_DATA; 2760 2761 if (start == 0 && end == 0) 2762 return B_ENTRY_NOT_FOUND; 2763 2764 if (start == maxAddress) { 2765 baseAddress = end; 2766 continue; 2767 } 2768 2769 uint16 expressionLength = dataReader.Read<uint16>(0); 2770 const void* expression = dataReader.Data(); 2771 if (!dataReader.Skip(expressionLength)) 2772 return B_BAD_DATA; 2773 2774 if (start == end) 2775 continue; 2776 2777 start += baseAddress; 2778 end += baseAddress; 2779 2780 if (address >= start && address < end) { 2781 _expression = expression; 2782 _length = expressionLength; 2783 return B_OK; 2784 } 2785 } 2786 } 2787 2788 2789 status_t 2790 DwarfFile::_LocateDebugInfo(BString& _requiredExternalFileName, 2791 const char* locatedFilePath) 2792 { 2793 ElfFile* debugInfoFile = fElfFile; 2794 ElfSection* debugLinkSection = fElfFile->GetSection(".gnu_debuglink"); 2795 if (debugLinkSection != NULL) { 2796 AutoSectionPutter putter(fElfFile, debugLinkSection); 2797 2798 // the file specifies a debug link, look at its target instead 2799 // for debug information. 2800 // Format: null-terminated filename, as many 0 padding bytes as 2801 // needed to reach the next 32-bit address boundary, followed 2802 // by a 32-bit CRC 2803 2804 BString debugPath; 2805 if (locatedFilePath) 2806 debugPath = locatedFilePath; 2807 else { 2808 status_t result = _GetDebugInfoPath( 2809 (const char*)debugLinkSection->Data(), 2810 _requiredExternalFileName); 2811 if (result != B_OK) 2812 return result; 2813 debugPath = _requiredExternalFileName; 2814 } 2815 2816 if (fAlternateName != NULL) 2817 free(fAlternateName); 2818 2819 fAlternateName = strdup(debugPath.String()); 2820 2821 if (fAlternateName == NULL) 2822 return B_NO_MEMORY; 2823 2824 /* 2825 // TODO: validate CRC 2826 int32 debugCRC = *(int32*)((char*)debugLinkSection->Data() 2827 + debugLinkSection->Size() - sizeof(int32)); 2828 */ 2829 if (fAlternateElfFile == NULL) { 2830 fAlternateElfFile = new(std::nothrow) ElfFile; 2831 if (fAlternateElfFile == NULL) 2832 return B_NO_MEMORY; 2833 } 2834 2835 status_t result = fAlternateElfFile->Init(fAlternateName); 2836 if (result != B_OK) 2837 return result; 2838 2839 debugInfoFile = fAlternateElfFile; 2840 } 2841 2842 // get the interesting sections 2843 fDebugInfoSection = debugInfoFile->GetSection(".debug_info"); 2844 fDebugAbbrevSection = debugInfoFile->GetSection(".debug_abbrev"); 2845 if (fDebugInfoSection == NULL || fDebugAbbrevSection == NULL) { 2846 WARNING("DwarfManager::File::Load(\"%s\"): no " 2847 ".debug_info or .debug_abbrev.\n", fName); 2848 2849 // if we at least have an EH frame, use that for stack unwinding 2850 // if nothing else. 2851 fEHFrameSection = fElfFile->GetSection(".eh_frame"); 2852 if (fEHFrameSection == NULL) 2853 return B_ERROR; 2854 } 2855 2856 return B_OK; 2857 } 2858 2859 2860 status_t 2861 DwarfFile::_GetDebugInfoPath(const char* debugFileName, 2862 BString& _infoPath) const 2863 { 2864 // first, see if we have a relative match to our local directory 2865 BPath basePath; 2866 status_t result = basePath.SetTo(fName); 2867 if (result != B_OK) 2868 return result; 2869 basePath.GetParent(&basePath); 2870 if (strcmp(basePath.Leaf(), "lib") == 0 || strcmp(basePath.Leaf(), 2871 "add-ons") == 0) { 2872 _infoPath.SetToFormat("%s/../debug/%s", basePath.Path(), 2873 debugFileName); 2874 } else 2875 _infoPath.SetToFormat("%s/debug/%s", basePath.Path(), debugFileName); 2876 2877 BEntry entry(_infoPath.String()); 2878 result = entry.InitCheck(); 2879 if (result != B_OK && result != B_ENTRY_NOT_FOUND) 2880 return result; 2881 if (entry.Exists()) 2882 return B_OK; 2883 2884 // If the above search failed, check if our image is located in any 2885 // of the system installation paths, and attempt to locate the debug info 2886 // file in the corresponding well-known location 2887 BString pathSuffix; 2888 pathSuffix.SetToFormat("debug/%s", debugFileName); 2889 2890 BPathFinder finder(fName); 2891 result = finder.FindPath(B_FIND_PATH_DEVELOP_DIRECTORY, 2892 pathSuffix.String(), B_FIND_PATH_EXISTING_ONLY, basePath); 2893 if (result == B_OK) { 2894 _infoPath = basePath.Path(); 2895 return B_OK; 2896 } else { 2897 // if we failed to find a match, then it's up to the user to 2898 // locate it. As such, return the external info file name 2899 // for user interface purposes. 2900 _infoPath.SetTo(debugFileName); 2901 } 2902 2903 return B_ENTRY_NOT_FOUND; 2904 } 2905 2906 2907 TypeUnitTableEntry* 2908 DwarfFile::_GetTypeUnit(uint64 signature) const 2909 { 2910 return fTypeUnits.Lookup(signature); 2911 } 2912 2913 2914 CompilationUnit* 2915 DwarfFile::_GetContainingCompilationUnit(off_t refAddr) const 2916 { 2917 if (fCompilationUnits.IsEmpty()) 2918 return NULL; 2919 2920 // binary search 2921 int lower = 0; 2922 int upper = fCompilationUnits.CountItems() - 1; 2923 while (lower < upper) { 2924 int mid = (lower + upper + 1) / 2; 2925 if (fCompilationUnits.ItemAt(mid)->HeaderOffset() > refAddr) 2926 upper = mid - 1; 2927 else 2928 lower = mid; 2929 } 2930 2931 CompilationUnit* unit = fCompilationUnits.ItemAt(lower); 2932 return unit->ContainsAbsoluteOffset(refAddr) ? unit : NULL; 2933 } 2934 2935 2936 DwarfFile::FDELookupInfo* 2937 DwarfFile::_GetContainingFDEInfo(target_addr_t offset) const 2938 { 2939 FDELookupInfo* info = NULL; 2940 if (fDebugFrameSection != NULL) { 2941 info = _GetContainingFDEInfo(offset, fDebugFrameInfos); 2942 if (info != NULL) 2943 return info; 2944 } 2945 2946 return _GetContainingFDEInfo(offset, fEHFrameInfos); 2947 } 2948 2949 2950 DwarfFile::FDELookupInfo* 2951 DwarfFile::_GetContainingFDEInfo(target_addr_t offset, 2952 const FDEInfoList& infoList) const 2953 { 2954 // binary search 2955 int lower = 0; 2956 int upper = infoList.CountItems() - 1; 2957 if (upper < 0) 2958 return NULL; 2959 2960 while (lower < upper) { 2961 int mid = (lower + upper + 1) / 2; 2962 if (offset < infoList.ItemAt(mid)->start) 2963 upper = mid - 1; 2964 else 2965 lower = mid; 2966 } 2967 2968 FDELookupInfo* info = infoList.ItemAt(lower); 2969 return info->ContainsAddress(offset) ? info : NULL; 2970 } 2971