From 96a4619b92d32c9a068d32e60aba9d02f230fac7 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Fri, 21 Dec 2012 23:26:34 -0500 Subject: [PATCH] Make use of augmentation if available. - Pull out a _ParseCIEAugmentation() from _ParseCIE(). - If .eh_frame is being used, do a quick parse of the CIE up front in order to determine the augmentation (if any), and use it to retrieve addresses in the appropriate format. This fixes stack unwinding on x86-64, and possibly other cases where the address encoding didn't correspond to architectural target size in absolute address format. --- src/apps/debugger/dwarf/DwarfFile.cpp | 96 +++++++++++++++++++-------- src/apps/debugger/dwarf/DwarfFile.h | 10 +++ 2 files changed, 80 insertions(+), 26 deletions(-) diff --git a/src/apps/debugger/dwarf/DwarfFile.cpp b/src/apps/debugger/dwarf/DwarfFile.cpp index e858ceb2ff..69187c5f6f 100644 --- a/src/apps/debugger/dwarf/DwarfFile.cpp +++ b/src/apps/debugger/dwarf/DwarfFile.cpp @@ -335,17 +335,15 @@ struct DwarfFile::CIEAugmentation { return (fFlags & CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT) != 0; } - target_addr_t FDEAddressOffset(CompilationUnit* unit, - ElfFile* file) const + target_addr_t FDEAddressOffset(ElfFile* file) const { switch (FDEAddressType()) { // function relative is currently equivalent to absolute // in all the cases in which it gets generated case CFI_ADDRESS_FORMAT_ABSOLUTE: + case CFI_ADDRESS_TYPE_PC_RELATIVE: case CFI_ADDRESS_TYPE_FUNCTION_RELATIVE: return 0; - case CFI_ADDRESS_TYPE_PC_RELATIVE: - return unit->AddressRangeBase(); case CFI_ADDRESS_TYPE_TEXT_RELATIVE: return file->TextSegment()->LoadAddress(); case CFI_ADDRESS_TYPE_DATA_RELATIVE: @@ -384,9 +382,9 @@ struct DwarfFile::CIEAugmentation { } target_addr_t ReadEncodedAddress(DataReader &reader, - CompilationUnit* unit, ElfFile* file) const + ElfFile* file) const { - target_addr_t address = FDEAddressOffset(unit, file); + target_addr_t address = FDEAddressOffset(file); switch (fAddressEncoding & 0x0f) { case CFI_ADDRESS_FORMAT_ABSOLUTE: address += reader.ReadAddress(0); @@ -1512,8 +1510,44 @@ DwarfFile::_UnwindCallFrame(bool usingEHFrameSection, CompilationUnit* unit, } else { // this is a FDE uint64 initialLocationOffset = dataReader.Offset(); - target_addr_t initialLocation = dataReader.ReadAddress(0); - target_size_t addressRange = dataReader.ReadAddress(0); + // 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; + } + + + 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 + if (usingEHFrameSection) { + // TODO: this isn't so ideal since it means we parse + // the CIE twice, once here in order to get the augmentation + // data for address parsing, and again later when we perform + // the full CIE parse to get its initial Cfa ruleset. In the + // long term, we should probably + // shift to parsing the CIEs as we hit them and caching + // their information so it can simply be retrieved directly + // later. + DataReader cieReader; + status_t error = _ParseCIEAugmentation(currentFrameSection, + usingEHFrameSection, unit, addressSize, context, cieID, + cieAugmentation, cieReader); + if (error != B_OK) + return error; + } + + target_addr_t initialLocation = cieAugmentation.ReadEncodedAddress( + dataReader, fElfFile); + target_size_t addressRange = cieAugmentation.ReadEncodedAddress( + dataReader, fElfFile); if (dataReader.HasOverflow()) return B_BAD_DATA; @@ -1552,23 +1586,12 @@ DwarfFile::_UnwindCallFrame(bool usingEHFrameSection, CompilationUnit* unit, 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: %" B_PRIu64 " (%" B_PRIdOFF "), CIE offset: %#" B_PRIx64 ", location: %#" B_PRIx64 ", " "range: %#" B_PRIx64 "\n", length, remaining, cieID, initialLocation, addressRange); - CfaContext context(location, initialLocation); + context.SetLocation(location, initialLocation); uint32 registerCount = outputInterface->CountRegisters(); status_t error = context.Init(registerCount); if (error != B_OK) @@ -1579,7 +1602,6 @@ DwarfFile::_UnwindCallFrame(bool usingEHFrameSection, CompilationUnit* unit, return error; // process the CIE - CIEAugmentation cieAugmentation; error = _ParseCIE(currentFrameSection, usingEHFrameSection, unit, addressSize, context, cieID, cieAugmentation); if (error != B_OK) @@ -1750,14 +1772,15 @@ DwarfFile::_UnwindCallFrame(bool usingEHFrameSection, CompilationUnit* unit, status_t -DwarfFile::_ParseCIE(ElfSection* debugFrameSection, bool usingEHFrameSection, - CompilationUnit* unit, uint8 addressSize, CfaContext& context, - off_t cieOffset, CIEAugmentation& cieAugmentation) +DwarfFile::_ParseCIEAugmentation(ElfSection* debugFrameSection, + bool usingEHFrameSection, CompilationUnit* unit, uint8 addressSize, + CfaContext& context, off_t cieOffset, CIEAugmentation& cieAugmentation, + DataReader& dataReader, off_t* _length, off_t* _lengthOffset) { if (cieOffset < 0 || cieOffset >= debugFrameSection->Size()) return B_BAD_DATA; - DataReader dataReader((uint8*)debugFrameSection->Data() + cieOffset, + dataReader.SetTo((uint8*)debugFrameSection->Data() + cieOffset, debugFrameSection->Size() - cieOffset, unit != NULL ? unit->AddressSize() : addressSize); @@ -1767,7 +1790,11 @@ DwarfFile::_ParseCIE(ElfSection* debugFrameSection, bool usingEHFrameSection, if (length > (uint64)dataReader.BytesRemaining()) return B_BAD_DATA; - off_t lengthOffset = dataReader.Offset(); + if (_length != NULL) + *_length = length; + + if (_lengthOffset != NULL) + *_lengthOffset = dataReader.Offset(); // CIE ID/CIE pointer uint64 cieID = dwarf64 @@ -1815,6 +1842,23 @@ DwarfFile::_ParseCIE(ElfSection* debugFrameSection, bool usingEHFrameSection, return error; } + return B_OK; +} + + +status_t +DwarfFile::_ParseCIE(ElfSection* debugFrameSection, bool usingEHFrameSection, + CompilationUnit* unit, uint8 addressSize, CfaContext& context, + off_t cieOffset, CIEAugmentation& cieAugmentation) +{ + DataReader dataReader; + off_t length; + off_t lengthOffset; + status_t result = _ParseCIEAugmentation(debugFrameSection, + usingEHFrameSection, unit, addressSize, context, cieOffset, + cieAugmentation, dataReader, &length, &lengthOffset); + if (result != B_OK) + return result; if (dataReader.HasOverflow()) return B_BAD_DATA; off_t remaining = (off_t)length diff --git a/src/apps/debugger/dwarf/DwarfFile.h b/src/apps/debugger/dwarf/DwarfFile.h index 429e98dde4..35159c9a89 100644 --- a/src/apps/debugger/dwarf/DwarfFile.h +++ b/src/apps/debugger/dwarf/DwarfFile.h @@ -123,6 +123,16 @@ private: DwarfTargetInterface* outputInterface, target_addr_t& _framePointer); + status_t _ParseCIEAugmentation( + ElfSection* debugFrameSection, + bool usingEHFrameSection, + CompilationUnit* unit, + uint8 addressSize, + CfaContext& context, off_t cieOffset, + CIEAugmentation& cieAugmentation, + DataReader& reader, + off_t* length = NULL, + off_t* lengthOffset = NULL); status_t _ParseCIE(ElfSection* debugFrameSection, bool usingEHFrameSection, CompilationUnit* unit,