* DWARF: Implemented parsing the DWARF frame info and evaluating it (save for

DWARF expressions). Several related new classes: CfaRule[Set], CfaContext,
  DwarfTargetInterface (for accessing target registers and memory).
* Implemented DwarfImageDebugInfo::CreateFrame(), so the DWARF frame info is
  used for unwinding the stack.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31540 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2009-07-13 18:54:11 +00:00
parent 614e1dc42f
commit f7526300d9
16 changed files with 1295 additions and 8 deletions

View File

@ -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<RegisterMap> toDwarfMapReference(toDwarfMap, true);
Reference<RegisterMap> 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<CpuState> 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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
};

View File

@ -14,6 +14,7 @@
#include <AutoLocker.h>
#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;

View File

@ -0,0 +1,117 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <new>
#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);
}
}

View File

@ -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 <ObjectList.h>
#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<CfaRuleSet> 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

View File

@ -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

View File

@ -0,0 +1,59 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <string.h>
#include <new>
#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;
}

View File

@ -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

View File

@ -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
};

View File

@ -3,6 +3,7 @@
* Distributed under the terms of the MIT License.
*/
#include "DwarfFile.h"
#include <algorithm>
@ -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<uint64>(0) : dataReader.Read<uint32>(0);
if (dwarf64 ? cieID == 0xffffffffffffffffULL : cieID == 0xffffffff) {
// this is a CIE -- skip it
} else {
// this is a FDE
dwarf_addr_t initialLocation = dataReader.Read<dwarf_addr_t>(0);
dwarf_size_t addressRange = dataReader.Read<dwarf_addr_t>(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<uint64>(0) : dataReader.Read<uint32>(0);
if (dwarf64 ? cieID != 0xffffffffffffffffULL : cieID != 0xffffffff)
return B_BAD_DATA;
uint8 version = dataReader.Read<uint8>(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<uint8>(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<dwarf_addr_t>(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<uint8>(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<uint16>(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<uint32>(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<uint64>(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)
{

View File

@ -5,6 +5,7 @@
#ifndef DWARF_FILE_H
#define DWARF_FILE_H
#include <ObjectList.h>
#include <util/DoublyLinkedList.h>
@ -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<AbbreviationTable> AbbreviationTableList;
typedef BObjectList<CompilationUnit> 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;

View File

@ -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()
{
}

View File

@ -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 <Variant.h>
#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

View File

@ -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