From dfa21dfeabe22cd7df5de50e21bf1ad3678454b8 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Wed, 11 Jul 2012 19:10:32 -0400 Subject: [PATCH] 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. --- .../debug_info/DwarfImageDebugInfo.cpp | 19 ++++- src/apps/debugger/dwarf/DwarfFile.cpp | 77 +++++++++---------- src/apps/debugger/dwarf/DwarfFile.h | 18 ++++- 3 files changed, 68 insertions(+), 46 deletions(-) diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp index 7731e5ae88..f24f9b1299 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp @@ -1,5 +1,6 @@ /* * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2012, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ @@ -554,8 +555,22 @@ DwarfImageDebugInfo::CreateFrame(Image* image, = cpuState->InstructionPointer() - fRelocationDelta; target_addr_t framePointer; CompilationUnit* unit = function->GetCompilationUnit(); - error = fFile->UnwindCallFrame(unit, function->SubprogramEntry(), - instructionPointer, inputInterface, outputInterface, framePointer); + // 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); + } + if (error != B_OK) { TRACE_CFI("Failed to unwind call frame: %s\n", strerror(error)); return B_UNSUPPORTED; diff --git a/src/apps/debugger/dwarf/DwarfFile.cpp b/src/apps/debugger/dwarf/DwarfFile.cpp index 49b5a9c6da..aee71b4ce9 100644 --- a/src/apps/debugger/dwarf/DwarfFile.cpp +++ b/src/apps/debugger/dwarf/DwarfFile.cpp @@ -1,5 +1,6 @@ /* * Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2012, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ @@ -287,12 +288,11 @@ DwarfFile::DwarfFile() fDebugRangesSection(NULL), fDebugLineSection(NULL), fDebugFrameSection(NULL), + fEHFrameSection(NULL), fDebugLocationSection(NULL), fDebugPublicTypesSection(NULL), fCompilationUnits(20, true), fCurrentCompilationUnit(NULL), - fUsingEHFrameSection(false), - fGCC4EHFrameSection(false), fFinished(false), fFinishError(B_OK) { @@ -311,6 +311,7 @@ DwarfFile::~DwarfFile() fElfFile->PutSection(fDebugRangesSection); fElfFile->PutSection(fDebugLineSection); fElfFile->PutSection(fDebugFrameSection); + fElfFile->PutSection(fEHFrameSection); fElfFile->PutSection(fDebugLocationSection); fElfFile->PutSection(fDebugPublicTypesSection); delete fElfFile; @@ -350,26 +351,7 @@ DwarfFile::Load(const char* fileName) fDebugRangesSection = fElfFile->GetSection(".debug_ranges"); fDebugLineSection = fElfFile->GetSection(".debug_line"); fDebugFrameSection = fElfFile->GetSection(".debug_frame"); - ElfSection* ehFrameSection = 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. - } - + fEHFrameSection = fElfFile->GetSection(".eh_frame"); fDebugLocationSection = fElfFile->GetSection(".debug_loc"); fDebugPublicTypesSection = fElfFile->GetSection(".debug_pubtypes"); @@ -553,18 +535,31 @@ DwarfFile::ResolveRangeList(CompilationUnit* unit, uint64 offset) const status_t -DwarfFile::UnwindCallFrame(CompilationUnit* unit, +DwarfFile::UnwindCallFrame(bool usingEHFrameSection, CompilationUnit* unit, DIESubprogram* subprogramEntry, target_addr_t location, const DwarfTargetInterface* inputInterface, DwarfTargetInterface* outputInterface, target_addr_t& _framePointer) { - if (fDebugFrameSection == NULL) + 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*)fDebugFrameSection->Data(), - fDebugFrameSection->Size(), unit->AddressSize()); + DataReader dataReader((uint8*)currentFrameSection->Data(), + currentFrameSection->Size(), unit->AddressSize()); while (dataReader.BytesRemaining() > 0) { // length @@ -584,7 +579,7 @@ DwarfFile::UnwindCallFrame(CompilationUnit* unit, ? dataReader.Read(0) : dataReader.Read(0); // In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does. - if (fUsingEHFrameSection + if (usingEHFrameSection ? cieID == 0 : (dwarf64 ? cieID == 0xffffffffffffffffULL @@ -601,16 +596,16 @@ DwarfFile::UnwindCallFrame(CompilationUnit* unit, // In the GCC 4 .eh_frame initialLocation is relative to the offset // of the address. - if (fUsingEHFrameSection && fGCC4EHFrameSection) { + 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)fDebugFrameSection->LoadAddress() - + (uint64)initialLocationOffset + initialLocation = (uint64)currentFrameSection + ->LoadAddress() + (uint64)initialLocationOffset + (uint64)initialLocation; } else { - initialLocation = (uint32)fDebugFrameSection->LoadAddress() - + (uint32)initialLocationOffset + initialLocation = (uint32)currentFrameSection + ->LoadAddress() + (uint32)initialLocationOffset + (uint32)initialLocation; } } @@ -634,7 +629,7 @@ DwarfFile::UnwindCallFrame(CompilationUnit* unit, return B_BAD_DATA; // In .eh_frame the CIE offset is a relative back offset. - if (fUsingEHFrameSection) { + if (usingEHFrameSection) { if (cieID > (uint64)lengthOffset) { TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max " "possible: %" B_PRIu64 "\n", cieID, lengthOffset); @@ -660,7 +655,8 @@ DwarfFile::UnwindCallFrame(CompilationUnit* unit, // process the CIE CIEAugmentation cieAugmentation; - error = _ParseCIE(unit, context, cieID, cieAugmentation); + error = _ParseCIE(currentFrameSection, usingEHFrameSection, + unit, context, cieID, cieAugmentation); if (error != B_OK) return error; @@ -1554,14 +1550,15 @@ DwarfFile::_ParseLineInfo(CompilationUnit* unit) status_t -DwarfFile::_ParseCIE(CompilationUnit* unit, CfaContext& context, - off_t cieOffset, CIEAugmentation& cieAugmentation) +DwarfFile::_ParseCIE(ElfSection* debugFrameSection, bool usingEHFrameSection, + 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; - DataReader dataReader((uint8*)fDebugFrameSection->Data() + cieOffset, - fDebugFrameSection->Size() - cieOffset, unit->AddressSize()); + DataReader dataReader((uint8*)debugFrameSection->Data() + cieOffset, + debugFrameSection->Size() - cieOffset, unit->AddressSize()); // length bool dwarf64; @@ -1573,7 +1570,7 @@ DwarfFile::_ParseCIE(CompilationUnit* unit, CfaContext& context, // CIE ID/CIE pointer uint64 cieID = dwarf64 ? dataReader.Read(0) : dataReader.Read(0); - if (fUsingEHFrameSection) { + if (usingEHFrameSection) { if (cieID != 0) return B_BAD_DATA; } else { diff --git a/src/apps/debugger/dwarf/DwarfFile.h b/src/apps/debugger/dwarf/DwarfFile.h index f4d5281862..a7afede41f 100644 --- a/src/apps/debugger/dwarf/DwarfFile.h +++ b/src/apps/debugger/dwarf/DwarfFile.h @@ -1,5 +1,6 @@ /* * Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2012, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ #ifndef DWARF_FILE_H @@ -38,6 +39,13 @@ 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( @@ -46,7 +54,8 @@ public: TargetAddressRangeList* ResolveRangeList(CompilationUnit* unit, uint64 offset) const; - status_t UnwindCallFrame(CompilationUnit* unit, + status_t UnwindCallFrame(bool usingEHFrameSection, + CompilationUnit* unit, DIESubprogram* subprogramEntry, target_addr_t location, const DwarfTargetInterface* inputInterface, @@ -112,7 +121,9 @@ private: status_t _ParseLineInfo(CompilationUnit* unit); - status_t _ParseCIE(CompilationUnit* unit, + status_t _ParseCIE(ElfSection* debugFrameSection, + bool usingEHFrameSection, + CompilationUnit* unit, CfaContext& context, off_t cieOffset, CIEAugmentation& cieAugmentation); status_t _ParseFrameInfoInstructions( @@ -151,14 +162,13 @@ private: ElfSection* fDebugRangesSection; ElfSection* fDebugLineSection; ElfSection* fDebugFrameSection; + ElfSection* fEHFrameSection; ElfSection* fDebugLocationSection; ElfSection* fDebugPublicTypesSection; AbbreviationTableList fAbbreviationTables; DebugInfoEntryFactory fDebugInfoFactory; CompilationUnitList fCompilationUnits; CompilationUnit* fCurrentCompilationUnit; - bool fUsingEHFrameSection; - bool fGCC4EHFrameSection; bool fFinished; status_t fFinishError; };