Debugger: Call frame unwind optimizations.

- Pass address size to DwarfManager, and subsequently DwarfFile's Load()
  method, as that information is needed in order to parse the frame
  information correctly early on.
- When initially loading debug information, also do a quick pass through
  .{debug,eh}_frame, and build a lookup table of offsets. This is then
  used later when actual unwinding is requested in order to quickly find
  the corresponding FDE/CIE. Should noticeably improve performance when
  stepping through code, especially for larger/more complex executable images.

Implements #8613.
This commit is contained in:
Rene Gollent
2014-11-13 21:18:55 -05:00
parent 8507d262d8
commit d390ebee9e
5 changed files with 442 additions and 302 deletions
@@ -10,6 +10,7 @@
#include <string.h>
#include "arch/Architecture.h"
#include "DebuggerInterface.h"
#include "DwarfFile.h"
#include "DwarfImageDebugInfo.h"
@@ -47,7 +48,7 @@ DwarfTeamDebugInfo::~DwarfTeamDebugInfo()
status_t
DwarfTeamDebugInfo::Init()
{
fManager = new(std::nothrow) DwarfManager;
fManager = new(std::nothrow) DwarfManager(fArchitecture->AddressSize());
if (fManager == NULL)
return B_NO_MEMORY;
+416 -295
View File
@@ -442,6 +442,45 @@ private:
};
// #pragma mark - FDELookupInfo
struct DwarfFile::FDELookupInfo {
public:
FDELookupInfo(target_addr_t start, target_addr_t end,
uint64 fdeOffset, uint64 cieOffset, bool ehFrame)
:
start(start),
end(end),
fdeOffset(fdeOffset),
cieOffset(cieOffset),
ehFrame(ehFrame)
{
}
static int CompareFDEInfos(const FDELookupInfo* a, const FDELookupInfo* b)
{
if (a->start < b->start)
return -1;
else if (a->start > b->start)
return 1;
return 0;
}
inline bool ContainsAddress(target_addr_t address) const
{
return address >= start && address < end;
}
target_addr_t start;
target_addr_t end;
uint64 fdeOffset;
uint64 cieOffset;
bool ehFrame;
};
// #pragma mark - DwarfFile
@@ -462,8 +501,12 @@ DwarfFile::DwarfFile()
fDebugPublicTypesSection(NULL),
fDebugTypesSection(NULL),
fCompilationUnits(20, true),
fTypeUnits(),
fDebugFrameInfos(100, true),
fEHFrameInfos(100, true),
fTypesSectionRequired(false),
fFinished(false),
fItaniumEHFrameFormat(false),
fFinishError(B_OK)
{
}
@@ -528,7 +571,7 @@ DwarfFile::StartLoading(const char* fileName, BString& _requiredExternalFile)
status_t
DwarfFile::Load(const BString& externalInfoFilePath)
DwarfFile::Load(uint8 addressSize, const BString& externalInfoFilePath)
{
status_t error = B_OK;
if (fDebugInfoSection == NULL) {
@@ -547,11 +590,27 @@ DwarfFile::Load(const BString& externalInfoFilePath)
fDebugRangesSection = debugInfoFile->GetSection(".debug_ranges");
fDebugLineSection = debugInfoFile->GetSection(".debug_line");
fDebugFrameSection = debugInfoFile->GetSection(".debug_frame");
if (fDebugFrameSection != NULL) {
error = _ParseFrameSection(fDebugFrameSection, addressSize, false,
fDebugFrameInfos);
if (error != B_OK)
return error;
}
// .eh_frame doesn't appear to get copied into separate debug
// info files properly, therefore always use it off the main
// executable image
if (fEHFrameSection == NULL)
fEHFrameSection = fElfFile->GetSection(".eh_frame");
if (fEHFrameSection != NULL) {
error = _ParseFrameSection(fEHFrameSection, addressSize, true,
fEHFrameInfos);
if (error != B_OK)
return error;
}
fDebugLocationSection = debugInfoFile->GetSection(".debug_loc");
fDebugPublicTypesSection = debugInfoFile->GetSection(".debug_pubtypes");
@@ -699,22 +758,12 @@ DwarfFile::UnwindCallFrame(CompilationUnit* unit, uint8 addressSize,
const DwarfTargetInterface* inputInterface,
DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
{
status_t result = B_ENTRY_NOT_FOUND;
FDELookupInfo* info = _GetContainingFDEInfo(location);
if (info == NULL)
return B_ENTRY_NOT_FOUND;
// first try to find the FDE in .debug_frame
if (fDebugFrameSection != NULL) {
result = _UnwindCallFrame(false, unit, addressSize, subprogramEntry,
location, inputInterface, outputInterface, _framePointer);
}
// 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, addressSize, subprogramEntry,
location, inputInterface, outputInterface, _framePointer);
}
return result;
return _UnwindCallFrame(unit, addressSize, subprogramEntry, location, info,
inputInterface, outputInterface, _framePointer);
}
@@ -1080,6 +1129,116 @@ DwarfFile::_ParseTypesSection()
}
status_t
DwarfFile::_ParseFrameSection(ElfSection* section, uint8 addressSize,
bool ehFrame, FDEInfoList& infos)
{
if (ehFrame) {
fItaniumEHFrameFormat = section->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.
}
DataReader dataReader((uint8*)section->Data(),
section->Size(), addressSize);
while (dataReader.BytesRemaining() > 0) {
// length
bool dwarf64;
off_t entryOffset = dataReader.Offset();
uint64 length = dataReader.ReadInitialLength(dwarf64);
TRACE_CFI("DwarfFile::_ParseFrameSection(): 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 (ehFrame
? cieID == 0
: (dwarf64
? cieID == 0xffffffffffffffffULL
: cieID == 0xffffffff)) {
// this is a CIE -- skip it
} else {
// this is a FDE
uint64 initialLocationOffset = dataReader.Offset();
// In .eh_frame the CIE offset is a relative back offset.
if (ehFrame) {
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;
}
CfaContext context;
CIEAugmentation cieAugmentation;
// when using .eh_frame format, we need to parse the CIE's
// augmentation up front in order to know how the FDE's addresses
// will be represented
DataReader cieReader;
off_t cieRemaining;
status_t error = _ParseCIEHeader(section, ehFrame, NULL,
addressSize, context, cieID, cieAugmentation, cieReader,
cieRemaining);
if (error != B_OK)
return error;
if (cieReader.HasOverflow())
return B_BAD_DATA;
if (cieRemaining < 0)
return B_BAD_DATA;
target_addr_t initialLocation = cieAugmentation.ReadEncodedAddress(
dataReader, fElfFile, section);
target_addr_t addressRange = cieAugmentation.ReadEncodedAddress(
dataReader, fElfFile, section, true);
if (dataReader.HasOverflow())
return B_BAD_DATA;
if ((cieAugmentation.FDEAddressType()
& CFI_ADDRESS_TYPE_PC_RELATIVE) != 0) {
initialLocation += initialLocationOffset;
}
// for unknown reasons, the debug frame sections generated by gcc
// sometimes contain duplicates at different offsets within the
// section. In such a case, simply skip the duplicates.
FDELookupInfo* temp = _GetContainingFDEInfo(initialLocation,
infos);
if (temp == NULL) {
FDELookupInfo* info = new(std::nothrow)FDELookupInfo(
initialLocation, initialLocation + addressRange - 1,
entryOffset, cieID, ehFrame);
if (info == NULL)
return B_NO_MEMORY;
ObjectDeleter<FDELookupInfo> infoDeleter(info);
if (!infos.BinaryInsert(info, FDELookupInfo::CompareFDEInfos))
return B_NO_MEMORY;
infoDeleter.Detach();
}
}
dataReader.SeekAbsolute(lengthOffset + length);
}
return B_OK;
}
status_t
DwarfFile::_ParseCompilationUnit(CompilationUnit* unit)
{
@@ -1705,305 +1864,230 @@ DwarfFile::_ParseLineInfo(CompilationUnit* unit)
status_t
DwarfFile::_UnwindCallFrame(bool usingEHFrameSection, CompilationUnit* unit,
uint8 addressSize, DIESubprogram* subprogramEntry, target_addr_t location,
const DwarfTargetInterface* inputInterface,
DwarfFile::_UnwindCallFrame(CompilationUnit* unit, uint8 addressSize,
DIESubprogram* subprogramEntry, target_addr_t location,
const FDELookupInfo* info, const DwarfTargetInterface* inputInterface,
DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
{
ElfSection* currentFrameSection = (usingEHFrameSection)
ElfSection* currentFrameSection = (info->ehFrame)
? 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(%#" B_PRIx64 ")\n", location);
DataReader dataReader((uint8*)currentFrameSection->Data(),
currentFrameSection->Size(), unit != NULL
? unit->AddressSize() : addressSize);
dataReader.SeekAbsolute(info->fdeOffset);
while (dataReader.BytesRemaining() > 0) {
// length
bool dwarf64;
TRACE_CFI_ONLY(off_t entryOffset = dataReader.Offset();)
uint64 length = dataReader.ReadInitialLength(dwarf64);
bool dwarf64;
uint64 length = dataReader.ReadInitialLength(dwarf64);
uint64 lengthOffset = dataReader.Offset();
TRACE_CFI("DwarfFile::_UnwindCallFrame(): offset: %" B_PRIdOFF
", length: %" B_PRId64 "\n", entryOffset, length);
CfaContext context;
CIEAugmentation cieAugmentation;
// when using .eh_frame format, we need to parse the CIE's
// augmentation up front in order to know how the FDE's addresses
// will be represented
DataReader cieReader;
off_t cieRemaining;
status_t error = _ParseCIEHeader(currentFrameSection,
info->ehFrame, unit, addressSize, context, info->cieOffset,
cieAugmentation, cieReader, cieRemaining);
if (error != B_OK)
return error;
if (cieReader.HasOverflow())
return B_BAD_DATA;
if (cieRemaining < 0)
return B_BAD_DATA;
if (length > (uint64)dataReader.BytesRemaining())
return B_BAD_DATA;
off_t lengthOffset = dataReader.Offset();
uint64 remaining = lengthOffset + length - info->fdeOffset;
if (remaining < 0)
return B_BAD_DATA;
// CIE ID/CIE pointer
uint64 cieID = dwarf64
? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
// skip CIE ID, initial offset and range, since we already know those
// from FDELookupInfo.
dwarf64 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
cieAugmentation.ReadEncodedAddress(dataReader, fElfFile,
currentFrameSection);
cieAugmentation.ReadEncodedAddress(dataReader, fElfFile,
currentFrameSection, true);
// 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();
// 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: %" B_PRIu64 " (%" B_PRIdOFF
"), CIE offset: %#" B_PRIx64 ", location: %#" B_PRIx64 ", "
"range: %#" B_PRIx64 "\n", length, dataReader.BytesRemaining(),
info->cieOffset, info->start, info->end - info->start);
context.SetLocation(location, info->start);
uint32 registerCount = outputInterface->CountRegisters();
error = context.Init(registerCount);
if (error != B_OK)
return error;
CfaContext context;
CIEAugmentation cieAugmentation;
// when using .eh_frame format, we need to parse the CIE's
// augmentation up front in order to know how the FDE's addresses
// will be represented
DataReader cieReader;
off_t cieRemaining;
status_t error = _ParseCIEHeader(currentFrameSection,
usingEHFrameSection, unit, addressSize, context, cieID,
cieAugmentation, cieReader, cieRemaining);
if (error != B_OK)
return error;
if (cieReader.HasOverflow())
return B_BAD_DATA;
if (cieRemaining < 0)
return B_BAD_DATA;
error = outputInterface->InitRegisterRules(context);
if (error != B_OK)
return error;
target_addr_t initialLocation = cieAugmentation.ReadEncodedAddress(
dataReader, fElfFile, currentFrameSection);
target_addr_t addressRange = cieAugmentation.ReadEncodedAddress(
dataReader, fElfFile, currentFrameSection, true);
// process the CIE's frame info instructions
cieReader = cieReader.RestrictedReader(cieRemaining);
error = _ParseFrameInfoInstructions(unit, context,
cieReader, cieAugmentation);
if (error != B_OK)
return error;
if (dataReader.HasOverflow())
return B_BAD_DATA;
if ((cieAugmentation.FDEAddressType()
& CFI_ADDRESS_TYPE_PC_RELATIVE) != 0) {
initialLocation += initialLocationOffset;
}
// 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;
TRACE_CFI(" found fde: length: %" B_PRIu64 " (%" B_PRIdOFF
"), CIE offset: %#" B_PRIx64 ", location: %#" B_PRIx64 ", "
"range: %#" B_PRIx64 "\n", length, remaining, cieID,
initialLocation, addressRange);
context.SetLocation(location, initialLocation);
uint32 registerCount = outputInterface->CountRegisters();
error = context.Init(registerCount);
if (error != B_OK)
return error;
error = outputInterface->InitRegisterRules(context);
if (error != B_OK)
return error;
// process the CIE's frame info instructions
cieReader = cieReader.RestrictedReader(cieRemaining);
error = _ParseFrameInfoInstructions(unit, context,
cieReader, 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, cieAugmentation);
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, addressSize,
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: %#" B_PRIx64 "\n", frameAddress);
// apply the register rules
for (uint32 i = 0; i < registerCount; i++) {
TRACE_CFI(" reg %" B_PRIu32 "\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: %"
B_PRId64 "\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, addressSize,
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, addressSize,
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);
// 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;
}
return B_ENTRY_NOT_FOUND;
error = context.SaveInitialRuleSet();
if (error != B_OK)
return error;
DataReader restrictedReader =
dataReader.RestrictedReader(remaining);
error = _ParseFrameInfoInstructions(unit, context,
restrictedReader, cieAugmentation);
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, addressSize,
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: %#" B_PRIx64 "\n", frameAddress);
// apply the register rules
for (uint32 i = 0; i < registerCount; i++) {
TRACE_CFI(" reg %" B_PRIu32 "\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: %"
B_PRId64 "\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, addressSize,
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, addressSize,
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;
}
@@ -2842,3 +2926,40 @@ DwarfFile::_GetContainingCompilationUnit(off_t refAddr) const
CompilationUnit* unit = fCompilationUnits.ItemAt(lower);
return unit->ContainsAbsoluteOffset(refAddr) ? unit : NULL;
}
DwarfFile::FDELookupInfo*
DwarfFile::_GetContainingFDEInfo(target_addr_t offset) const
{
FDELookupInfo* info = NULL;
if (fDebugFrameSection != NULL) {
info = _GetContainingFDEInfo(offset, fDebugFrameInfos);
if (info != NULL)
return info;
}
return _GetContainingFDEInfo(offset, fEHFrameInfos);
}
DwarfFile::FDELookupInfo*
DwarfFile::_GetContainingFDEInfo(target_addr_t offset,
const FDEInfoList& infoList) const
{
// binary search
int lower = 0;
int upper = infoList.CountItems() - 1;
if (upper < 0)
return NULL;
while (lower < upper) {
int mid = (lower + upper + 1) / 2;
if (offset < infoList.ItemAt(mid)->start)
upper = mid - 1;
else
lower = mid;
}
FDELookupInfo* info = infoList.ItemAt(lower);
return info->ContainsAddress(offset) ? info : NULL;
}
+19 -3
View File
@@ -37,7 +37,8 @@ public:
status_t StartLoading(const char* fileName,
BString& _requiredExternalFile);
status_t Load(const BString& externalFilePath);
status_t Load(uint8 addressSize,
const BString& externalFilePath);
status_t FinishLoading();
const char* Name() const { return fName; }
@@ -108,14 +109,19 @@ private:
struct ExpressionEvaluationContext;
struct FDEAugmentation;
struct CIEAugmentation;
struct FDELookupInfo;
typedef DoublyLinkedList<AbbreviationTable> AbbreviationTableList;
typedef BObjectList<CompilationUnit> CompilationUnitList;
typedef BOpenHashTable<TypeUnitTableHashDefinition> TypeUnitTable;
typedef BObjectList<FDELookupInfo> FDEInfoList;
private:
status_t _ParseDebugInfoSection();
status_t _ParseTypesSection();
status_t _ParseFrameSection(ElfSection* section,
uint8 addressSize, bool ehFrame,
FDEInfoList& infos);
status_t _ParseCompilationUnit(CompilationUnit* unit);
status_t _ParseTypeUnit(TypeUnit* unit);
status_t _ParseDebugInfoEntry(DataReader& dataReader,
@@ -131,11 +137,11 @@ private:
status_t _ParseLineInfo(CompilationUnit* unit);
status_t _UnwindCallFrame(bool usingEHFrameSection,
CompilationUnit* unit,
status_t _UnwindCallFrame(CompilationUnit* unit,
uint8 addressSize,
DIESubprogram* subprogramEntry,
target_addr_t location,
const FDELookupInfo* info,
const DwarfTargetInterface* inputInterface,
DwarfTargetInterface* outputInterface,
target_addr_t& _framePointer);
@@ -185,6 +191,13 @@ private:
CompilationUnit* _GetContainingCompilationUnit(
off_t refAddr) const;
FDELookupInfo* _GetContainingFDEInfo(
target_addr_t offset) const;
FDELookupInfo* _GetContainingFDEInfo(
target_addr_t offset,
const FDEInfoList& infoList) const;
private:
friend class DwarfFile::ExpressionEvaluationContext;
@@ -207,8 +220,11 @@ private:
DebugInfoEntryFactory fDebugInfoFactory;
CompilationUnitList fCompilationUnits;
TypeUnitTable fTypeUnits;
FDEInfoList fDebugFrameInfos;
FDEInfoList fEHFrameInfos;
bool fTypesSectionRequired;
bool fFinished;
bool fItaniumEHFrameFormat;
status_t fFinishError;
};
+3 -2
View File
@@ -15,8 +15,9 @@
#include "DwarfFileLoadingState.h"
DwarfManager::DwarfManager()
DwarfManager::DwarfManager(uint8 addressSize)
:
fAddressSize(addressSize),
fLock("dwarf manager")
{
}
@@ -65,7 +66,7 @@ DwarfManager::LoadFile(const char* fileName, DwarfFileLoadingState& _state)
}
}
error = file->Load(_state.locatedExternalInfoPath);
error = file->Load(fAddressSize, _state.locatedExternalInfoPath);
if (error != B_OK) {
_state.state = DWARF_FILE_LOADING_STATE_FAILED;
return error;
+2 -1
View File
@@ -17,7 +17,7 @@ struct DwarfFileLoadingState;
class DwarfManager {
public:
DwarfManager();
DwarfManager(uint8 addressSize);
~DwarfManager();
status_t Init();
@@ -36,6 +36,7 @@ private:
typedef DoublyLinkedList<DwarfFile> FileList;
private:
uint8 fAddressSize;
BLocker fLock;
FileList fFiles;
};