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