diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp index 2076d87791..203e9dddc4 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp @@ -18,26 +18,131 @@ #include "Architecture.h" #include "CompilationUnit.h" +#include "CpuState.h" #include "DebugInfoEntries.h" #include "Dwarf.h" #include "DwarfFile.h" #include "DwarfFunctionDebugInfo.h" +#include "DwarfTargetInterface.h" #include "DwarfUtils.h" #include "ElfFile.h" #include "FileManager.h" #include "FileSourceCode.h" #include "LocatableFile.h" +#include "Register.h" +#include "RegisterMap.h" #include "SourceFile.h" +#include "StackFrame.h" #include "Statement.h" #include "StringUtils.h" +#include "TeamMemory.h" + + +// #pragma mark - UnwindTargetInterface + + +struct DwarfImageDebugInfo::UnwindTargetInterface : DwarfTargetInterface { + UnwindTargetInterface(const Register* registers, int32 registerCount, + RegisterMap* fromDwarfMap, RegisterMap* toDwarfMap, CpuState* cpuState, + Architecture* architecture, TeamMemory* teamMemory) + : + fRegisters(registers), + fRegisterCount(registerCount), + fFromDwarfMap(fromDwarfMap), + fToDwarfMap(toDwarfMap), + fCpuState(cpuState), + fArchitecture(architecture), + fTeamMemory(teamMemory) + { + fFromDwarfMap->AcquireReference(); + fToDwarfMap->AcquireReference(); + fCpuState->AcquireReference(); + } + + ~UnwindTargetInterface() + { + fFromDwarfMap->ReleaseReference(); + fToDwarfMap->ReleaseReference(); + fCpuState->ReleaseReference(); + } + + virtual uint32 CountRegisters() const + { + return fRegisterCount; + } + + virtual uint32 RegisterValueType(uint32 index) const + { + const Register* reg = _RegisterAt(index); + return reg != NULL ? reg->ValueType() : 0; + } + + virtual bool GetRegisterValue(uint32 index, BVariant& _value) const + { + const Register* reg = _RegisterAt(index); + if (reg == NULL) + return false; + return fCpuState->GetRegisterValue(reg, _value); + } + + virtual bool SetRegisterValue(uint32 index, const BVariant& value) + { + const Register* reg = _RegisterAt(index); + if (reg == NULL) + return false; + return fCpuState->SetRegisterValue(reg, value); + } + + virtual bool IsCalleePreservedRegister(uint32 index) const + { + const Register* reg = _RegisterAt(index); + return reg != NULL && reg->IsCalleePreserved(); + } + + virtual bool ReadMemory(target_addr_t address, void* buffer, + size_t size) const + { + ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer, size); + return bytesRead >= 0 && (size_t)bytesRead == size; + } + + virtual bool ReadValueFromMemory(target_addr_t address, + uint32 valueType, BVariant& _value) const + { + return fArchitecture->ReadValueFromMemory(address, valueType, _value) + == B_OK; + } + +private: + const Register* _RegisterAt(uint32 dwarfIndex) const + { + int32 index = fFromDwarfMap->MapRegisterIndex(dwarfIndex); + return index >= 0 && index < fRegisterCount ? fRegisters + index : NULL; + } + +private: + const Register* fRegisters; + int32 fRegisterCount; + RegisterMap* fFromDwarfMap; + RegisterMap* fToDwarfMap; + CpuState* fCpuState; + Architecture* fArchitecture; + TeamMemory* fTeamMemory; +}; + + + +// #pragma mark - DwarfImageDebugInfo DwarfImageDebugInfo::DwarfImageDebugInfo(const ImageInfo& imageInfo, - Architecture* architecture, FileManager* fileManager, DwarfFile* file) + Architecture* architecture, TeamMemory* teamMemory, + FileManager* fileManager, DwarfFile* file) : fLock("dwarf image debug info"), fImageInfo(imageInfo), fArchitecture(architecture), + fTeamMemory(teamMemory), fFileManager(fileManager), fFile(file), fTextSegment(NULL), @@ -188,8 +293,64 @@ DwarfImageDebugInfo::CreateFrame(Image* image, FunctionDebugInfo* function, CpuState* cpuState, StackFrame*& _previousFrame, CpuState*& _previousCpuState) { - // TODO:... - return B_UNSUPPORTED; + int32 registerCount = fArchitecture->CountRegisters(); + const Register* registers = fArchitecture->Registers(); + + // get the DWARF <-> architecture register maps + RegisterMap* toDwarfMap; + RegisterMap* fromDwarfMap; + status_t error = fArchitecture->GetDwarfRegisterMaps(&toDwarfMap, + &fromDwarfMap); + if (error != B_OK) + return error; + Reference toDwarfMapReference(toDwarfMap, true); + Reference fromDwarfMapReference(fromDwarfMap, true); + + // create a clean CPU state for the previous frame + CpuState* previousCpuState; + error = fArchitecture->CreateCpuState(previousCpuState); + if (error != B_OK) + return error; + Reference previousCpuStateReference(previousCpuState, true); + + // create the target interfaces + UnwindTargetInterface inputInterface(registers, registerCount, + fromDwarfMap, toDwarfMap, cpuState, fArchitecture, fTeamMemory); + UnwindTargetInterface outputInterface(registers, registerCount, + fromDwarfMap, toDwarfMap, previousCpuState, fArchitecture, fTeamMemory); + + // do the unwinding + target_addr_t framePointer; + error = fFile->UnwindCallFrame( + cpuState->InstructionPointer() - fRelocationDelta, + &inputInterface, &outputInterface, framePointer); + if (error != B_OK) + return B_UNSUPPORTED; + +printf("unwound registers:\n"); +for (int32 i = 0; i < registerCount; i++) { +const Register* reg = registers + i; +BVariant value; +if (previousCpuState->GetRegisterValue(reg, value)) { + printf(" %3s: %#lx\n", reg->Name(), value.ToUInt32()); +} else + printf(" %3s: undefined\n", reg->Name()); +} + + // create the stack frame + StackFrame* frame = new(std::nothrow) StackFrame(STACK_FRAME_TYPE_STANDARD, + cpuState, framePointer, cpuState->InstructionPointer()); + if (frame == NULL) + return B_NO_MEMORY; + + frame->SetReturnAddress(previousCpuState->InstructionPointer()); + // Note, this is correct, since we actually retrieved the return + // address. Our caller will fix the IP for us. + + _previousFrame = frame; + _previousCpuState = previousCpuStateReference.Detach(); + + return B_OK; } diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h index 3e024a1d04..f723273851 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h @@ -22,12 +22,14 @@ class FileManager; class FileSourceCode; class LocatableFile; class SourceCode; +class TeamMemory; class DwarfImageDebugInfo : public SpecificImageDebugInfo { public: DwarfImageDebugInfo(const ImageInfo& imageInfo, Architecture* architecture, + TeamMemory* teamMemory, FileManager* fileManager, DwarfFile* file); virtual ~DwarfImageDebugInfo(); @@ -57,6 +59,9 @@ public: virtual status_t AddSourceCodeInfo(LocatableFile* file, FileSourceCode* sourceCode); +private: + struct UnwindTargetInterface; + private: status_t _AddSourceCodeInfo(CompilationUnit* unit, FileSourceCode* sourceCode, @@ -68,6 +73,7 @@ private: BLocker fLock; ImageInfo fImageInfo; Architecture* fArchitecture; + TeamMemory* fTeamMemory; FileManager* fFileManager; DwarfFile* fFile; ElfSegment* fTextSegment; diff --git a/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp index 99c1f81380..2b4b62a9b6 100644 --- a/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp @@ -15,9 +15,10 @@ DwarfTeamDebugInfo::DwarfTeamDebugInfo(Architecture* architecture, - FileManager* fileManager) + TeamMemory* teamMemory, FileManager* fileManager) : fArchitecture(architecture), + fTeamMemory(teamMemory), fFileManager(fileManager), fManager(NULL) { @@ -64,7 +65,7 @@ DwarfTeamDebugInfo::CreateImageDebugInfo(const ImageInfo& imageInfo, // create the image debug info DwarfImageDebugInfo* debuggerInfo = new(std::nothrow) DwarfImageDebugInfo( - imageInfo, fArchitecture, fFileManager, file); + imageInfo, fArchitecture, fTeamMemory, fFileManager, file); if (debuggerInfo == NULL) return B_NO_MEMORY; diff --git a/src/apps/debugger/debug_info/DwarfTeamDebugInfo.h b/src/apps/debugger/debug_info/DwarfTeamDebugInfo.h index 555dab45f6..9f6176f6a3 100644 --- a/src/apps/debugger/debug_info/DwarfTeamDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfTeamDebugInfo.h @@ -12,11 +12,13 @@ class Architecture; class DwarfManager; class FileManager; class ImageInfo; +class TeamMemory; class DwarfTeamDebugInfo : public SpecificTeamDebugInfo { public: DwarfTeamDebugInfo(Architecture* architecture, + TeamMemory* teamMemory, FileManager* fileManager); virtual ~DwarfTeamDebugInfo(); @@ -28,6 +30,7 @@ public: private: Architecture* fArchitecture; + TeamMemory* fTeamMemory; FileManager* fFileManager; DwarfManager* fManager; }; diff --git a/src/apps/debugger/debug_info/TeamDebugInfo.cpp b/src/apps/debugger/debug_info/TeamDebugInfo.cpp index 18cd439af2..c2de541746 100644 --- a/src/apps/debugger/debug_info/TeamDebugInfo.cpp +++ b/src/apps/debugger/debug_info/TeamDebugInfo.cpp @@ -14,6 +14,7 @@ #include #include "Architecture.h" +#include "DebuggerInterface.h" #include "DebuggerTeamDebugInfo.h" #include "DisassembledCode.h" #include "DwarfTeamDebugInfo.h" @@ -298,7 +299,7 @@ TeamDebugInfo::Init() // DWARF DwarfTeamDebugInfo* dwarfInfo = new(std::nothrow) DwarfTeamDebugInfo( - fArchitecture, fFileManager); + fArchitecture, fDebuggerInterface, fFileManager); if (dwarfInfo == NULL || !fSpecificInfos.AddItem(dwarfInfo)) { delete dwarfInfo; return B_NO_MEMORY; diff --git a/src/apps/debugger/dwarf/CfaContext.cpp b/src/apps/debugger/dwarf/CfaContext.cpp new file mode 100644 index 0000000000..2b03592008 --- /dev/null +++ b/src/apps/debugger/dwarf/CfaContext.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include "CfaContext.h" + + +CfaContext::CfaContext(dwarf_addr_t targetLocation, + dwarf_addr_t initialLocation) + : + fTargetLocation(targetLocation), + fLocation(initialLocation), + fCodeAlignment(0), + fDataAlignment(0), + fReturnAddressRegister(0), + fRuleSet(NULL), + fInitialRuleSet(NULL), + fRuleSetStack(10, true) +{ +} + + +CfaContext::~CfaContext() +{ + delete fRuleSet; + delete fInitialRuleSet; +} + + +status_t +CfaContext::Init(uint32 registerCount) +{ + fRuleSet = new(std::nothrow) CfaRuleSet; + if (fRuleSet == NULL) + return B_NO_MEMORY; + + return fRuleSet->Init(registerCount); +} + + +status_t +CfaContext::SaveInitialRuleSet() +{ + fInitialRuleSet = fRuleSet->Clone(); + if (fInitialRuleSet == NULL) + return B_NO_MEMORY; + return B_OK; +} + + +status_t +CfaContext::PushRuleSet() +{ + CfaRuleSet* ruleSet = fRuleSet->Clone(); + if (ruleSet == NULL || !fRuleSetStack.AddItem(ruleSet)) { + delete ruleSet; + return B_NO_MEMORY; + } + + return B_OK; +} + + +status_t +CfaContext::PopRuleSet() +{ + if (fRuleSetStack.IsEmpty()) + return B_BAD_DATA; + + delete fRuleSet; + fRuleSet = fRuleSetStack.RemoveItemAt( + fRuleSetStack.CountItems() - 1); + + return B_OK; +} + + +void +CfaContext::SetLocation(dwarf_addr_t location) +{ + fLocation = location; +} + + +void +CfaContext::SetCodeAlignment(uint32 alignment) +{ + fCodeAlignment = alignment; +} + + +void +CfaContext::SetDataAlignment(int32 alignment) +{ + fDataAlignment = alignment; +} + + +void +CfaContext::SetReturnAddressRegister(uint32 reg) +{ + fReturnAddressRegister = reg; +} + + +void +CfaContext::RestoreRegisterRule(uint32 reg) +{ + if (CfaRule* rule = RegisterRule(reg)) { + if (fInitialRuleSet != NULL) + *rule = *fInitialRuleSet->RegisterRule(reg); + } +} diff --git a/src/apps/debugger/dwarf/CfaContext.h b/src/apps/debugger/dwarf/CfaContext.h new file mode 100644 index 0000000000..b3033463d1 --- /dev/null +++ b/src/apps/debugger/dwarf/CfaContext.h @@ -0,0 +1,68 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef CFA_CONTEXT_H +#define CFA_CONTEXT_H + + +#include + +#include "CfaRuleSet.h" + + +class CfaContext { +public: + CfaContext(dwarf_addr_t targetLocation, + dwarf_addr_t initialLocation); + ~CfaContext(); + + status_t Init(uint32 registerCount); + status_t SaveInitialRuleSet(); + + status_t PushRuleSet(); + status_t PopRuleSet(); + + dwarf_addr_t TargetLocation() const + { return fTargetLocation; } + + dwarf_addr_t Location() const + { return fLocation; } + void SetLocation(dwarf_addr_t location); + + uint32 CodeAlignment() const + { return fCodeAlignment; } + void SetCodeAlignment(uint32 alignment); + + int32 DataAlignment() const + { return fDataAlignment; } + void SetDataAlignment(int32 alignment); + + uint32 ReturnAddressRegister() const + { return fReturnAddressRegister; } + void SetReturnAddressRegister(uint32 reg); + + CfaCfaRule* GetCfaCfaRule() const + { return fRuleSet->GetCfaCfaRule(); } + CfaRule* RegisterRule(uint32 index) const + { return fRuleSet->RegisterRule(index); } + + void RestoreRegisterRule(uint32 reg); + +private: + typedef BObjectList RuleSetList; + +private: + dwarf_addr_t fTargetLocation; + dwarf_addr_t fLocation; + uint32 fCodeAlignment; + int32 fDataAlignment; + uint32 fReturnAddressRegister; + CfaRuleSet* fRuleSet; + CfaRuleSet* fInitialRuleSet; + RuleSetList fRuleSetStack; +}; + + + +#endif // CFA_CONTEXT_H diff --git a/src/apps/debugger/dwarf/CfaRule.h b/src/apps/debugger/dwarf/CfaRule.h new file mode 100644 index 0000000000..a1939c2a11 --- /dev/null +++ b/src/apps/debugger/dwarf/CfaRule.h @@ -0,0 +1,212 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef CFA_RULE_H +#define CFA_RULE_H + + +#include "DwarfTypes.h" + + +enum cfa_rule_type { + CFA_RULE_UNDEFINED, + CFA_RULE_SAME_VALUE, + CFA_RULE_LOCATION_OFFSET, + CFA_RULE_VALUE_OFFSET, + CFA_RULE_REGISTER, + CFA_RULE_LOCATION_EXPRESSION, + CFA_RULE_VALUE_EXPRESSION +}; + + +enum cfa_cfa_rule_type { + CFA_CFA_RULE_UNDEFINED, + CFA_CFA_RULE_REGISTER_OFFSET, + CFA_CFA_RULE_EXPRESSION +}; + + +struct CfaExpression { + const void* block; + size_t size; +}; + + +class CfaRule { +public: + inline CfaRule(); + + cfa_rule_type Type() const { return fType; } + + int64 Offset() const { return fOffset; } + uint32 Register() const { return fRegister; } + const CfaExpression& Expression() const { return fExpression; } + + inline void SetToUndefined(); + inline void SetToSameValue(); + inline void SetToLocationOffset(int64 offset); + inline void SetToValueOffset(int64 offset); + inline void SetToRegister(uint32 reg); + inline void SetToLocationExpression(const void* block, + size_t size); + inline void SetToValueExpression(const void* block, + size_t size); + +private: + cfa_rule_type fType; + union { + int64 fOffset; + uint32 fRegister; + CfaExpression fExpression; + }; +}; + + +class CfaCfaRule { +public: + inline CfaCfaRule(); + + cfa_cfa_rule_type Type() const { return fType; } + + uint64 Offset() const + { return fRegisterOffset.offset; } + uint32 Register() const + { return fRegisterOffset.reg; } + const CfaExpression& Expression() const { return fExpression; } + + inline void SetToUndefined(); + inline void SetToRegisterOffset(uint32 reg, uint64 offset); + inline void SetToExpression(const void* block, size_t size); + + inline void SetRegister(uint32 reg); + inline void SetOffset(uint64 offset); + +private: + cfa_cfa_rule_type fType; + union { + struct { + uint64 offset; + uint32 reg; + } fRegisterOffset; + CfaExpression fExpression; + }; +}; + + +// #pragma mark - CfaRule + + +CfaRule::CfaRule() + : + fType(CFA_RULE_UNDEFINED) +{ +} + + +void +CfaRule::SetToUndefined() +{ + fType = CFA_RULE_UNDEFINED; +} + + +void +CfaRule::SetToSameValue() +{ + fType = CFA_RULE_SAME_VALUE; +} + + +void +CfaRule::SetToLocationOffset(int64 offset) +{ + fType = CFA_RULE_LOCATION_OFFSET; + fOffset = offset; +} + + +void +CfaRule::SetToValueOffset(int64 offset) +{ + fType = CFA_RULE_VALUE_OFFSET; + fOffset = offset; +} + + +void +CfaRule::SetToRegister(uint32 reg) +{ + fType = CFA_RULE_REGISTER; + fRegister = reg; +} + + +void +CfaRule::SetToLocationExpression(const void* block, size_t size) +{ + fType = CFA_RULE_LOCATION_EXPRESSION; + fExpression.block = block; + fExpression.size = size; +} + + +void +CfaRule::SetToValueExpression(const void* block, size_t size) +{ + fType = CFA_RULE_VALUE_EXPRESSION; + fExpression.block = block; + fExpression.size = size; +} + + +// #pragma mark - CfaCfaRule + + +CfaCfaRule::CfaCfaRule() + : + fType(CFA_CFA_RULE_UNDEFINED) +{ +} + + +void +CfaCfaRule::SetToUndefined() +{ + fType = CFA_CFA_RULE_UNDEFINED; +} + + +void +CfaCfaRule::SetToRegisterOffset(uint32 reg, uint64 offset) +{ + fType = CFA_CFA_RULE_REGISTER_OFFSET; + fRegisterOffset.reg = reg; + fRegisterOffset.offset = offset; +} + + +void +CfaCfaRule::SetToExpression(const void* block, size_t size) +{ + fType = CFA_CFA_RULE_EXPRESSION; + fExpression.block = block; + fExpression.size = size; +} + + +void +CfaCfaRule::SetRegister(uint32 reg) +{ + fRegisterOffset.reg = reg; +} + + +void +CfaCfaRule::SetOffset(uint64 offset) +{ + fRegisterOffset.offset = offset; +} + + +#endif // CFA_RULE_H diff --git a/src/apps/debugger/dwarf/CfaRuleSet.cpp b/src/apps/debugger/dwarf/CfaRuleSet.cpp new file mode 100644 index 0000000000..c88396d6fb --- /dev/null +++ b/src/apps/debugger/dwarf/CfaRuleSet.cpp @@ -0,0 +1,59 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include + +#include "CfaRuleSet.h" + + +CfaRuleSet::CfaRuleSet() + : + fRegisterRules(NULL), + fRegisterCount(0) +{ +} + + +status_t +CfaRuleSet::Init(uint32 registerCount) +{ + fRegisterRules = new(std::nothrow) CfaRule[registerCount]; + if (fRegisterRules == NULL) + return B_NO_MEMORY; + + fRegisterCount = registerCount; + + return B_OK; +} + + +CfaRuleSet* +CfaRuleSet::Clone() const +{ + CfaRuleSet* other = new(std::nothrow) CfaRuleSet; + if (other == NULL) + return NULL; + + if (other->Init(fRegisterCount) != B_OK) { + delete other; + return NULL; + } + + other->fCfaCfaRule = fCfaCfaRule; + memcpy(other->fRegisterRules, fRegisterRules, + sizeof(CfaRule) * fRegisterCount); + + return other; +} + + +CfaRule* +CfaRuleSet::RegisterRule(uint32 index) const +{ + return index < fRegisterCount ? fRegisterRules + index : NULL; +} diff --git a/src/apps/debugger/dwarf/CfaRuleSet.h b/src/apps/debugger/dwarf/CfaRuleSet.h new file mode 100644 index 0000000000..11873a49a2 --- /dev/null +++ b/src/apps/debugger/dwarf/CfaRuleSet.h @@ -0,0 +1,31 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef CFA_RULE_SET_H +#define CFA_RULE_SET_H + + +#include "CfaRule.h" + + +class CfaRuleSet { +public: + CfaRuleSet(); + + status_t Init(uint32 registerCount); + CfaRuleSet* Clone() const; + + CfaCfaRule* GetCfaCfaRule() { return &fCfaCfaRule; } + const CfaCfaRule* GetCfaCfaRule() const { return &fCfaCfaRule; } + + CfaRule* RegisterRule(uint32 index) const; + +private: + CfaCfaRule fCfaCfaRule; + CfaRule* fRegisterRules; + uint32 fRegisterCount; +}; + + +#endif // CFA_RULE_SET_H diff --git a/src/apps/debugger/dwarf/Dwarf.h b/src/apps/debugger/dwarf/Dwarf.h index 9543cfaee1..f8765019b0 100644 --- a/src/apps/debugger/dwarf/Dwarf.h +++ b/src/apps/debugger/dwarf/Dwarf.h @@ -450,7 +450,13 @@ enum { DW_CFA_val_offset_sf = 0x15, DW_CFA_val_expression = 0x16, DW_CFA_lo_user = 0x1c, - DW_CFA_hi_user = 0x3f + DW_CFA_hi_user = 0x3f, + + // extensions + DW_CFA_MIPS_advance_loc8 = 0x1d, + DW_CFA_GNU_window_save = 0x2d, + DW_CFA_GNU_args_size = 0x2e, + DW_CFA_GNU_negative_offset_extended = 0x2f }; diff --git a/src/apps/debugger/dwarf/DwarfFile.cpp b/src/apps/debugger/dwarf/DwarfFile.cpp index 342109b652..24e6e9d37a 100644 --- a/src/apps/debugger/dwarf/DwarfFile.cpp +++ b/src/apps/debugger/dwarf/DwarfFile.cpp @@ -3,6 +3,7 @@ * Distributed under the terms of the MIT License. */ + #include "DwarfFile.h" #include @@ -13,8 +14,10 @@ #include "AttributeClasses.h" #include "AttributeValue.h" #include "AbbreviationTable.h" +#include "CfaContext.h" #include "CompilationUnit.h" #include "DataReader.h" +#include "DwarfTargetInterface.h" #include "ElfFile.h" #include "TagNames.h" #include "TargetAddressRangeList.h" @@ -29,6 +32,7 @@ DwarfFile::DwarfFile() fDebugStringSection(NULL), fDebugRangesSection(NULL), fDebugLineSection(NULL), + fDebugFrameSection(NULL), fCompilationUnits(20, true), fCurrentCompilationUnit(NULL), fFinished(false), @@ -48,6 +52,7 @@ DwarfFile::~DwarfFile() fElfFile->PutSection(fDebugStringSection); fElfFile->PutSection(fDebugRangesSection); fElfFile->PutSection(fDebugLineSection); + fElfFile->PutSection(fDebugFrameSection); delete fElfFile; } @@ -81,10 +86,11 @@ DwarfFile::Load(const char* fileName) return B_ERROR; } - // not mandatory sections + // non mandatory sections fDebugStringSection = fElfFile->GetSection(".debug_str"); fDebugRangesSection = fElfFile->GetSection(".debug_ranges"); fDebugLineSection = fElfFile->GetSection(".debug_line"); + fDebugFrameSection = fElfFile->GetSection(".debug_frame"); // iterate through the debug info section DataReader dataReader(fDebugInfoSection->Data(), @@ -215,6 +221,184 @@ DwarfFile::CompilationUnitForDIE(const DebugInfoEntry* entry) const } +status_t +DwarfFile::UnwindCallFrame(target_addr_t location, + const DwarfTargetInterface* inputInterface, + DwarfTargetInterface* outputInterface, target_addr_t& _framePointer) +{ + if (fDebugFrameSection == NULL) + return B_ENTRY_NOT_FOUND; + +printf("DwarfFile::UnwindCallFrame(%#llx)\n", location); + + DataReader dataReader((uint8*)fDebugFrameSection->Data(), + fDebugFrameSection->Size()); + + while (dataReader.BytesRemaining() > 0) { + // length + bool dwarf64; + uint64 length = dataReader.ReadInitialLength(dwarf64); + if (length > (uint64)dataReader.BytesRemaining()) + return B_BAD_DATA; + off_t lengthOffset = dataReader.Offset(); + + // CIE ID/CIE pointer + uint64 cieID = dwarf64 + ? dataReader.Read(0) : dataReader.Read(0); + if (dwarf64 ? cieID == 0xffffffffffffffffULL : cieID == 0xffffffff) { + // this is a CIE -- skip it + } else { + // this is a FDE + dwarf_addr_t initialLocation = dataReader.Read(0); + dwarf_size_t addressRange = dataReader.Read(0); + + if (dataReader.HasOverflow()) + return B_BAD_DATA; + + if (location >= initialLocation + && location < initialLocation + addressRange) { + // This is the FDE we're looking for. + off_t remaining = (off_t)length + - (dataReader.Offset() - lengthOffset); + if (remaining < 0) + return B_BAD_DATA; +printf(" found fde: length: %llu (%lld), CIE offset: %llu, location: %#lx, range: %#lx\n", length, remaining, cieID, +initialLocation, addressRange); + + CfaContext context(location, initialLocation); + uint32 registerCount = outputInterface->CountRegisters(); + status_t error = context.Init(registerCount); + if (error != B_OK) + return error; + + // Init the initial register rules. The DWARF 3 specs on the + // matter: "The default rule for all columns before + // interpretation of the initial instructions is the undefined + // rule. However, an ABI authoring body or a compilation system + // authoring body may specify an alternate default value for any + // or all columns." + // GCC's assumes the "same value" rule for all callee preserved + // registers. We set them respectively. + for (uint32 i = 0; i < registerCount; i++) { + if (outputInterface->IsCalleePreservedRegister(i)) + context.RegisterRule(i)->SetToSameValue(); + } + + // process the CIE + error = _ParseCIE(context, cieID); + if (error != B_OK) + return error; + + error = context.SaveInitialRuleSet(); + if (error != B_OK) + return error; + + error = _ParseFrameInfoInstructions(context, + dataReader.Offset(), remaining); + if (error != B_OK) + return error; + +printf(" found row!\n"); + + // apply the rules of the final row + // get the frameAddress first + dwarf_addr_t frameAddress; + CfaCfaRule* cfaCfaRule = context.GetCfaCfaRule(); + switch (cfaCfaRule->Type()) { + case CFA_CFA_RULE_REGISTER_OFFSET: + { + BVariant value; + if (!inputInterface->GetRegisterValue( + cfaCfaRule->Register(), value) + || !value.IsNumber()) { + return B_UNSUPPORTED; + } + frameAddress = value.ToUInt64() + cfaCfaRule->Offset(); + break; + } + case CFA_CFA_RULE_EXPRESSION: +// TODO: Implement! + return B_UNSUPPORTED; + case CFA_CFA_RULE_UNDEFINED: + default: + return B_BAD_VALUE; + } +printf(" frame address: %#lx\n", frameAddress); + + // apply the register rules + for (uint32 i = 0; i < registerCount; i++) { +printf(" reg %lu\n", i); + uint32 valueType = outputInterface->RegisterValueType(i); + if (valueType == 0) + continue; + + CfaRule* rule = context.RegisterRule(i); + if (rule == NULL) + continue; + + // apply the rule + switch (rule->Type()) { + case CFA_RULE_SAME_VALUE: + { +printf(" -> CFA_RULE_SAME_VALUE\n"); + BVariant value; + if (inputInterface->GetRegisterValue(i, value)) + outputInterface->SetRegisterValue(i, value); + break; + } + case CFA_RULE_LOCATION_OFFSET: + { +printf(" -> CFA_RULE_LOCATION_OFFSET: %lld\n", rule->Offset()); + BVariant value; + if (inputInterface->ReadValueFromMemory( + frameAddress + rule->Offset(), valueType, + value)) { + outputInterface->SetRegisterValue(i, value); + } + break; + } + case CFA_RULE_VALUE_OFFSET: +printf(" -> CFA_RULE_VALUE_OFFSET\n"); + outputInterface->SetRegisterValue(i, + frameAddress + rule->Offset()); + break; + case CFA_RULE_REGISTER: + { +printf(" -> CFA_RULE_REGISTER\n"); + BVariant value; + if (inputInterface->GetRegisterValue( + rule->Register(), value)) { + outputInterface->SetRegisterValue(i, value); + } + break; + } + case CFA_RULE_LOCATION_EXPRESSION: +printf(" -> CFA_RULE_LOCATION_EXPRESSION\n"); +// TODO:... + break; + case CFA_RULE_VALUE_EXPRESSION: +printf(" -> CFA_RULE_VALUE_EXPRESSION\n"); +// TODO:... + break; + case CFA_RULE_UNDEFINED: +printf(" -> CFA_RULE_UNDEFINED\n"); + default: + break; + } + } + + _framePointer = frameAddress; + return B_OK; + } + } + + dataReader.SeekAbsolute(lengthOffset + length); + } + + return B_ENTRY_NOT_FOUND; +} + + status_t DwarfFile::_ParseCompilationUnit(CompilationUnit* unit) { @@ -736,6 +920,375 @@ printf("DwarfFile::_ParseLineInfo(%p), offset: %lu\n", unit, offset); } +status_t +DwarfFile::_ParseCIE(CfaContext& context, dwarf_off_t cieOffset) +{ + if (cieOffset < 0 || cieOffset >= fDebugFrameSection->Size()) + return B_BAD_DATA; + + DataReader dataReader((uint8*)fDebugFrameSection->Data() + cieOffset, + fDebugFrameSection->Size() - cieOffset); + + // length + bool dwarf64; + uint64 length = dataReader.ReadInitialLength(dwarf64); + if (length > (uint64)dataReader.BytesRemaining()) + return B_BAD_DATA; + off_t lengthOffset = dataReader.Offset(); + + // CIE ID/CIE pointer + uint64 cieID = dwarf64 + ? dataReader.Read(0) : dataReader.Read(0); + if (dwarf64 ? cieID != 0xffffffffffffffffULL : cieID != 0xffffffff) + return B_BAD_DATA; + + uint8 version = dataReader.Read(0); + const char* augmentation = dataReader.ReadString(); + if (version != 1 || augmentation == NULL || *augmentation != '\0') + return B_UNSUPPORTED; + + context.SetCodeAlignment(dataReader.ReadUnsignedLEB128(0)); + context.SetDataAlignment(dataReader.ReadSignedLEB128(0)); + context.SetReturnAddressRegister(dataReader.ReadUnsignedLEB128(0)); +printf(" cie: length: %llu, version: %u, augmentation: \"%s\", " +"aligment: code: %lu, data: %ld, return address reg: %lu\n", +length, version, augmentation, context.CodeAlignment(), context.DataAlignment(), +context.ReturnAddressRegister()); + + if (dataReader.HasOverflow()) + return B_BAD_DATA; + off_t remaining = (off_t)length + - (dataReader.Offset() - lengthOffset); + if (remaining < 0) + return B_BAD_DATA; + + return _ParseFrameInfoInstructions(context, dataReader.Offset(), remaining); +} + + +status_t +DwarfFile::_ParseFrameInfoInstructions(CfaContext& context, + dwarf_off_t instructionOffset, dwarf_off_t instructionSize) +{ + if (instructionSize <= 0) + return B_OK; + + DataReader dataReader( + (uint8*)fDebugFrameSection->Data() + instructionOffset, + instructionSize); + + while (dataReader.BytesRemaining() > 0) { +printf(" [%2lld]", dataReader.BytesRemaining()); + uint8 opcode = dataReader.Read(0); + if ((opcode >> 6) != 0) { + uint32 operand = opcode & 0x3f; + + switch (opcode >> 6) { + case DW_CFA_advance_loc: + { +printf(" DW_CFA_advance_loc: %#lx\n", operand); + dwarf_addr_t location = context.Location() + + operand * context.CodeAlignment(); + if (location > context.TargetLocation()) + return B_OK; + context.SetLocation(location); + break; + } + case DW_CFA_offset: + { + uint64 offset = dataReader.ReadUnsignedLEB128(0); +printf(" DW_CFA_offset: reg: %lu, offset: %llu\n", operand, offset); + if (CfaRule* rule = context.RegisterRule(operand)) { + rule->SetToLocationOffset( + offset * context.DataAlignment()); + } + break; + } + case DW_CFA_restore: + { +printf(" DW_CFA_restore: %#lx\n", operand); + context.RestoreRegisterRule(operand); + break; + } + } + } else { + switch (opcode) { + case DW_CFA_nop: + { + printf(" DW_CFA_nop\n"); + break; + } + case DW_CFA_set_loc: + { + dwarf_addr_t location = dataReader.Read(0); +printf(" DW_CFA_set_loc: %#lx\n", location); + if (location < context.Location()) + return B_BAD_VALUE; + if (location > context.TargetLocation()) + return B_OK; + context.SetLocation(location); + break; + } + case DW_CFA_advance_loc1: + { + uint32 delta = dataReader.Read(0); +printf(" DW_CFA_advance_loc1: %#lx\n", delta); + dwarf_addr_t location = context.Location() + + delta * context.CodeAlignment(); + if (location > context.TargetLocation()) + return B_OK; + context.SetLocation(location); + break; + } + case DW_CFA_advance_loc2: + { + uint32 delta = dataReader.Read(0); +printf(" DW_CFA_advance_loc2: %#lx\n", delta); + dwarf_addr_t location = context.Location() + + delta * context.CodeAlignment(); + if (location > context.TargetLocation()) + return B_OK; + context.SetLocation(location); + break; + } + case DW_CFA_advance_loc4: + { + uint32 delta = dataReader.Read(0); +printf(" DW_CFA_advance_loc4: %#lx\n", delta); + dwarf_addr_t location = context.Location() + + delta * context.CodeAlignment(); + if (location > context.TargetLocation()) + return B_OK; + context.SetLocation(location); + break; + } + case DW_CFA_offset_extended: + { + uint32 reg = dataReader.ReadUnsignedLEB128(0); + uint64 offset = dataReader.ReadUnsignedLEB128(0); +printf(" DW_CFA_offset_extended: reg: %lu, offset: %llu\n", reg, offset); + if (CfaRule* rule = context.RegisterRule(reg)) { + rule->SetToLocationOffset( + offset * context.DataAlignment()); + } + break; + } + case DW_CFA_restore_extended: + { + uint32 reg = dataReader.ReadUnsignedLEB128(0); +printf(" DW_CFA_restore_extended: %#lx\n", reg); + context.RestoreRegisterRule(reg); + break; + } + case DW_CFA_undefined: + { + uint32 reg = dataReader.ReadUnsignedLEB128(0); +printf(" DW_CFA_undefined: %lu\n", reg); + if (CfaRule* rule = context.RegisterRule(reg)) + rule->SetToUndefined(); + break; + } + case DW_CFA_same_value: + { + uint32 reg = dataReader.ReadUnsignedLEB128(0); +printf(" DW_CFA_same_value: %lu\n", reg); + if (CfaRule* rule = context.RegisterRule(reg)) + rule->SetToSameValue(); + break; + } + case DW_CFA_register: + { + uint32 reg1 = dataReader.ReadUnsignedLEB128(0); + uint32 reg2 = dataReader.ReadUnsignedLEB128(0); +printf(" DW_CFA_register: reg1: %lu, reg2: %lu\n", reg1, reg2); + if (CfaRule* rule = context.RegisterRule(reg1)) + rule->SetToValueOffset(reg2); + break; + } + case DW_CFA_remember_state: + { +printf(" DW_CFA_remember_state\n"); + status_t error = context.PushRuleSet(); + if (error != B_OK) + return error; + break; + } + case DW_CFA_restore_state: + { +printf(" DW_CFA_restore_state\n"); + status_t error = context.PopRuleSet(); + if (error != B_OK) + return error; + break; + } + case DW_CFA_def_cfa: + { + uint32 reg = dataReader.ReadUnsignedLEB128(0); + uint64 offset = dataReader.ReadUnsignedLEB128(0); +printf(" DW_CFA_def_cfa: reg: %lu, offset: %llu\n", reg, offset); + context.GetCfaCfaRule()->SetToRegisterOffset(reg, offset); + break; + } + case DW_CFA_def_cfa_register: + { + uint32 reg = dataReader.ReadUnsignedLEB128(0); +printf(" DW_CFA_def_cfa_register: %lu\n", reg); + if (context.GetCfaCfaRule()->Type() + != CFA_CFA_RULE_REGISTER_OFFSET) { + return B_BAD_DATA; + } + context.GetCfaCfaRule()->SetRegister(reg); + break; + } + case DW_CFA_def_cfa_offset: + { + uint64 offset = dataReader.ReadUnsignedLEB128(0); +printf(" DW_CFA_def_cfa_offset: %llu\n", offset); + if (context.GetCfaCfaRule()->Type() + != CFA_CFA_RULE_REGISTER_OFFSET) { + return B_BAD_DATA; + } + context.GetCfaCfaRule()->SetOffset(offset); + break; + } + case DW_CFA_def_cfa_expression: + { + uint8* block = (uint8*)dataReader.Data(); + uint64 blockLength = dataReader.ReadUnsignedLEB128(0); + dataReader.Skip(blockLength); +printf(" DW_CFA_def_cfa_expression: %p, %llu\n", block, blockLength); + context.GetCfaCfaRule()->SetToExpression(block, + blockLength); + break; + } + case DW_CFA_expression: + { + uint32 reg = dataReader.ReadUnsignedLEB128(0); + uint8* block = (uint8*)dataReader.Data(); + uint64 blockLength = dataReader.ReadUnsignedLEB128(0); + dataReader.Skip(blockLength); +printf(" DW_CFA_expression: reg: %lu, block: %p, %llu\n", reg, block, blockLength); + if (CfaRule* rule = context.RegisterRule(reg)) + rule->SetToLocationExpression(block, blockLength); + break; + } + case DW_CFA_offset_extended_sf: + { + uint32 reg = dataReader.ReadUnsignedLEB128(0); + int64 offset = dataReader.ReadSignedLEB128(0); +printf(" DW_CFA_offset_extended: reg: %lu, offset: %lld\n", reg, offset); + if (CfaRule* rule = context.RegisterRule(reg)) { + rule->SetToLocationOffset( + offset * (int32)context.DataAlignment()); + } + break; + } + case DW_CFA_def_cfa_sf: + { + uint32 reg = dataReader.ReadUnsignedLEB128(0); + int64 offset = dataReader.ReadSignedLEB128(0); +printf(" DW_CFA_def_cfa_sf: reg: %lu, offset: %lld\n", reg, offset); + context.GetCfaCfaRule()->SetToRegisterOffset(reg, + offset * (int32)context.DataAlignment()); + break; + } + case DW_CFA_def_cfa_offset_sf: + { + int64 offset = dataReader.ReadSignedLEB128(0); +printf(" DW_CFA_def_cfa_offset: %lld\n", offset); + if (context.GetCfaCfaRule()->Type() + != CFA_CFA_RULE_REGISTER_OFFSET) { + return B_BAD_DATA; + } + context.GetCfaCfaRule()->SetOffset( + offset * (int32)context.DataAlignment()); + break; + } + case DW_CFA_val_offset: + { + uint32 reg = dataReader.ReadUnsignedLEB128(0); + uint64 offset = dataReader.ReadUnsignedLEB128(0); +printf(" DW_CFA_val_offset: reg: %lu, offset: %llu\n", reg, offset); + if (CfaRule* rule = context.RegisterRule(reg)) { + rule->SetToValueOffset( + offset * context.DataAlignment()); + } + break; + } + case DW_CFA_val_offset_sf: + { + uint32 reg = dataReader.ReadUnsignedLEB128(0); + int64 offset = dataReader.ReadSignedLEB128(0); +printf(" DW_CFA_val_offset_sf: reg: %lu, offset: %lld\n", reg, offset); + if (CfaRule* rule = context.RegisterRule(reg)) { + rule->SetToValueOffset( + offset * (int32)context.DataAlignment()); + } + break; + } + case DW_CFA_val_expression: + { + uint32 reg = dataReader.ReadUnsignedLEB128(0); + uint8* block = (uint8*)dataReader.Data(); + uint64 blockLength = dataReader.ReadUnsignedLEB128(0); + dataReader.Skip(blockLength); +printf(" DW_CFA_val_expression: reg: %lu, block: %p, %llu\n", reg, block, blockLength); + if (CfaRule* rule = context.RegisterRule(reg)) + rule->SetToValueExpression(block, blockLength); + break; + } + + // extensions + case DW_CFA_MIPS_advance_loc8: + { + uint64 delta = dataReader.Read(0); +printf(" DW_CFA_MIPS_advance_loc8: %#llx\n", delta); + dwarf_addr_t location = context.Location() + + delta * context.CodeAlignment(); + if (location > context.TargetLocation()) + return B_OK; + context.SetLocation(location); + break; + } + case DW_CFA_GNU_window_save: + { + // SPARC specific, no args + printf(" DW_CFA_GNU_window_save\n"); + // TODO: Implement once we have SPARC support! + break; + } + case DW_CFA_GNU_args_size: + { + // Updates the total size of arguments on the stack. + uint64 size = dataReader.ReadUnsignedLEB128(0); + printf(" DW_CFA_GNU_args_size: %llu\n", size); +// TODO: Implement! + break; + } + case DW_CFA_GNU_negative_offset_extended: + { + // obsolete + uint32 reg = dataReader.ReadUnsignedLEB128(0); + int64 offset = dataReader.ReadSignedLEB128(0); +printf(" DW_CFA_GNU_negative_offset_extended: reg: %lu, offset: %lld\n", reg, offset); + if (CfaRule* rule = context.RegisterRule(reg)) { + rule->SetToLocationOffset( + offset * (int32)context.DataAlignment()); + } + break; + } + + default: + printf(" unknown opcode %u!\n", opcode); + return B_BAD_DATA; + } + } + } + + return B_OK; +} + + status_t DwarfFile::_GetAbbreviationTable(off_t offset, AbbreviationTable*& _table) { diff --git a/src/apps/debugger/dwarf/DwarfFile.h b/src/apps/debugger/dwarf/DwarfFile.h index b177320400..af328b1f57 100644 --- a/src/apps/debugger/dwarf/DwarfFile.h +++ b/src/apps/debugger/dwarf/DwarfFile.h @@ -5,6 +5,7 @@ #ifndef DWARF_FILE_H #define DWARF_FILE_H + #include #include @@ -13,8 +14,10 @@ class AbbreviationEntry; class AbbreviationTable; +class CfaContext; class CompilationUnit; class DataReader; +class DwarfTargetInterface; class ElfFile; class ElfSection; class TargetAddressRangeList; @@ -36,6 +39,11 @@ public: CompilationUnit* CompilationUnitForDIE( const DebugInfoEntry* entry) const; + status_t UnwindCallFrame(target_addr_t location, + const DwarfTargetInterface* inputInterface, + DwarfTargetInterface* outputInterface, + target_addr_t& _framePointer); + private: typedef DoublyLinkedList AbbreviationTableList; typedef BObjectList CompilationUnitList; @@ -53,6 +61,12 @@ private: status_t _ParseLineInfo(CompilationUnit* unit); + status_t _ParseCIE(CfaContext& context, + dwarf_off_t cieOffset); + status_t _ParseFrameInfoInstructions(CfaContext& context, + dwarf_off_t instructionOffset, + dwarf_off_t instructionSize); + status_t _GetAbbreviationTable(off_t offset, AbbreviationTable*& _table); @@ -69,6 +83,7 @@ private: ElfSection* fDebugStringSection; ElfSection* fDebugRangesSection; ElfSection* fDebugLineSection; + ElfSection* fDebugFrameSection; AbbreviationTableList fAbbreviationTables; DebugInfoEntryFactory fDebugInfoFactory; CompilationUnitList fCompilationUnits; diff --git a/src/apps/debugger/dwarf/DwarfTargetInterface.cpp b/src/apps/debugger/dwarf/DwarfTargetInterface.cpp new file mode 100644 index 0000000000..4541c1b48e --- /dev/null +++ b/src/apps/debugger/dwarf/DwarfTargetInterface.cpp @@ -0,0 +1,12 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "DwarfTargetInterface.h" + + +DwarfTargetInterface::~DwarfTargetInterface() +{ +} diff --git a/src/apps/debugger/dwarf/DwarfTargetInterface.h b/src/apps/debugger/dwarf/DwarfTargetInterface.h new file mode 100644 index 0000000000..91c8453d7a --- /dev/null +++ b/src/apps/debugger/dwarf/DwarfTargetInterface.h @@ -0,0 +1,39 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef DWARF_TARGET_INTERFACE_H +#define DWARF_TARGET_INTERFACE_H + + +#include + +#include "Types.h" + + +class Register; + + +class DwarfTargetInterface { +public: + virtual ~DwarfTargetInterface(); + + virtual uint32 CountRegisters() const = 0; + virtual uint32 RegisterValueType(uint32 index) const = 0; + + virtual bool GetRegisterValue(uint32 index, + BVariant& _value) const = 0; + virtual bool SetRegisterValue(uint32 index, + const BVariant& value) = 0; + virtual bool IsCalleePreservedRegister(uint32 index) const + = 0; + + virtual bool ReadMemory(target_addr_t address, void* buffer, + size_t size) const = 0; + virtual bool ReadValueFromMemory(target_addr_t address, + uint32 valueType, BVariant& _value) const + = 0; +}; + + +#endif // DWARF_TARGET_INTERFACE_H diff --git a/src/apps/debugger/dwarf/Jamfile b/src/apps/debugger/dwarf/Jamfile index 74504a80b8..0728c7f9ed 100644 --- a/src/apps/debugger/dwarf/Jamfile +++ b/src/apps/debugger/dwarf/Jamfile @@ -17,11 +17,14 @@ MergeObject Debugger_dwarf.o AbbreviationTable.cpp AttributeClasses.cpp AttributeValue.cpp + CfaContext.cpp + CfaRuleSet.cpp CompilationUnit.cpp DebugInfoEntries.cpp DebugInfoEntry.cpp DwarfFile.cpp DwarfManager.cpp + DwarfTargetInterface.cpp DwarfUtils.cpp LineNumberProgram.cpp SourceLanguageInfo.cpp