1/* 2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2012, Rene Gollent, rene@gollent.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8#include "DwarfImageDebugInfo.h" 9 10#include <errno.h> 11#include <stdio.h> 12#include <unistd.h> 13 14#include <algorithm> 15#include <new> 16 17#include <AutoDeleter.h> 18#include <AutoLocker.h> 19 20#include "Architecture.h" 21#include "BasicFunctionDebugInfo.h" 22#include "CLanguage.h" 23#include "CompilationUnit.h" 24#include "CppLanguage.h" 25#include "CpuState.h" 26#include "DebuggerInterface.h" 27#include "DebugInfoEntries.h" 28#include "Demangler.h" 29#include "DisassembledCode.h" 30#include "Dwarf.h" 31#include "DwarfFile.h" 32#include "DwarfFunctionDebugInfo.h" 33#include "DwarfStackFrameDebugInfo.h" 34#include "DwarfTargetInterface.h" 35#include "DwarfTypeFactory.h" 36#include "DwarfTypes.h" 37#include "DwarfUtils.h" 38#include "ElfFile.h" 39#include "FileManager.h" 40#include "FileSourceCode.h" 41#include "FunctionID.h" 42#include "FunctionInstance.h" 43#include "GlobalTypeLookup.h" 44#include "Image.h" 45#include "ImageDebugInfo.h" 46#include "InstructionInfo.h" 47#include "LocatableFile.h" 48#include "Register.h" 49#include "RegisterMap.h" 50#include "SourceFile.h" 51#include "StackFrame.h" 52#include "Statement.h" 53#include "StringUtils.h" 54#include "SymbolInfo.h" 55#include "TargetAddressRangeList.h" 56#include "Team.h" 57#include "TeamMemory.h" 58#include "Tracing.h" 59#include "TypeLookupConstraints.h" 60#include "UnsupportedLanguage.h" 61#include "Variable.h" 62#include "ValueLocation.h" 63 64 65namespace { 66 67 68// #pragma mark - HasTypePredicate 69 70 71template<typename EntryType> 72struct HasTypePredicate { 73 inline bool operator()(EntryType* entry) const 74 { 75 return entry->GetType() != NULL; 76 } 77}; 78 79} 80 81 82// #pragma mark - BasicTargetInterface 83 84 85struct DwarfImageDebugInfo::BasicTargetInterface : DwarfTargetInterface { 86 BasicTargetInterface(const Register* registers, int32 registerCount, 87 RegisterMap* fromDwarfMap, Architecture* architecture, 88 TeamMemory* teamMemory) 89 : 90 fRegisters(registers), 91 fRegisterCount(registerCount), 92 fFromDwarfMap(fromDwarfMap), 93 fArchitecture(architecture), 94 fTeamMemory(teamMemory) 95 { 96 fFromDwarfMap->AcquireReference(); 97 } 98 99 ~BasicTargetInterface() 100 { 101 fFromDwarfMap->ReleaseReference(); 102 } 103 104 virtual uint32 CountRegisters() const 105 { 106 return fRegisterCount; 107 } 108 109 virtual uint32 RegisterValueType(uint32 index) const 110 { 111 const Register* reg = _RegisterAt(index); 112 return reg != NULL ? reg->ValueType() : 0; 113 } 114 115 virtual bool GetRegisterValue(uint32 index, BVariant& _value) const 116 { 117 return false; 118 } 119 120 virtual bool SetRegisterValue(uint32 index, const BVariant& value) 121 { 122 return false; 123 } 124 125 virtual bool IsCalleePreservedRegister(uint32 index) const 126 { 127 const Register* reg = _RegisterAt(index); 128 return reg != NULL && reg->IsCalleePreserved(); 129 } 130 131 virtual status_t InitRegisterRules(CfaContext& context) const 132 { 133 return fArchitecture->InitRegisterRules(context); 134 } 135 136 virtual bool ReadMemory(target_addr_t address, void* buffer, 137 size_t size) const 138 { 139 ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer, size); 140 return bytesRead >= 0 && (size_t)bytesRead == size; 141 } 142 143 virtual bool ReadValueFromMemory(target_addr_t address, 144 uint32 valueType, BVariant& _value) const 145 { 146 return fArchitecture->ReadValueFromMemory(address, valueType, _value) 147 == B_OK; 148 } 149 150 virtual bool ReadValueFromMemory(target_addr_t addressSpace, 151 target_addr_t address, uint32 valueType, BVariant& _value) const 152 { 153 return fArchitecture->ReadValueFromMemory(addressSpace, address, 154 valueType, _value) == B_OK; 155 } 156 157protected: 158 const Register* _RegisterAt(uint32 dwarfIndex) const 159 { 160 int32 index = fFromDwarfMap->MapRegisterIndex(dwarfIndex); 161 return index >= 0 && index < fRegisterCount ? fRegisters + index : NULL; 162 } 163 164protected: 165 const Register* fRegisters; 166 int32 fRegisterCount; 167 RegisterMap* fFromDwarfMap; 168 Architecture* fArchitecture; 169 TeamMemory* fTeamMemory; 170}; 171 172 173// #pragma mark - UnwindTargetInterface 174 175 176struct DwarfImageDebugInfo::UnwindTargetInterface : BasicTargetInterface { 177 UnwindTargetInterface(const Register* registers, int32 registerCount, 178 RegisterMap* fromDwarfMap, RegisterMap* toDwarfMap, CpuState* cpuState, 179 Architecture* architecture, TeamMemory* teamMemory) 180 : 181 BasicTargetInterface(registers, registerCount, fromDwarfMap, 182 architecture, teamMemory), 183 fToDwarfMap(toDwarfMap), 184 fCpuState(cpuState) 185 { 186 fToDwarfMap->AcquireReference(); 187 fCpuState->AcquireReference(); 188 } 189 190 ~UnwindTargetInterface() 191 { 192 fToDwarfMap->ReleaseReference(); 193 fCpuState->ReleaseReference(); 194 } 195 196 virtual bool GetRegisterValue(uint32 index, BVariant& _value) const 197 { 198 const Register* reg = _RegisterAt(index); 199 if (reg == NULL) 200 return false; 201 return fCpuState->GetRegisterValue(reg, _value); 202 } 203 204 virtual bool SetRegisterValue(uint32 index, const BVariant& value) 205 { 206 const Register* reg = _RegisterAt(index); 207 if (reg == NULL) 208 return false; 209 return fCpuState->SetRegisterValue(reg, value); 210 } 211 212private: 213 RegisterMap* fToDwarfMap; 214 CpuState* fCpuState; 215}; 216 217 218// #pragma mark - EntryListWrapper 219 220 221/*! Wraps a DebugInfoEntryList, which is a typedef and thus cannot appear in 222 the header, since our policy disallows us to include DWARF headers there. 223*/ 224struct DwarfImageDebugInfo::EntryListWrapper { 225 const DebugInfoEntryList& list; 226 227 EntryListWrapper(const DebugInfoEntryList& list) 228 : 229 list(list) 230 { 231 } 232}; 233 234 235// #pragma mark - DwarfImageDebugInfo 236 237 238DwarfImageDebugInfo::DwarfImageDebugInfo(const ImageInfo& imageInfo, 239 DebuggerInterface* interface, Architecture* architecture, 240 FileManager* fileManager, GlobalTypeLookup* typeLookup, 241 GlobalTypeCache* typeCache, DwarfFile* file) 242 : 243 fLock("dwarf image debug info"), 244 fImageInfo(imageInfo), 245 fDebuggerInterface(interface), 246 fArchitecture(architecture), 247 fFileManager(fileManager), 248 fTypeLookup(typeLookup), 249 fTypeCache(typeCache), 250 fFile(file), 251 fTextSegment(NULL), 252 fRelocationDelta(0), 253 fTextSectionStart(0), 254 fTextSectionEnd(0), 255 fPLTSectionStart(0), 256 fPLTSectionEnd(0) 257{ 258 fDebuggerInterface->AcquireReference(); 259 fFile->AcquireReference(); 260 fTypeCache->AcquireReference(); 261} 262 263 264DwarfImageDebugInfo::~DwarfImageDebugInfo() 265{ 266 fDebuggerInterface->ReleaseReference(); 267 fFile->ReleaseReference(); 268 fTypeCache->ReleaseReference(); 269} 270 271 272status_t 273DwarfImageDebugInfo::Init() 274{ 275 status_t error = fLock.InitCheck(); 276 if (error != B_OK) 277 return error; 278 279 fTextSegment = fFile->GetElfFile()->TextSegment(); 280 if (fTextSegment == NULL) 281 return B_ENTRY_NOT_FOUND; 282 283 fRelocationDelta = fImageInfo.TextBase() - fTextSegment->LoadAddress(); 284 285 ElfSection* section = fFile->GetElfFile()->FindSection(".text"); 286 if (section != NULL) { 287 fTextSectionStart = section->LoadAddress() + fRelocationDelta; 288 fTextSectionEnd = fTextSectionStart + section->Size(); 289 } 290 291 section = fFile->GetElfFile()->FindSection(".plt"); 292 if (section != NULL) { 293 fPLTSectionStart = section->LoadAddress() + fRelocationDelta; 294 fPLTSectionEnd = fPLTSectionStart + section->Size(); 295 } 296 297 return B_OK; 298} 299 300 301status_t 302DwarfImageDebugInfo::GetFunctions(BObjectList<FunctionDebugInfo>& functions) 303{ 304 TRACE_IMAGES("DwarfImageDebugInfo::GetFunctions()\n"); 305 TRACE_IMAGES(" %" B_PRId32 " compilation units\n", 306 fFile->CountCompilationUnits()); 307 308 for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i); 309 i++) { 310 DIECompileUnitBase* unitEntry = unit->UnitEntry(); 311// printf(" %s:\n", unitEntry->Name()); 312// printf(" address ranges:\n"); 313// TargetAddressRangeList* rangeList = unitEntry->AddressRanges(); 314// if (rangeList != NULL) { 315// int32 count = rangeList->CountRanges(); 316// for (int32 i = 0; i < count; i++) { 317// TargetAddressRange range = rangeList->RangeAt(i); 318// printf(" %#llx - %#llx\n", range.Start(), range.End()); 319// } 320// } else { 321// printf(" %#llx - %#llx\n", (target_addr_t)unitEntry->LowPC(), 322// (target_addr_t)unitEntry->HighPC()); 323// } 324 325// printf(" functions:\n"); 326 for (DebugInfoEntryList::ConstIterator it 327 = unitEntry->OtherChildren().GetIterator(); 328 DebugInfoEntry* entry = it.Next();) { 329 if (entry->Tag() != DW_TAG_subprogram) 330 continue; 331 332 DIESubprogram* subprogramEntry = static_cast<DIESubprogram*>(entry); 333 334 // ignore declarations and inlined functions 335 if (subprogramEntry->IsDeclaration() 336 || subprogramEntry->Inline() == DW_INL_inlined 337 || subprogramEntry->Inline() == DW_INL_declared_inlined) { 338 continue; 339 } 340 341 // get the name 342 BString name; 343 DwarfUtils::GetFullyQualifiedDIEName(subprogramEntry, name); 344 if (name.Length() == 0) 345 continue; 346 347 // get the address ranges 348 TargetAddressRangeList* rangeList = fFile->ResolveRangeList(unit, 349 subprogramEntry->AddressRangesOffset()); 350 if (rangeList == NULL) { 351 target_addr_t lowPC = subprogramEntry->LowPC(); 352 target_addr_t highPC = subprogramEntry->HighPC(); 353 if (lowPC >= highPC) 354 continue; 355 356 rangeList = new(std::nothrow) TargetAddressRangeList( 357 TargetAddressRange(lowPC, highPC - lowPC)); 358 if (rangeList == NULL) 359 return B_NO_MEMORY; 360 // TODO: Clean up already added functions! 361 } 362 BReference<TargetAddressRangeList> rangeListReference(rangeList, 363 true); 364 365 // get the source location 366 const char* directoryPath = NULL; 367 const char* fileName = NULL; 368 int32 line = -1; 369 int32 column = -1; 370 DwarfUtils::GetDeclarationLocation(fFile, subprogramEntry, 371 directoryPath, fileName, line, column); 372 373 LocatableFile* file = NULL; 374 if (fileName != NULL) { 375 file = fFileManager->GetSourceFile(directoryPath, 376 fileName); 377 } 378 BReference<LocatableFile> fileReference(file, true); 379 380 // create and add the functions 381 DwarfFunctionDebugInfo* function 382 = new(std::nothrow) DwarfFunctionDebugInfo(this, unit, 383 subprogramEntry, rangeList, name, file, 384 SourceLocation(line, std::max(column, (int32)0))); 385 if (function == NULL || !functions.AddItem(function)) { 386 delete function; 387 return B_NO_MEMORY; 388 // TODO: Clean up already added functions! 389 } 390 391// BString name; 392// DwarfUtils::GetFullyQualifiedDIEName(subprogramEntry, name); 393// printf(" subprogram entry: %p, name: %s, declaration: %d\n", 394// subprogramEntry, name.String(), 395// subprogramEntry->IsDeclaration()); 396// 397// rangeList = subprogramEntry->AddressRanges(); 398// if (rangeList != NULL) { 399// int32 count = rangeList->CountRanges(); 400// for (int32 i = 0; i < count; i++) { 401// TargetAddressRange range = rangeList->RangeAt(i); 402// printf(" %#llx - %#llx\n", range.Start(), range.End()); 403// } 404// } else { 405// printf(" %#llx - %#llx\n", 406// (target_addr_t)subprogramEntry->LowPC(), 407// (target_addr_t)subprogramEntry->HighPC()); 408// } 409 } 410 } 411 412 if (fFile->CountCompilationUnits() != 0) 413 return B_OK; 414 415 // if we had no compilation units, fall back to providing basic 416 // debug infos with DWARF-supported call frame unwinding 417 return SpecificImageDebugInfo::GetFunctionsFromSymbols(functions, 418 fDebuggerInterface, fImageInfo, this); 419} 420 421 422status_t 423DwarfImageDebugInfo::GetType(GlobalTypeCache* cache, 424 const BString& name, const TypeLookupConstraints& constraints, 425 Type*& _type) 426{ 427 int32 registerCount = fArchitecture->CountRegisters(); 428 const Register* registers = fArchitecture->Registers(); 429 430 // get the DWARF -> architecture register map 431 RegisterMap* fromDwarfMap; 432 status_t error = fArchitecture->GetDwarfRegisterMaps(NULL, &fromDwarfMap); 433 if (error != B_OK) 434 return error; 435 BReference<RegisterMap> fromDwarfMapReference(fromDwarfMap, true); 436 437 // create the target interface 438 BasicTargetInterface *inputInterface 439 = new(std::nothrow) BasicTargetInterface(registers, registerCount, 440 fromDwarfMap, fArchitecture, fDebuggerInterface); 441 442 if (inputInterface == NULL) 443 return B_NO_MEMORY; 444 445 BReference<BasicTargetInterface> inputInterfaceReference(inputInterface, 446 true); 447 448 // iterate through all compilation units 449 for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i); 450 i++) { 451 DwarfTypeContext* typeContext = NULL; 452 BReference<DwarfTypeContext> typeContextReference; 453 454 // iterate through all types of the compilation unit 455 for (DebugInfoEntryList::ConstIterator it 456 = unit->UnitEntry()->Types().GetIterator(); 457 DIEType* typeEntry = dynamic_cast<DIEType*>(it.Next());) { 458 if (typeEntry->IsDeclaration()) 459 continue; 460 461 if (constraints.HasTypeKind()) { 462 if (dwarf_tag_to_type_kind(typeEntry->Tag()) 463 != constraints.TypeKind()) 464 continue; 465 466 if (!_EvaluateBaseTypeConstraints(typeEntry, 467 constraints)) 468 continue; 469 } 470 471 if (constraints.HasSubtypeKind() 472 && dwarf_tag_to_subtype_kind(typeEntry->Tag()) 473 != constraints.SubtypeKind()) 474 continue; 475 476 BString typeEntryName; 477 DwarfUtils::GetFullyQualifiedDIEName(typeEntry, typeEntryName); 478 if (typeEntryName != name) 479 continue; 480 481 // The name matches and the entry is not just a declaration -- 482 // create the type. First create the type context lazily. 483 if (typeContext == NULL) { 484 typeContext = new(std::nothrow) 485 DwarfTypeContext(fArchitecture, fImageInfo.ImageID(), fFile, 486 unit, NULL, 0, 0, fRelocationDelta, inputInterface, 487 fromDwarfMap); 488 if (typeContext == NULL) 489 return B_NO_MEMORY; 490 typeContextReference.SetTo(typeContext, true); 491 } 492 493 // create the type 494 DwarfType* type; 495 DwarfTypeFactory typeFactory(typeContext, fTypeLookup, cache); 496 error = typeFactory.CreateType(typeEntry, type); 497 if (error != B_OK) 498 continue; 499 500 _type = type; 501 return B_OK; 502 } 503 } 504 505 return B_ENTRY_NOT_FOUND; 506} 507 508 509AddressSectionType 510DwarfImageDebugInfo::GetAddressSectionType(target_addr_t address) 511{ 512 if (address >= fTextSectionStart && address < fTextSectionEnd) 513 return ADDRESS_SECTION_TYPE_FUNCTION; 514 515 if (address >= fPLTSectionStart && address < fPLTSectionEnd) 516 return ADDRESS_SECTION_TYPE_PLT; 517 518 return ADDRESS_SECTION_TYPE_UNKNOWN; 519} 520 521 522status_t 523DwarfImageDebugInfo::CreateFrame(Image* image, 524 FunctionInstance* functionInstance, CpuState* cpuState, 525 bool getFullFrameInfo, target_addr_t returnFunctionAddress, 526 StackFrame*& _frame, CpuState*& _previousCpuState) 527{ 528 DwarfFunctionDebugInfo* function = dynamic_cast<DwarfFunctionDebugInfo*>( 529 functionInstance->GetFunctionDebugInfo()); 530 531 FunctionID* functionID = functionInstance->GetFunctionID(); 532 BReference<FunctionID> functionIDReference; 533 if (functionID != NULL) 534 functionIDReference.SetTo(functionID, true); 535 536 DIESubprogram* entry = function != NULL 537 ? function->SubprogramEntry() : NULL; 538 539 TRACE_CFI("DwarfImageDebugInfo::CreateFrame(): subprogram DIE: %p, " 540 "function: %s\n", entry, 541 functionID->FunctionName().String()); 542 543 int32 registerCount = fArchitecture->CountRegisters(); 544 const Register* registers = fArchitecture->Registers(); 545 546 // get the DWARF <-> architecture register maps 547 RegisterMap* toDwarfMap; 548 RegisterMap* fromDwarfMap; 549 status_t error = fArchitecture->GetDwarfRegisterMaps(&toDwarfMap, 550 &fromDwarfMap); 551 if (error != B_OK) 552 return error; 553 BReference<RegisterMap> toDwarfMapReference(toDwarfMap, true); 554 BReference<RegisterMap> fromDwarfMapReference(fromDwarfMap, true); 555 556 // create a clean CPU state for the previous frame 557 CpuState* previousCpuState; 558 error = fArchitecture->CreateCpuState(previousCpuState); 559 if (error != B_OK) 560 return error; 561 BReference<CpuState> previousCpuStateReference(previousCpuState, true); 562 563 // create the target interfaces 564 UnwindTargetInterface* inputInterface 565 = new(std::nothrow) UnwindTargetInterface(registers, registerCount, 566 fromDwarfMap, toDwarfMap, cpuState, fArchitecture, 567 fDebuggerInterface); 568 if (inputInterface == NULL) 569 return B_NO_MEMORY; 570 BReference<UnwindTargetInterface> inputInterfaceReference(inputInterface, 571 true); 572 573 UnwindTargetInterface* outputInterface 574 = new(std::nothrow) UnwindTargetInterface(registers, registerCount, 575 fromDwarfMap, toDwarfMap, previousCpuState, fArchitecture, 576 fDebuggerInterface); 577 if (outputInterface == NULL) 578 return B_NO_MEMORY; 579 BReference<UnwindTargetInterface> outputInterfaceReference(outputInterface, 580 true); 581 582 // do the unwinding 583 target_addr_t instructionPointer 584 = cpuState->InstructionPointer() - fRelocationDelta; 585 target_addr_t framePointer; 586 CompilationUnit* unit = function != NULL ? function->GetCompilationUnit() 587 : NULL; 588 error = fFile->UnwindCallFrame(unit, fArchitecture->AddressSize(), entry, 589 instructionPointer, inputInterface, outputInterface, framePointer); 590 591 if (error != B_OK) { 592 TRACE_CFI("Failed to unwind call frame: %s\n", strerror(error)); 593 return B_UNSUPPORTED; 594 } 595 596 TRACE_CFI_ONLY( 597 TRACE_CFI("unwound registers:\n"); 598 for (int32 i = 0; i < registerCount; i++) { 599 const Register* reg = registers + i; 600 BVariant value; 601 if (previousCpuState->GetRegisterValue(reg, value)) { 602 TRACE_CFI(" %3s: %#" B_PRIx64 "\n", reg->Name(), 603 value.ToUInt64()); 604 } else 605 TRACE_CFI(" %3s: undefined\n", reg->Name()); 606 } 607 ) 608 609 // create the stack frame debug info 610 DIESubprogram* subprogramEntry = function != NULL ? 611 function->SubprogramEntry() : NULL; 612 DwarfStackFrameDebugInfo* stackFrameDebugInfo 613 = new(std::nothrow) DwarfStackFrameDebugInfo(fArchitecture, 614 fImageInfo.ImageID(), fFile, unit, subprogramEntry, fTypeLookup, 615 fTypeCache, instructionPointer, framePointer, fRelocationDelta, 616 inputInterface, fromDwarfMap); 617 if (stackFrameDebugInfo == NULL) 618 return B_NO_MEMORY; 619 BReference<DwarfStackFrameDebugInfo> stackFrameDebugInfoReference( 620 stackFrameDebugInfo, true); 621 622 error = stackFrameDebugInfo->Init(); 623 if (error != B_OK) 624 return error; 625 626 // create the stack frame 627 StackFrame* frame = new(std::nothrow) StackFrame(STACK_FRAME_TYPE_STANDARD, 628 cpuState, framePointer, cpuState->InstructionPointer(), 629 stackFrameDebugInfo); 630 if (frame == NULL) 631 return B_NO_MEMORY; 632 BReference<StackFrame> frameReference(frame, true); 633 634 error = frame->Init(); 635 if (error != B_OK) 636 return error; 637 638 frame->SetReturnAddress(previousCpuState->InstructionPointer()); 639 // Note, this is correct, since we actually retrieved the return 640 // address. Our caller will fix the IP for us. 641 642 // The subprogram entry may not be available since this may be a case 643 // where .eh_frame was used to unwind the stack without other DWARF 644 // info being available. 645 if (subprogramEntry != NULL && getFullFrameInfo) { 646 // create function parameter objects 647 for (DebugInfoEntryList::ConstIterator it 648 = subprogramEntry->Parameters().GetIterator(); 649 DebugInfoEntry* entry = it.Next();) { 650 if (entry->Tag() != DW_TAG_formal_parameter) 651 continue; 652 653 BString parameterName; 654 DwarfUtils::GetDIEName(entry, parameterName); 655 if (parameterName.Length() == 0) 656 continue; 657 658 DIEFormalParameter* parameterEntry 659 = dynamic_cast<DIEFormalParameter*>(entry); 660 Variable* parameter; 661 if (stackFrameDebugInfo->CreateParameter(functionID, 662 parameterEntry, parameter) != B_OK) { 663 continue; 664 } 665 BReference<Variable> parameterReference(parameter, true); 666 667 if (!frame->AddParameter(parameter)) 668 return B_NO_MEMORY; 669 } 670 671 // create objects for the local variables 672 _CreateLocalVariables(unit, frame, functionID, *stackFrameDebugInfo, 673 instructionPointer, functionInstance->Address() - fRelocationDelta, 674 subprogramEntry->Variables(), subprogramEntry->Blocks()); 675 676 // TODO: re-enable once PIC and false positive issues 677 // are properly dealt with 678#if 0 679 if (returnFunctionAddress != 0) { 680 _CreateReturnValue(returnFunctionAddress, image, frame, 681 *stackFrameDebugInfo); 682 } 683#endif 684 } 685 686 _frame = frameReference.Detach(); 687 _previousCpuState = previousCpuStateReference.Detach(); 688 689 frame->SetPreviousCpuState(_previousCpuState); 690 691 return B_OK; 692} 693 694 695status_t 696DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* _function, 697 target_addr_t address, Statement*& _statement) 698{ 699 TRACE_CODE("DwarfImageDebugInfo::GetStatement(function: %p, address: %#" 700 B_PRIx64 ")\n", _function, address); 701 702 DwarfFunctionDebugInfo* function 703 = dynamic_cast<DwarfFunctionDebugInfo*>(_function); 704 if (function == NULL) { 705 TRACE_LINES(" -> no dwarf function\n"); 706 return B_BAD_VALUE; 707 } 708 709 AutoLocker<BLocker> locker(fLock); 710 711 // check whether we have the source code 712 CompilationUnit* unit = function->GetCompilationUnit(); 713 LocatableFile* file = function->SourceFile(); 714 if (file == NULL) { 715 TRACE_CODE(" -> no source file\n"); 716 717 // no source code -- rather return the assembly statement 718 return fArchitecture->GetStatement(function, address, _statement); 719 } 720 721 // get the index of the source file in the compilation unit for cheaper 722 // comparison below 723 int32 fileIndex = _GetSourceFileIndex(unit, file); 724 725 // Get the statement by executing the line number program for the 726 // compilation unit. 727 LineNumberProgram& program = unit->GetLineNumberProgram(); 728 if (!program.IsValid()) { 729 TRACE_CODE(" -> no line number program\n"); 730 return B_BAD_DATA; 731 } 732 733 // adjust address 734 address -= fRelocationDelta; 735 736 LineNumberProgram::State state; 737 program.GetInitialState(state); 738 739 target_addr_t statementAddress = 0; 740 int32 statementLine = -1; 741 int32 statementColumn = -1; 742 while (program.GetNextRow(state)) { 743 // skip statements of other files 744 if (state.file != fileIndex) 745 continue; 746 747 if (statementAddress != 0 748 && (state.isStatement || state.isSequenceEnd)) { 749 target_addr_t endAddress = state.address; 750 if (address >= statementAddress && address < endAddress) { 751 ContiguousStatement* statement = new(std::nothrow) 752 ContiguousStatement( 753 SourceLocation(statementLine, statementColumn), 754 TargetAddressRange(fRelocationDelta + statementAddress, 755 endAddress - statementAddress)); 756 if (statement == NULL) 757 return B_NO_MEMORY; 758 759 _statement = statement; 760 return B_OK; 761 } 762 763 statementAddress = 0; 764 } 765 766 if (state.isStatement) { 767 statementAddress = state.address; 768 statementLine = state.line - 1; 769 statementColumn = std::max(state.column - 1, (int32)0); 770 } 771 } 772 773 TRACE_CODE(" -> no line number program match\n"); 774 return B_ENTRY_NOT_FOUND; 775} 776 777 778status_t 779DwarfImageDebugInfo::GetStatementAtSourceLocation(FunctionDebugInfo* _function, 780 const SourceLocation& sourceLocation, Statement*& _statement) 781{ 782 DwarfFunctionDebugInfo* function 783 = dynamic_cast<DwarfFunctionDebugInfo*>(_function); 784 if (function == NULL) 785 return B_BAD_VALUE; 786 787 target_addr_t functionStartAddress = function->Address() - fRelocationDelta; 788 target_addr_t functionEndAddress = functionStartAddress + function->Size(); 789 790 TRACE_LINES2("DwarfImageDebugInfo::GetStatementAtSourceLocation(%p, " 791 "(%" B_PRId32 ", %" B_PRId32 ")): function range: %#" B_PRIx64 " - %#" 792 B_PRIx64 "\n", function, sourceLocation.Line(), sourceLocation.Column(), 793 functionStartAddress, functionEndAddress); 794 795 AutoLocker<BLocker> locker(fLock); 796 797 // get the source file 798 LocatableFile* file = function->SourceFile(); 799 if (file == NULL) 800 return B_ENTRY_NOT_FOUND; 801 802 CompilationUnit* unit = function->GetCompilationUnit(); 803 804 // get the index of the source file in the compilation unit for cheaper 805 // comparison below 806 int32 fileIndex = _GetSourceFileIndex(unit, file); 807 808 // Get the statement by executing the line number program for the 809 // compilation unit. 810 LineNumberProgram& program = unit->GetLineNumberProgram(); 811 if (!program.IsValid()) 812 return B_BAD_DATA; 813 814 LineNumberProgram::State state; 815 program.GetInitialState(state); 816 817 target_addr_t statementAddress = 0; 818 int32 statementLine = -1; 819 int32 statementColumn = -1; 820 while (program.GetNextRow(state)) { 821 bool isOurFile = state.file == fileIndex; 822 823 if (statementAddress != 0 824 && (!isOurFile || state.isStatement || state.isSequenceEnd)) { 825 target_addr_t endAddress = state.address; 826 827 if (statementAddress < endAddress) { 828 TRACE_LINES2(" statement: %#" B_PRIx64 " - %#" B_PRIx64 829 ", location: (%" B_PRId32 ", %" B_PRId32 ")\n", 830 statementAddress, endAddress, statementLine, 831 statementColumn); 832 } 833 834 if (statementAddress < endAddress 835 && statementAddress >= functionStartAddress 836 && statementAddress < functionEndAddress 837 && statementLine == (int32)sourceLocation.Line() 838 && statementColumn == (int32)sourceLocation.Column()) { 839 TRACE_LINES2(" -> found statement!\n"); 840 841 ContiguousStatement* statement = new(std::nothrow) 842 ContiguousStatement( 843 SourceLocation(statementLine, statementColumn), 844 TargetAddressRange(fRelocationDelta + statementAddress, 845 endAddress - statementAddress)); 846 if (statement == NULL) 847 return B_NO_MEMORY; 848 849 _statement = statement; 850 return B_OK; 851 } 852 853 statementAddress = 0; 854 } 855 856 // skip statements of other files 857 if (!isOurFile) 858 continue; 859 860 if (state.isStatement) { 861 statementAddress = state.address; 862 statementLine = state.line - 1; 863 statementColumn = std::max(state.column - 1, (int32)0); 864 } 865 } 866 867 return B_ENTRY_NOT_FOUND; 868} 869 870 871status_t 872DwarfImageDebugInfo::GetSourceLanguage(FunctionDebugInfo* _function, 873 SourceLanguage*& _language) 874{ 875 DwarfFunctionDebugInfo* function 876 = dynamic_cast<DwarfFunctionDebugInfo*>(_function); 877 if (function == NULL) 878 return B_BAD_VALUE; 879 880 SourceLanguage* language; 881 CompilationUnit* unit = function->GetCompilationUnit(); 882 switch (unit->UnitEntry()->Language()) { 883 case DW_LANG_C89: 884 case DW_LANG_C: 885 case DW_LANG_C99: 886 language = new(std::nothrow) CLanguage; 887 break; 888 case DW_LANG_C_plus_plus: 889 language = new(std::nothrow) CppLanguage; 890 break; 891 case 0: 892 default: 893 language = new(std::nothrow) UnsupportedLanguage; 894 break; 895 } 896 897 if (language == NULL) 898 return B_NO_MEMORY; 899 900 _language = language; 901 return B_OK; 902} 903 904 905ssize_t 906DwarfImageDebugInfo::ReadCode(target_addr_t address, void* buffer, size_t size) 907{ 908 target_addr_t offset = address - fRelocationDelta 909 - fTextSegment->LoadAddress() + fTextSegment->FileOffset(); 910 ssize_t bytesRead = pread(fFile->GetElfFile()->FD(), buffer, size, offset); 911 return bytesRead >= 0 ? bytesRead : errno; 912} 913 914 915status_t 916DwarfImageDebugInfo::AddSourceCodeInfo(LocatableFile* file, 917 FileSourceCode* sourceCode) 918{ 919 bool addedAny = false; 920 for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i); 921 i++) { 922 int32 fileIndex = _GetSourceFileIndex(unit, file); 923 if (fileIndex < 0) 924 continue; 925 926 status_t error = _AddSourceCodeInfo(unit, sourceCode, fileIndex); 927 if (error == B_NO_MEMORY) 928 return error; 929 addedAny |= error == B_OK; 930 } 931 932 return addedAny ? B_OK : B_ENTRY_NOT_FOUND; 933} 934 935 936status_t 937DwarfImageDebugInfo::_AddSourceCodeInfo(CompilationUnit* unit, 938 FileSourceCode* sourceCode, int32 fileIndex) 939{ 940 // Get the statements by executing the line number program for the 941 // compilation unit and filtering the rows for our source file. 942 LineNumberProgram& program = unit->GetLineNumberProgram(); 943 if (!program.IsValid()) 944 return B_BAD_DATA; 945 946 LineNumberProgram::State state; 947 program.GetInitialState(state); 948 949 target_addr_t statementAddress = 0; 950 int32 statementLine = -1; 951 int32 statementColumn = -1; 952 while (program.GetNextRow(state)) { 953 TRACE_LINES2(" %#" B_PRIx64 " (%" B_PRId32 ", %" B_PRId32 ", %" 954 B_PRId32 ") %d\n", state.address, state.file, state.line, 955 state.column, state.isStatement); 956 957 bool isOurFile = state.file == fileIndex; 958 959 if (statementAddress != 0 960 && (!isOurFile || state.isStatement || state.isSequenceEnd)) { 961 target_addr_t endAddress = state.address; 962 if (endAddress > statementAddress) { 963 // add the statement 964 status_t error = sourceCode->AddSourceLocation( 965 SourceLocation(statementLine, statementColumn)); 966 if (error != B_OK) 967 return error; 968 969 TRACE_LINES2(" -> statement: %#" B_PRIx64 " - %#" B_PRIx64 970 ", source location: (%" B_PRId32 ", %" B_PRId32 ")\n", 971 statementAddress, endAddress, statementLine, 972 statementColumn); 973 } 974 975 statementAddress = 0; 976 } 977 978 // skip statements of other files 979 if (!isOurFile) 980 continue; 981 982 if (state.isStatement) { 983 statementAddress = state.address; 984 statementLine = state.line - 1; 985 statementColumn = std::max(state.column - 1, (int32)0); 986 } 987 } 988 989 return B_OK; 990} 991 992 993int32 994DwarfImageDebugInfo::_GetSourceFileIndex(CompilationUnit* unit, 995 LocatableFile* sourceFile) const 996{ 997 // get the index of the source file in the compilation unit for cheaper 998 // comparison below 999 const char* directory; 1000 for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) { 1001 LocatableFile* file = fFileManager->GetSourceFile(directory, fileName); 1002 if (file != NULL) { 1003 file->ReleaseReference(); 1004 if (file == sourceFile) { 1005 return i + 1; 1006 // indices are one-based 1007 } 1008 } 1009 } 1010 1011 return -1; 1012} 1013 1014 1015status_t 1016DwarfImageDebugInfo::_CreateLocalVariables(CompilationUnit* unit, 1017 StackFrame* frame, FunctionID* functionID, 1018 DwarfStackFrameDebugInfo& factory, target_addr_t instructionPointer, 1019 target_addr_t lowPC, const EntryListWrapper& variableEntries, 1020 const EntryListWrapper& blockEntries) 1021{ 1022 TRACE_LOCALS("DwarfImageDebugInfo::_CreateLocalVariables(): ip: %#" B_PRIx64 1023 ", low PC: %#" B_PRIx64 "\n", instructionPointer, lowPC); 1024 1025 // iterate through the variables and add the ones in scope 1026 for (DebugInfoEntryList::ConstIterator it 1027 = variableEntries.list.GetIterator(); 1028 DIEVariable* variableEntry = dynamic_cast<DIEVariable*>(it.Next());) { 1029 1030 TRACE_LOCALS(" variableEntry %p, scope start: %" B_PRIu64 "\n", 1031 variableEntry, variableEntry->StartScope()); 1032 1033 // check the variable's scope 1034 if (instructionPointer < lowPC + variableEntry->StartScope()) 1035 continue; 1036 1037 // add the variable 1038 Variable* variable; 1039 if (factory.CreateLocalVariable(functionID, variableEntry, variable) 1040 != B_OK) { 1041 continue; 1042 } 1043 BReference<Variable> variableReference(variable, true); 1044 1045 if (!frame->AddLocalVariable(variable)) 1046 return B_NO_MEMORY; 1047 } 1048 1049 // iterate through the blocks and find the one we're currently in (if any) 1050 for (DebugInfoEntryList::ConstIterator it = blockEntries.list.GetIterator(); 1051 DIELexicalBlock* block = dynamic_cast<DIELexicalBlock*>(it.Next());) { 1052 1053 TRACE_LOCALS(" lexical block: %p\n", block); 1054 1055 // check whether the block has low/high PC attributes 1056 if (block->LowPC() != 0) { 1057 TRACE_LOCALS(" has lowPC\n"); 1058 1059 // yep, compare with the instruction pointer 1060 if (instructionPointer < block->LowPC() 1061 || instructionPointer >= block->HighPC()) { 1062 continue; 1063 } 1064 } else { 1065 TRACE_LOCALS(" no lowPC\n"); 1066 1067 // check the address ranges instead 1068 TargetAddressRangeList* rangeList = fFile->ResolveRangeList(unit, 1069 block->AddressRangesOffset()); 1070 if (rangeList == NULL) { 1071 TRACE_LOCALS(" failed to get ranges\n"); 1072 continue; 1073 } 1074 BReference<TargetAddressRangeList> rangeListReference(rangeList, 1075 true); 1076 1077 if (!rangeList->Contains(instructionPointer)) { 1078 TRACE_LOCALS(" ranges don't contain IP\n"); 1079 continue; 1080 } 1081 } 1082 1083 // found a block -- recurse 1084 return _CreateLocalVariables(unit, frame, functionID, factory, 1085 instructionPointer, lowPC, block->Variables(), block->Blocks()); 1086 } 1087 1088 return B_OK; 1089} 1090 1091 1092status_t 1093DwarfImageDebugInfo::_CreateReturnValue(target_addr_t returnFunctionAddress, 1094 Image* image, StackFrame* frame, DwarfStackFrameDebugInfo& factory) 1095{ 1096 if (!image->ContainsAddress(returnFunctionAddress)) { 1097 // our current image doesn't contain the target function, 1098 // locate the one which does. 1099 image = image->GetTeam()->ImageByAddress(returnFunctionAddress); 1100 if (image == NULL) 1101 return B_BAD_VALUE; 1102 } 1103 1104 status_t result = B_OK; 1105 FunctionInstance* targetFunction; 1106 if (returnFunctionAddress >= fPLTSectionStart 1107 && returnFunctionAddress < fPLTSectionEnd) { 1108 // TODO: handle resolving PLT entries 1109 // to their target function 1110 return B_UNSUPPORTED; 1111 } 1112 1113 ImageDebugInfo* imageInfo = image->GetImageDebugInfo(); 1114 targetFunction = imageInfo->FunctionAtAddress(returnFunctionAddress); 1115 if (targetFunction != NULL) { 1116 DwarfFunctionDebugInfo* targetInfo = 1117 dynamic_cast<DwarfFunctionDebugInfo*>( 1118 targetFunction->GetFunctionDebugInfo()); 1119 if (targetInfo != NULL) { 1120 DIESubprogram* subProgram = targetInfo->SubprogramEntry(); 1121 DIEType* returnType = subProgram->ReturnType(); 1122 if (returnType == NULL) { 1123 // check if we have a specification, and if so, if that has 1124 // a return type 1125 subProgram = dynamic_cast<DIESubprogram*>(subProgram->Specification()); 1126 if (subProgram != NULL) 1127 returnType = subProgram->ReturnType(); 1128 1129 // function doesn't return a value, we're done. 1130 if (returnType == NULL) 1131 return B_OK; 1132 } 1133 1134 uint32 byteSize = 0; 1135 if (returnType->ByteSize() == NULL) { 1136 if (dynamic_cast<DIEAddressingType*>(returnType) != NULL) 1137 byteSize = fArchitecture->AddressSize(); 1138 } else 1139 byteSize = returnType->ByteSize()->constant; 1140 1141 ValueLocation* location; 1142 result = fArchitecture->GetReturnAddressLocation(frame, 1143 byteSize, location); 1144 if (result != B_OK) 1145 return result; 1146 1147 BReference<ValueLocation> locationReference(location, true); 1148 Variable* variable = NULL; 1149 BReference<FunctionID> idReference( 1150 targetFunction->GetFunctionID(), true); 1151 result = factory.CreateReturnValue(idReference, returnType, 1152 location, variable); 1153 if (result != B_OK) 1154 return result; 1155 1156 BReference<Variable> variableReference(variable, true); 1157 if (!frame->AddLocalVariable(variable)) 1158 return B_NO_MEMORY; 1159 } 1160 } 1161 1162 return B_OK; 1163} 1164 1165 1166bool 1167DwarfImageDebugInfo::_EvaluateBaseTypeConstraints(DIEType* type, 1168 const TypeLookupConstraints& constraints) 1169{ 1170 if (constraints.HasBaseTypeName()) { 1171 BString baseEntryName; 1172 DIEType* baseTypeOwnerEntry = NULL; 1173 1174 switch (constraints.TypeKind()) { 1175 case TYPE_ADDRESS: 1176 { 1177 DIEAddressingType* addressType = 1178 dynamic_cast<DIEAddressingType*>(type); 1179 if (addressType != NULL) { 1180 baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate( 1181 addressType, HasTypePredicate<DIEAddressingType>()); 1182 } 1183 break; 1184 } 1185 case TYPE_ARRAY: 1186 { 1187 DIEArrayType* arrayType = 1188 dynamic_cast<DIEArrayType*>(type); 1189 if (arrayType != NULL) { 1190 baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate( 1191 arrayType, HasTypePredicate<DIEArrayType>()); 1192 } 1193 break; 1194 } 1195 default: 1196 break; 1197 } 1198 1199 if (baseTypeOwnerEntry != NULL) { 1200 DwarfUtils::GetFullyQualifiedDIEName(baseTypeOwnerEntry, 1201 baseEntryName); 1202 1203 if (baseEntryName != constraints.BaseTypeName()) 1204 return false; 1205 } 1206 } 1207 1208 return true; 1209} 1210