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.
This commit is contained in:
Rene Gollent
2012-12-21 23:32:51 -05:00
parent 54531e9f97
commit 96a4619b92
2 changed files with 80 additions and 26 deletions
+70 -26
View File
@@ -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
+10
View File
@@ -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,