Refactor previous commit.

- Keep knowledge of the existence and need to search the different
  frame sections contained within DwarfFile.
This commit is contained in:
Rene Gollent 2012-07-11 21:56:15 -04:00
parent dfa21dfeab
commit c4120026a5
3 changed files with 311 additions and 301 deletions

View File

@ -555,21 +555,8 @@ DwarfImageDebugInfo::CreateFrame(Image* image,
= cpuState->InstructionPointer() - fRelocationDelta;
target_addr_t framePointer;
CompilationUnit* unit = function->GetCompilationUnit();
// first try .debug_frame
if (fFile->HasDebugFrameSection()) {
error = fFile->UnwindCallFrame(false, unit,
function->SubprogramEntry(), instructionPointer, inputInterface,
outputInterface, framePointer);
} else
error = B_ENTRY_NOT_FOUND;
// if that section isn't present, or we couldn't find a match,
// try .eh_frame if possible.
if (error == B_ENTRY_NOT_FOUND && fFile->HasEHFrameSection()) {
error = fFile->UnwindCallFrame(true, unit,
function->SubprogramEntry(), instructionPointer, inputInterface,
outputInterface, framePointer);
}
error = fFile->UnwindCallFrame(unit, function->SubprogramEntry(),
instructionPointer, inputInterface, outputInterface, framePointer);
if (error != B_OK) {
TRACE_CFI("Failed to unwind call frame: %s\n", strerror(error));

View File

@ -535,292 +535,27 @@ DwarfFile::ResolveRangeList(CompilationUnit* unit, uint64 offset) const
status_t
DwarfFile::UnwindCallFrame(bool usingEHFrameSection, CompilationUnit* unit,
DwarfFile::UnwindCallFrame(CompilationUnit* unit,
DIESubprogram* subprogramEntry, target_addr_t location,
const DwarfTargetInterface* inputInterface,
DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
{
ElfSection* currentFrameSection = (usingEHFrameSection)
? fEHFrameSection : fDebugFrameSection;
status_t result = B_ENTRY_NOT_FOUND;
if (currentFrameSection == NULL)
return B_ENTRY_NOT_FOUND;
bool gcc4EHFrameSection = false;
if (usingEHFrameSection) {
gcc4EHFrameSection = !currentFrameSection->IsWritable();
// Crude heuristic for recognizing GCC 4 (Itanium ABI) style
// .eh_frame sections. The ones generated by GCC 2 are writable,
// the ones generated by GCC 4 aren't.
// first try to find the FDE in .debug_frame
if (fDebugFrameSection != NULL) {
result = _UnwindCallFrame(false, unit, subprogramEntry, location,
inputInterface, outputInterface, _framePointer);
}
TRACE_CFI("DwarfFile::UnwindCallFrame(%#llx)\n", location);
DataReader dataReader((uint8*)currentFrameSection->Data(),
currentFrameSection->Size(), unit->AddressSize());
while (dataReader.BytesRemaining() > 0) {
// length
bool dwarf64;
TRACE_CFI_ONLY(off_t entryOffset = dataReader.Offset();)
uint64 length = dataReader.ReadInitialLength(dwarf64);
TRACE_CFI("DwarfFile::UnwindCallFrame(): offset: %" B_PRIdOFF
", length: %" B_PRId64 "\n", entryOffset, length);
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);
// In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does.
if (usingEHFrameSection
? cieID == 0
: (dwarf64
? cieID == 0xffffffffffffffffULL
: cieID == 0xffffffff)) {
// this is a CIE -- skip it
} else {
// this is a FDE
uint64 initialLocationOffset = dataReader.Offset();
target_addr_t initialLocation = dataReader.ReadAddress(0);
target_size_t addressRange = dataReader.ReadAddress(0);
if (dataReader.HasOverflow())
return B_BAD_DATA;
// In the GCC 4 .eh_frame initialLocation is relative to the offset
// of the address.
if (usingEHFrameSection && gcc4EHFrameSection) {
// Note: We need to cast to the exact address width, since the
// initialLocation value can be (and likely is) negative.
if (dwarf64) {
initialLocation = (uint64)currentFrameSection
->LoadAddress() + (uint64)initialLocationOffset
+ (uint64)initialLocation;
} else {
initialLocation = (uint32)currentFrameSection
->LoadAddress() + (uint32)initialLocationOffset
+ (uint32)initialLocation;
}
}
// TODO: For GCC 2 .eh_frame sections things work differently: The
// initial locations are relocated by the runtime loader and
// afterwards point to the absolute addresses. Fortunately the
// relocations that always seem to be used are R_386_RELATIVE, so
// that the value we read from the file is already absolute
// (assuming an unchanged segment load address).
TRACE_CFI("location: %" B_PRIx64 ", initial location: %" B_PRIx64
", address range: %" B_PRIx64 "\n", location, initialLocation,
addressRange);
if (location >= initialLocation
&& location < initialLocation + addressRange) {
// This is the FDE we're looking for.
off_t remaining = lengthOffset + length
- dataReader.Offset();
if (remaining < 0)
return B_BAD_DATA;
// In .eh_frame the CIE offset is a relative back offset.
if (usingEHFrameSection) {
if (cieID > (uint64)lengthOffset) {
TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max "
"possible: %" B_PRIu64 "\n", cieID, lengthOffset);
break;
}
// convert to a section relative offset
cieID = lengthOffset - cieID;
}
TRACE_CFI(" found fde: length: %llu (%lld), CIE offset: %#llx, "
"location: %#llx, range: %#llx\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;
error = outputInterface->InitRegisterRules(context);
if (error != B_OK)
return error;
// process the CIE
CIEAugmentation cieAugmentation;
error = _ParseCIE(currentFrameSection, usingEHFrameSection,
unit, context, cieID, cieAugmentation);
if (error != B_OK)
return error;
// read the FDE augmentation data (if any)
FDEAugmentation fdeAugmentation;
error = cieAugmentation.ReadFDEData(dataReader,
fdeAugmentation);
if (error != B_OK) {
TRACE_CFI(" failed to read FDE augmentation data!\n");
return error;
}
// adjust remaining byte count to take augmentation bytes
// (if any) into account.
remaining = lengthOffset + length
- dataReader.Offset();
error = context.SaveInitialRuleSet();
if (error != B_OK)
return error;
DataReader restrictedReader =
dataReader.RestrictedReader(remaining);
error = _ParseFrameInfoInstructions(unit, context,
restrictedReader);
if (error != B_OK)
return error;
TRACE_CFI(" found row!\n");
// apply the rules of the final row
// get the frameAddress first
target_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:
{
error = EvaluateExpression(unit, subprogramEntry,
cfaCfaRule->Expression().block,
cfaCfaRule->Expression().size,
inputInterface, location, 0, 0, false,
frameAddress);
if (error != B_OK)
return error;
break;
}
case CFA_CFA_RULE_UNDEFINED:
default:
return B_BAD_VALUE;
}
TRACE_CFI(" frame address: %#llx\n", frameAddress);
// apply the register rules
for (uint32 i = 0; i < registerCount; i++) {
TRACE_CFI(" 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:
{
TRACE_CFI(" -> CFA_RULE_SAME_VALUE\n");
BVariant value;
if (inputInterface->GetRegisterValue(i, value))
outputInterface->SetRegisterValue(i, value);
break;
}
case CFA_RULE_LOCATION_OFFSET:
{
TRACE_CFI(" -> 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:
TRACE_CFI(" -> CFA_RULE_VALUE_OFFSET\n");
outputInterface->SetRegisterValue(i,
frameAddress + rule->Offset());
break;
case CFA_RULE_REGISTER:
{
TRACE_CFI(" -> CFA_RULE_REGISTER\n");
BVariant value;
if (inputInterface->GetRegisterValue(
rule->Register(), value)) {
outputInterface->SetRegisterValue(i, value);
}
break;
}
case CFA_RULE_LOCATION_EXPRESSION:
{
TRACE_CFI(" -> CFA_RULE_LOCATION_EXPRESSION\n");
target_addr_t address;
error = EvaluateExpression(unit, subprogramEntry,
rule->Expression().block,
rule->Expression().size,
inputInterface, location, frameAddress,
frameAddress, true, address);
BVariant value;
if (error == B_OK
&& inputInterface->ReadValueFromMemory(address,
valueType, value)) {
outputInterface->SetRegisterValue(i, value);
}
break;
}
case CFA_RULE_VALUE_EXPRESSION:
{
TRACE_CFI(" -> CFA_RULE_VALUE_EXPRESSION\n");
target_addr_t value;
error = EvaluateExpression(unit, subprogramEntry,
rule->Expression().block,
rule->Expression().size,
inputInterface, location, frameAddress,
frameAddress, true, value);
if (error == B_OK)
outputInterface->SetRegisterValue(i, value);
break;
}
case CFA_RULE_UNDEFINED:
TRACE_CFI(" -> CFA_RULE_UNDEFINED\n");
default:
break;
}
}
_framePointer = frameAddress;
return B_OK;
}
}
dataReader.SeekAbsolute(lengthOffset + length);
// if .debug_frame isn't present, or if the FDE wasn't found there,
// try .eh_frame
if (result == B_ENTRY_NOT_FOUND && fEHFrameSection != NULL) {
result = _UnwindCallFrame(true, unit, subprogramEntry, location,
inputInterface, outputInterface, _framePointer);
}
return B_ENTRY_NOT_FOUND;
return result;
}
@ -1549,6 +1284,294 @@ DwarfFile::_ParseLineInfo(CompilationUnit* unit)
}
status_t
DwarfFile::_UnwindCallFrame(bool usingEHFrameSection, CompilationUnit* unit,
DIESubprogram* subprogramEntry, target_addr_t location,
const DwarfTargetInterface* inputInterface,
DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
{
ElfSection* currentFrameSection = (usingEHFrameSection)
? fEHFrameSection : fDebugFrameSection;
if (currentFrameSection == NULL)
return B_ENTRY_NOT_FOUND;
bool gcc4EHFrameSection = false;
if (usingEHFrameSection) {
gcc4EHFrameSection = !currentFrameSection->IsWritable();
// Crude heuristic for recognizing GCC 4 (Itanium ABI) style
// .eh_frame sections. The ones generated by GCC 2 are writable,
// the ones generated by GCC 4 aren't.
}
TRACE_CFI("DwarfFile::_UnwindCallFrame(%#llx)\n", location);
DataReader dataReader((uint8*)currentFrameSection->Data(),
currentFrameSection->Size(), unit->AddressSize());
while (dataReader.BytesRemaining() > 0) {
// length
bool dwarf64;
TRACE_CFI_ONLY(off_t entryOffset = dataReader.Offset();)
uint64 length = dataReader.ReadInitialLength(dwarf64);
TRACE_CFI("DwarfFile::_UnwindCallFrame(): offset: %" B_PRIdOFF
", length: %" B_PRId64 "\n", entryOffset, length);
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);
// In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does.
if (usingEHFrameSection
? cieID == 0
: (dwarf64
? cieID == 0xffffffffffffffffULL
: cieID == 0xffffffff)) {
// this is a CIE -- skip it
} else {
// this is a FDE
uint64 initialLocationOffset = dataReader.Offset();
target_addr_t initialLocation = dataReader.ReadAddress(0);
target_size_t addressRange = dataReader.ReadAddress(0);
if (dataReader.HasOverflow())
return B_BAD_DATA;
// In the GCC 4 .eh_frame initialLocation is relative to the offset
// of the address.
if (usingEHFrameSection && gcc4EHFrameSection) {
// Note: We need to cast to the exact address width, since the
// initialLocation value can be (and likely is) negative.
if (dwarf64) {
initialLocation = (uint64)currentFrameSection
->LoadAddress() + (uint64)initialLocationOffset
+ (uint64)initialLocation;
} else {
initialLocation = (uint32)currentFrameSection
->LoadAddress() + (uint32)initialLocationOffset
+ (uint32)initialLocation;
}
}
// TODO: For GCC 2 .eh_frame sections things work differently: The
// initial locations are relocated by the runtime loader and
// afterwards point to the absolute addresses. Fortunately the
// relocations that always seem to be used are R_386_RELATIVE, so
// that the value we read from the file is already absolute
// (assuming an unchanged segment load address).
TRACE_CFI("location: %" B_PRIx64 ", initial location: %" B_PRIx64
", address range: %" B_PRIx64 "\n", location, initialLocation,
addressRange);
if (location >= initialLocation
&& location < initialLocation + addressRange) {
// This is the FDE we're looking for.
off_t remaining = lengthOffset + length
- dataReader.Offset();
if (remaining < 0)
return B_BAD_DATA;
// In .eh_frame the CIE offset is a relative back offset.
if (usingEHFrameSection) {
if (cieID > (uint64)lengthOffset) {
TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max "
"possible: %" B_PRIu64 "\n", cieID, lengthOffset);
break;
}
// convert to a section relative offset
cieID = lengthOffset - cieID;
}
TRACE_CFI(" found fde: length: %llu (%lld), CIE offset: %#llx, "
"location: %#llx, range: %#llx\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;
error = outputInterface->InitRegisterRules(context);
if (error != B_OK)
return error;
// process the CIE
CIEAugmentation cieAugmentation;
error = _ParseCIE(currentFrameSection, usingEHFrameSection,
unit, context, cieID, cieAugmentation);
if (error != B_OK)
return error;
// read the FDE augmentation data (if any)
FDEAugmentation fdeAugmentation;
error = cieAugmentation.ReadFDEData(dataReader,
fdeAugmentation);
if (error != B_OK) {
TRACE_CFI(" failed to read FDE augmentation data!\n");
return error;
}
// adjust remaining byte count to take augmentation bytes
// (if any) into account.
remaining = lengthOffset + length
- dataReader.Offset();
error = context.SaveInitialRuleSet();
if (error != B_OK)
return error;
DataReader restrictedReader =
dataReader.RestrictedReader(remaining);
error = _ParseFrameInfoInstructions(unit, context,
restrictedReader);
if (error != B_OK)
return error;
TRACE_CFI(" found row!\n");
// apply the rules of the final row
// get the frameAddress first
target_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:
{
error = EvaluateExpression(unit, subprogramEntry,
cfaCfaRule->Expression().block,
cfaCfaRule->Expression().size,
inputInterface, location, 0, 0, false,
frameAddress);
if (error != B_OK)
return error;
break;
}
case CFA_CFA_RULE_UNDEFINED:
default:
return B_BAD_VALUE;
}
TRACE_CFI(" frame address: %#llx\n", frameAddress);
// apply the register rules
for (uint32 i = 0; i < registerCount; i++) {
TRACE_CFI(" 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:
{
TRACE_CFI(" -> CFA_RULE_SAME_VALUE\n");
BVariant value;
if (inputInterface->GetRegisterValue(i, value))
outputInterface->SetRegisterValue(i, value);
break;
}
case CFA_RULE_LOCATION_OFFSET:
{
TRACE_CFI(" -> 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:
TRACE_CFI(" -> CFA_RULE_VALUE_OFFSET\n");
outputInterface->SetRegisterValue(i,
frameAddress + rule->Offset());
break;
case CFA_RULE_REGISTER:
{
TRACE_CFI(" -> CFA_RULE_REGISTER\n");
BVariant value;
if (inputInterface->GetRegisterValue(
rule->Register(), value)) {
outputInterface->SetRegisterValue(i, value);
}
break;
}
case CFA_RULE_LOCATION_EXPRESSION:
{
TRACE_CFI(" -> CFA_RULE_LOCATION_EXPRESSION\n");
target_addr_t address;
error = EvaluateExpression(unit, subprogramEntry,
rule->Expression().block,
rule->Expression().size,
inputInterface, location, frameAddress,
frameAddress, true, address);
BVariant value;
if (error == B_OK
&& inputInterface->ReadValueFromMemory(address,
valueType, value)) {
outputInterface->SetRegisterValue(i, value);
}
break;
}
case CFA_RULE_VALUE_EXPRESSION:
{
TRACE_CFI(" -> CFA_RULE_VALUE_EXPRESSION\n");
target_addr_t value;
error = EvaluateExpression(unit, subprogramEntry,
rule->Expression().block,
rule->Expression().size,
inputInterface, location, frameAddress,
frameAddress, true, value);
if (error == B_OK)
outputInterface->SetRegisterValue(i, value);
break;
}
case CFA_RULE_UNDEFINED:
TRACE_CFI(" -> CFA_RULE_UNDEFINED\n");
default:
break;
}
}
_framePointer = frameAddress;
return B_OK;
}
}
dataReader.SeekAbsolute(lengthOffset + length);
}
return B_ENTRY_NOT_FOUND;
}
status_t
DwarfFile::_ParseCIE(ElfSection* debugFrameSection, bool usingEHFrameSection,
CompilationUnit* unit, CfaContext& context, off_t cieOffset,

View File

@ -39,13 +39,6 @@ public:
const char* Name() const { return fName; }
ElfFile* GetElfFile() const { return fElfFile; }
bool HasDebugFrameSection() const {
return fDebugFrameSection != NULL;
}
bool HasEHFrameSection() const {
return fEHFrameSection != NULL;
}
int32 CountCompilationUnits() const;
CompilationUnit* CompilationUnitAt(int32 index) const;
CompilationUnit* CompilationUnitForDIE(
@ -54,8 +47,7 @@ public:
TargetAddressRangeList* ResolveRangeList(CompilationUnit* unit,
uint64 offset) const;
status_t UnwindCallFrame(bool usingEHFrameSection,
CompilationUnit* unit,
status_t UnwindCallFrame(CompilationUnit* unit,
DIESubprogram* subprogramEntry,
target_addr_t location,
const DwarfTargetInterface* inputInterface,
@ -121,6 +113,14 @@ private:
status_t _ParseLineInfo(CompilationUnit* unit);
status_t _UnwindCallFrame(bool usingEHFrameSection,
CompilationUnit* unit,
DIESubprogram* subprogramEntry,
target_addr_t location,
const DwarfTargetInterface* inputInterface,
DwarfTargetInterface* outputInterface,
target_addr_t& _framePointer);
status_t _ParseCIE(ElfSection* debugFrameSection,
bool usingEHFrameSection,
CompilationUnit* unit,