Refactor previous commit.
- Keep knowledge of the existence and need to search the different frame sections contained within DwarfFile.
This commit is contained in:
@@ -555,21 +555,8 @@ DwarfImageDebugInfo::CreateFrame(Image* image,
|
|||||||
= cpuState->InstructionPointer() - fRelocationDelta;
|
= cpuState->InstructionPointer() - fRelocationDelta;
|
||||||
target_addr_t framePointer;
|
target_addr_t framePointer;
|
||||||
CompilationUnit* unit = function->GetCompilationUnit();
|
CompilationUnit* unit = function->GetCompilationUnit();
|
||||||
// first try .debug_frame
|
error = fFile->UnwindCallFrame(unit, function->SubprogramEntry(),
|
||||||
if (fFile->HasDebugFrameSection()) {
|
instructionPointer, inputInterface, outputInterface, framePointer);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
TRACE_CFI("Failed to unwind call frame: %s\n", strerror(error));
|
TRACE_CFI("Failed to unwind call frame: %s\n", strerror(error));
|
||||||
|
|||||||
@@ -535,292 +535,27 @@ DwarfFile::ResolveRangeList(CompilationUnit* unit, uint64 offset) const
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
DwarfFile::UnwindCallFrame(bool usingEHFrameSection, CompilationUnit* unit,
|
DwarfFile::UnwindCallFrame(CompilationUnit* unit,
|
||||||
DIESubprogram* subprogramEntry, target_addr_t location,
|
DIESubprogram* subprogramEntry, target_addr_t location,
|
||||||
const DwarfTargetInterface* inputInterface,
|
const DwarfTargetInterface* inputInterface,
|
||||||
DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
|
DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
|
||||||
{
|
{
|
||||||
ElfSection* currentFrameSection = (usingEHFrameSection)
|
status_t result = B_ENTRY_NOT_FOUND;
|
||||||
? fEHFrameSection : fDebugFrameSection;
|
|
||||||
|
|
||||||
if (currentFrameSection == NULL)
|
// first try to find the FDE in .debug_frame
|
||||||
return B_ENTRY_NOT_FOUND;
|
if (fDebugFrameSection != NULL) {
|
||||||
|
result = _UnwindCallFrame(false, unit, subprogramEntry, location,
|
||||||
bool gcc4EHFrameSection = false;
|
inputInterface, outputInterface, _framePointer);
|
||||||
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.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if .debug_frame isn't present, or if the FDE wasn't found there,
|
||||||
|
// try .eh_frame
|
||||||
TRACE_CFI("DwarfFile::UnwindCallFrame(%#llx)\n", location);
|
if (result == B_ENTRY_NOT_FOUND && fEHFrameSection != NULL) {
|
||||||
|
result = _UnwindCallFrame(true, unit, subprogramEntry, location,
|
||||||
DataReader dataReader((uint8*)currentFrameSection->Data(),
|
inputInterface, outputInterface, _framePointer);
|
||||||
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;
|
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
|
status_t
|
||||||
DwarfFile::_ParseCIE(ElfSection* debugFrameSection, bool usingEHFrameSection,
|
DwarfFile::_ParseCIE(ElfSection* debugFrameSection, bool usingEHFrameSection,
|
||||||
CompilationUnit* unit, CfaContext& context, off_t cieOffset,
|
CompilationUnit* unit, CfaContext& context, off_t cieOffset,
|
||||||
|
|||||||
@@ -39,13 +39,6 @@ public:
|
|||||||
const char* Name() const { return fName; }
|
const char* Name() const { return fName; }
|
||||||
ElfFile* GetElfFile() const { return fElfFile; }
|
ElfFile* GetElfFile() const { return fElfFile; }
|
||||||
|
|
||||||
bool HasDebugFrameSection() const {
|
|
||||||
return fDebugFrameSection != NULL;
|
|
||||||
}
|
|
||||||
bool HasEHFrameSection() const {
|
|
||||||
return fEHFrameSection != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 CountCompilationUnits() const;
|
int32 CountCompilationUnits() const;
|
||||||
CompilationUnit* CompilationUnitAt(int32 index) const;
|
CompilationUnit* CompilationUnitAt(int32 index) const;
|
||||||
CompilationUnit* CompilationUnitForDIE(
|
CompilationUnit* CompilationUnitForDIE(
|
||||||
@@ -54,8 +47,7 @@ public:
|
|||||||
TargetAddressRangeList* ResolveRangeList(CompilationUnit* unit,
|
TargetAddressRangeList* ResolveRangeList(CompilationUnit* unit,
|
||||||
uint64 offset) const;
|
uint64 offset) const;
|
||||||
|
|
||||||
status_t UnwindCallFrame(bool usingEHFrameSection,
|
status_t UnwindCallFrame(CompilationUnit* unit,
|
||||||
CompilationUnit* unit,
|
|
||||||
DIESubprogram* subprogramEntry,
|
DIESubprogram* subprogramEntry,
|
||||||
target_addr_t location,
|
target_addr_t location,
|
||||||
const DwarfTargetInterface* inputInterface,
|
const DwarfTargetInterface* inputInterface,
|
||||||
@@ -121,6 +113,14 @@ private:
|
|||||||
|
|
||||||
status_t _ParseLineInfo(CompilationUnit* unit);
|
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,
|
status_t _ParseCIE(ElfSection* debugFrameSection,
|
||||||
bool usingEHFrameSection,
|
bool usingEHFrameSection,
|
||||||
CompilationUnit* unit,
|
CompilationUnit* unit,
|
||||||
|
|||||||
Reference in New Issue
Block a user