Fix #8508.
- When attempting to unwind the call frame, we now search for the appropriate FDE in both .debug_frame and .eh_frame. This mirrors gdb's behavior and works around the ever-changing whims of the gcc developers as to which section the requisite FDE/CIE resides in.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Copyright 2012, Rene Gollent, [email protected].
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -554,8 +555,22 @@ 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();
|
||||||
error = fFile->UnwindCallFrame(unit, function->SubprogramEntry(),
|
// first try .debug_frame
|
||||||
instructionPointer, inputInterface, outputInterface, framePointer);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
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));
|
||||||
return B_UNSUPPORTED;
|
return B_UNSUPPORTED;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2009-2010, Ingo Weinhold, [email protected].
|
* Copyright 2009-2010, Ingo Weinhold, [email protected].
|
||||||
|
* Copyright 2012, Rene Gollent, [email protected].
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -287,12 +288,11 @@ DwarfFile::DwarfFile()
|
|||||||
fDebugRangesSection(NULL),
|
fDebugRangesSection(NULL),
|
||||||
fDebugLineSection(NULL),
|
fDebugLineSection(NULL),
|
||||||
fDebugFrameSection(NULL),
|
fDebugFrameSection(NULL),
|
||||||
|
fEHFrameSection(NULL),
|
||||||
fDebugLocationSection(NULL),
|
fDebugLocationSection(NULL),
|
||||||
fDebugPublicTypesSection(NULL),
|
fDebugPublicTypesSection(NULL),
|
||||||
fCompilationUnits(20, true),
|
fCompilationUnits(20, true),
|
||||||
fCurrentCompilationUnit(NULL),
|
fCurrentCompilationUnit(NULL),
|
||||||
fUsingEHFrameSection(false),
|
|
||||||
fGCC4EHFrameSection(false),
|
|
||||||
fFinished(false),
|
fFinished(false),
|
||||||
fFinishError(B_OK)
|
fFinishError(B_OK)
|
||||||
{
|
{
|
||||||
@@ -311,6 +311,7 @@ DwarfFile::~DwarfFile()
|
|||||||
fElfFile->PutSection(fDebugRangesSection);
|
fElfFile->PutSection(fDebugRangesSection);
|
||||||
fElfFile->PutSection(fDebugLineSection);
|
fElfFile->PutSection(fDebugLineSection);
|
||||||
fElfFile->PutSection(fDebugFrameSection);
|
fElfFile->PutSection(fDebugFrameSection);
|
||||||
|
fElfFile->PutSection(fEHFrameSection);
|
||||||
fElfFile->PutSection(fDebugLocationSection);
|
fElfFile->PutSection(fDebugLocationSection);
|
||||||
fElfFile->PutSection(fDebugPublicTypesSection);
|
fElfFile->PutSection(fDebugPublicTypesSection);
|
||||||
delete fElfFile;
|
delete fElfFile;
|
||||||
@@ -350,26 +351,7 @@ DwarfFile::Load(const char* fileName)
|
|||||||
fDebugRangesSection = fElfFile->GetSection(".debug_ranges");
|
fDebugRangesSection = fElfFile->GetSection(".debug_ranges");
|
||||||
fDebugLineSection = fElfFile->GetSection(".debug_line");
|
fDebugLineSection = fElfFile->GetSection(".debug_line");
|
||||||
fDebugFrameSection = fElfFile->GetSection(".debug_frame");
|
fDebugFrameSection = fElfFile->GetSection(".debug_frame");
|
||||||
ElfSection* ehFrameSection = fElfFile->GetSection(".eh_frame");
|
fEHFrameSection = fElfFile->GetSection(".eh_frame");
|
||||||
if (fDebugFrameSection != NULL && ehFrameSection != NULL) {
|
|
||||||
if (ehFrameSection->Size() > fDebugFrameSection->Size()) {
|
|
||||||
fElfFile->PutSection(fDebugFrameSection);
|
|
||||||
fDebugFrameSection = ehFrameSection;
|
|
||||||
fUsingEHFrameSection = true;
|
|
||||||
} else
|
|
||||||
fElfFile->PutSection(ehFrameSection);
|
|
||||||
} else if (ehFrameSection != NULL) {
|
|
||||||
fDebugFrameSection = ehFrameSection;
|
|
||||||
fUsingEHFrameSection = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fUsingEHFrameSection) {
|
|
||||||
fGCC4EHFrameSection = !fDebugFrameSection->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.
|
|
||||||
}
|
|
||||||
|
|
||||||
fDebugLocationSection = fElfFile->GetSection(".debug_loc");
|
fDebugLocationSection = fElfFile->GetSection(".debug_loc");
|
||||||
fDebugPublicTypesSection = fElfFile->GetSection(".debug_pubtypes");
|
fDebugPublicTypesSection = fElfFile->GetSection(".debug_pubtypes");
|
||||||
|
|
||||||
@@ -553,18 +535,31 @@ DwarfFile::ResolveRangeList(CompilationUnit* unit, uint64 offset) const
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
DwarfFile::UnwindCallFrame(CompilationUnit* unit,
|
DwarfFile::UnwindCallFrame(bool usingEHFrameSection, 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)
|
||||||
{
|
{
|
||||||
if (fDebugFrameSection == NULL)
|
ElfSection* currentFrameSection = (usingEHFrameSection)
|
||||||
|
? fEHFrameSection : fDebugFrameSection;
|
||||||
|
|
||||||
|
if (currentFrameSection == NULL)
|
||||||
return B_ENTRY_NOT_FOUND;
|
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);
|
TRACE_CFI("DwarfFile::UnwindCallFrame(%#llx)\n", location);
|
||||||
|
|
||||||
DataReader dataReader((uint8*)fDebugFrameSection->Data(),
|
DataReader dataReader((uint8*)currentFrameSection->Data(),
|
||||||
fDebugFrameSection->Size(), unit->AddressSize());
|
currentFrameSection->Size(), unit->AddressSize());
|
||||||
|
|
||||||
while (dataReader.BytesRemaining() > 0) {
|
while (dataReader.BytesRemaining() > 0) {
|
||||||
// length
|
// length
|
||||||
@@ -584,7 +579,7 @@ DwarfFile::UnwindCallFrame(CompilationUnit* unit,
|
|||||||
? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
|
? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
|
||||||
|
|
||||||
// In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does.
|
// In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does.
|
||||||
if (fUsingEHFrameSection
|
if (usingEHFrameSection
|
||||||
? cieID == 0
|
? cieID == 0
|
||||||
: (dwarf64
|
: (dwarf64
|
||||||
? cieID == 0xffffffffffffffffULL
|
? cieID == 0xffffffffffffffffULL
|
||||||
@@ -601,16 +596,16 @@ DwarfFile::UnwindCallFrame(CompilationUnit* unit,
|
|||||||
|
|
||||||
// In the GCC 4 .eh_frame initialLocation is relative to the offset
|
// In the GCC 4 .eh_frame initialLocation is relative to the offset
|
||||||
// of the address.
|
// of the address.
|
||||||
if (fUsingEHFrameSection && fGCC4EHFrameSection) {
|
if (usingEHFrameSection && gcc4EHFrameSection) {
|
||||||
// Note: We need to cast to the exact address width, since the
|
// Note: We need to cast to the exact address width, since the
|
||||||
// initialLocation value can be (and likely is) negative.
|
// initialLocation value can be (and likely is) negative.
|
||||||
if (dwarf64) {
|
if (dwarf64) {
|
||||||
initialLocation = (uint64)fDebugFrameSection->LoadAddress()
|
initialLocation = (uint64)currentFrameSection
|
||||||
+ (uint64)initialLocationOffset
|
->LoadAddress() + (uint64)initialLocationOffset
|
||||||
+ (uint64)initialLocation;
|
+ (uint64)initialLocation;
|
||||||
} else {
|
} else {
|
||||||
initialLocation = (uint32)fDebugFrameSection->LoadAddress()
|
initialLocation = (uint32)currentFrameSection
|
||||||
+ (uint32)initialLocationOffset
|
->LoadAddress() + (uint32)initialLocationOffset
|
||||||
+ (uint32)initialLocation;
|
+ (uint32)initialLocation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -634,7 +629,7 @@ DwarfFile::UnwindCallFrame(CompilationUnit* unit,
|
|||||||
return B_BAD_DATA;
|
return B_BAD_DATA;
|
||||||
|
|
||||||
// In .eh_frame the CIE offset is a relative back offset.
|
// In .eh_frame the CIE offset is a relative back offset.
|
||||||
if (fUsingEHFrameSection) {
|
if (usingEHFrameSection) {
|
||||||
if (cieID > (uint64)lengthOffset) {
|
if (cieID > (uint64)lengthOffset) {
|
||||||
TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max "
|
TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max "
|
||||||
"possible: %" B_PRIu64 "\n", cieID, lengthOffset);
|
"possible: %" B_PRIu64 "\n", cieID, lengthOffset);
|
||||||
@@ -660,7 +655,8 @@ DwarfFile::UnwindCallFrame(CompilationUnit* unit,
|
|||||||
|
|
||||||
// process the CIE
|
// process the CIE
|
||||||
CIEAugmentation cieAugmentation;
|
CIEAugmentation cieAugmentation;
|
||||||
error = _ParseCIE(unit, context, cieID, cieAugmentation);
|
error = _ParseCIE(currentFrameSection, usingEHFrameSection,
|
||||||
|
unit, context, cieID, cieAugmentation);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
@@ -1554,14 +1550,15 @@ DwarfFile::_ParseLineInfo(CompilationUnit* unit)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
DwarfFile::_ParseCIE(CompilationUnit* unit, CfaContext& context,
|
DwarfFile::_ParseCIE(ElfSection* debugFrameSection, bool usingEHFrameSection,
|
||||||
off_t cieOffset, CIEAugmentation& cieAugmentation)
|
CompilationUnit* unit, CfaContext& context, off_t cieOffset,
|
||||||
|
CIEAugmentation& cieAugmentation)
|
||||||
{
|
{
|
||||||
if (cieOffset < 0 || cieOffset >= fDebugFrameSection->Size())
|
if (cieOffset < 0 || cieOffset >= debugFrameSection->Size())
|
||||||
return B_BAD_DATA;
|
return B_BAD_DATA;
|
||||||
|
|
||||||
DataReader dataReader((uint8*)fDebugFrameSection->Data() + cieOffset,
|
DataReader dataReader((uint8*)debugFrameSection->Data() + cieOffset,
|
||||||
fDebugFrameSection->Size() - cieOffset, unit->AddressSize());
|
debugFrameSection->Size() - cieOffset, unit->AddressSize());
|
||||||
|
|
||||||
// length
|
// length
|
||||||
bool dwarf64;
|
bool dwarf64;
|
||||||
@@ -1573,7 +1570,7 @@ DwarfFile::_ParseCIE(CompilationUnit* unit, CfaContext& context,
|
|||||||
// CIE ID/CIE pointer
|
// CIE ID/CIE pointer
|
||||||
uint64 cieID = dwarf64
|
uint64 cieID = dwarf64
|
||||||
? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
|
? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
|
||||||
if (fUsingEHFrameSection) {
|
if (usingEHFrameSection) {
|
||||||
if (cieID != 0)
|
if (cieID != 0)
|
||||||
return B_BAD_DATA;
|
return B_BAD_DATA;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2009-2010, Ingo Weinhold, [email protected].
|
* Copyright 2009-2010, Ingo Weinhold, [email protected].
|
||||||
|
* Copyright 2012, Rene Gollent, [email protected].
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef DWARF_FILE_H
|
#ifndef DWARF_FILE_H
|
||||||
@@ -38,6 +39,13 @@ 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(
|
||||||
@@ -46,7 +54,8 @@ public:
|
|||||||
TargetAddressRangeList* ResolveRangeList(CompilationUnit* unit,
|
TargetAddressRangeList* ResolveRangeList(CompilationUnit* unit,
|
||||||
uint64 offset) const;
|
uint64 offset) const;
|
||||||
|
|
||||||
status_t UnwindCallFrame(CompilationUnit* unit,
|
status_t UnwindCallFrame(bool usingEHFrameSection,
|
||||||
|
CompilationUnit* unit,
|
||||||
DIESubprogram* subprogramEntry,
|
DIESubprogram* subprogramEntry,
|
||||||
target_addr_t location,
|
target_addr_t location,
|
||||||
const DwarfTargetInterface* inputInterface,
|
const DwarfTargetInterface* inputInterface,
|
||||||
@@ -112,7 +121,9 @@ private:
|
|||||||
|
|
||||||
status_t _ParseLineInfo(CompilationUnit* unit);
|
status_t _ParseLineInfo(CompilationUnit* unit);
|
||||||
|
|
||||||
status_t _ParseCIE(CompilationUnit* unit,
|
status_t _ParseCIE(ElfSection* debugFrameSection,
|
||||||
|
bool usingEHFrameSection,
|
||||||
|
CompilationUnit* unit,
|
||||||
CfaContext& context, off_t cieOffset,
|
CfaContext& context, off_t cieOffset,
|
||||||
CIEAugmentation& cieAugmentation);
|
CIEAugmentation& cieAugmentation);
|
||||||
status_t _ParseFrameInfoInstructions(
|
status_t _ParseFrameInfoInstructions(
|
||||||
@@ -151,14 +162,13 @@ private:
|
|||||||
ElfSection* fDebugRangesSection;
|
ElfSection* fDebugRangesSection;
|
||||||
ElfSection* fDebugLineSection;
|
ElfSection* fDebugLineSection;
|
||||||
ElfSection* fDebugFrameSection;
|
ElfSection* fDebugFrameSection;
|
||||||
|
ElfSection* fEHFrameSection;
|
||||||
ElfSection* fDebugLocationSection;
|
ElfSection* fDebugLocationSection;
|
||||||
ElfSection* fDebugPublicTypesSection;
|
ElfSection* fDebugPublicTypesSection;
|
||||||
AbbreviationTableList fAbbreviationTables;
|
AbbreviationTableList fAbbreviationTables;
|
||||||
DebugInfoEntryFactory fDebugInfoFactory;
|
DebugInfoEntryFactory fDebugInfoFactory;
|
||||||
CompilationUnitList fCompilationUnits;
|
CompilationUnitList fCompilationUnits;
|
||||||
CompilationUnit* fCurrentCompilationUnit;
|
CompilationUnit* fCurrentCompilationUnit;
|
||||||
bool fUsingEHFrameSection;
|
|
||||||
bool fGCC4EHFrameSection;
|
|
||||||
bool fFinished;
|
bool fFinished;
|
||||||
status_t fFinishError;
|
status_t fFinishError;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user