DwarfFile: Implement handling of .debug_types section.

- Refactor ExpressionEvaluationContext::GetCallTarget() and
DwarfFile::_ResolveReference() to use an enum value for the type of
reference being passed in, as we now need to support signature
references in addition to local/global. Adjust callers.
- Factor out an _ParseDebugInfoSection() and add a corresponding
_ParseTypesSection() for the top level loops that handle .debug_info and
.debug_types respectively.
- Refactor _ParseDebugInfoEntry(), _ParseEntryAttributes() and
_ResolveReference to take a pointer to the relevant BaseUnit in order
to allow sharing between parsing of the types and info sections.
- Implement support for DW_FORM_ref_sig8. In order to handle this, we
use a hash table that maps from the corresponding 64-bit DW_AT_signature
values to their respective type units.
- Adjust debug output to more closely match offsets and values used by
objdump for ease of troubleshooting parsing issues.

Combined, these changes allow us to load DWARF 4 binaries sufficiently
to get source information and unwind call frame, though support is still
incomplete. In particular, global references aren't yet implemented,
and neither are location expression attributes, which are now used
quite heavily, and consequently we can't yet resolve variable values
and a few other things properly.
This commit is contained in:
Rene Gollent
2013-07-16 23:29:22 -04:00
parent 4bf8368675
commit 71fec49e67
5 changed files with 362 additions and 127 deletions
+7
View File
@@ -507,4 +507,11 @@ enum {
}; };
enum dwarf_reference_type {
dwarf_reference_type_local = 0,
dwarf_reference_type_global,
dwarf_reference_type_signature
};
#endif // DWARF_H #endif // DWARF_H
@@ -600,18 +600,21 @@ DwarfExpressionEvaluator::_Evaluate(ValuePieceLocation* _piece)
case DW_OP_call2: case DW_OP_call2:
TRACE_EXPR(" DW_OP_call2\n"); TRACE_EXPR(" DW_OP_call2\n");
_Call(fDataReader.Read<uint16>(0), true); _Call(fDataReader.Read<uint16>(0), dwarf_reference_type_local);
break; break;
case DW_OP_call4: case DW_OP_call4:
TRACE_EXPR(" DW_OP_call4\n"); TRACE_EXPR(" DW_OP_call4\n");
_Call(fDataReader.Read<uint32>(0), true); _Call(fDataReader.Read<uint32>(0), dwarf_reference_type_local);
break; break;
case DW_OP_call_ref: case DW_OP_call_ref:
TRACE_EXPR(" DW_OP_call_ref\n"); TRACE_EXPR(" DW_OP_call_ref\n");
if (fContext->AddressSize() == 4) if (fContext->AddressSize() == 4) {
_Call(fDataReader.Read<uint32>(0), false); _Call(fDataReader.Read<uint32>(0),
else dwarf_reference_type_global);
_Call(fDataReader.Read<uint64>(0), false); } else {
_Call(fDataReader.Read<uint64>(0),
dwarf_reference_type_global);
}
break; break;
case DW_OP_piece: case DW_OP_piece:
@@ -746,7 +749,7 @@ DwarfExpressionEvaluator::_PushRegister(uint32 reg, target_addr_t offset)
void void
DwarfExpressionEvaluator::_Call(uint64 offset, bool local) DwarfExpressionEvaluator::_Call(uint64 offset, uint8 refType)
{ {
if (fDataReader.HasOverflow()) if (fDataReader.HasOverflow())
throw EvaluationException("unexpected end of expression"); throw EvaluationException("unexpected end of expression");
@@ -754,7 +757,7 @@ DwarfExpressionEvaluator::_Call(uint64 offset, bool local)
// get the expression to "call" // get the expression to "call"
const void* block; const void* block;
off_t size; off_t size;
if (fContext->GetCallTarget(offset, local, block, size) != B_OK) if (fContext->GetCallTarget(offset, refType, block, size) != B_OK)
throw EvaluationException("failed to get call target"); throw EvaluationException("failed to get call target");
// no expression is OK, then this is just a no-op // no expression is OK, then this is just a no-op
@@ -37,8 +37,9 @@ public:
virtual bool GetTLSAddress(target_addr_t localAddress, virtual bool GetTLSAddress(target_addr_t localAddress,
target_addr_t& _address) = 0; target_addr_t& _address) = 0;
virtual status_t GetCallTarget(uint64 offset, bool local, virtual status_t GetCallTarget(uint64 offset,
const void*& _block, off_t& _size) = 0; uint8 refType, const void*& _block,
off_t& _size) = 0;
// returns error, when an error resolving // returns error, when an error resolving
// the entry occurs; returns B_OK and a NULL // the entry occurs; returns B_OK and a NULL
// block, when the entry doesn't have a // block, when the entry doesn't have a
@@ -81,7 +82,7 @@ private:
void _DereferenceAddressSpaceAddress( void _DereferenceAddressSpaceAddress(
uint8 addressSize); uint8 addressSize);
void _PushRegister(uint32 reg, target_addr_t offset); void _PushRegister(uint32 reg, target_addr_t offset);
void _Call(uint64 offset, bool local); void _Call(uint64 offset, uint8 refType);
private: private:
DwarfExpressionEvaluationContext* fContext; DwarfExpressionEvaluationContext* fContext;
+322 -111
View File
@@ -147,11 +147,11 @@ public:
return false; return false;
} }
virtual status_t GetCallTarget(uint64 offset, bool local, virtual status_t GetCallTarget(uint64 offset, uint8 refType,
const void*& _block, off_t& _size) const void*& _block, off_t& _size)
{ {
// resolve the entry // resolve the entry
DebugInfoEntry* entry = fFile->_ResolveReference(fUnit, offset, local); DebugInfoEntry* entry = fFile->_ResolveReference(fUnit, offset, refType);
if (entry == NULL) if (entry == NULL)
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
@@ -459,8 +459,9 @@ DwarfFile::DwarfFile()
fEHFrameSection(NULL), fEHFrameSection(NULL),
fDebugLocationSection(NULL), fDebugLocationSection(NULL),
fDebugPublicTypesSection(NULL), fDebugPublicTypesSection(NULL),
fDebugTypesSection(NULL),
fCompilationUnits(20, true), fCompilationUnits(20, true),
fCurrentCompilationUnit(NULL), fTypesSectionRequired(false),
fFinished(false), fFinished(false),
fFinishError(B_OK) fFinishError(B_OK)
{ {
@@ -501,12 +502,16 @@ DwarfFile::Load(const char* fileName)
if (fName == NULL) if (fName == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
status_t error = fTypeUnits.Init();
if (error != B_OK)
return error;
// load the ELF file // load the ELF file
fElfFile = new(std::nothrow) ElfFile; fElfFile = new(std::nothrow) ElfFile;
if (fElfFile == NULL) if (fElfFile == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
status_t error = fElfFile->Init(fileName); error = fElfFile->Init(fileName);
if (error != B_OK) if (error != B_OK)
return error; return error;
@@ -535,72 +540,19 @@ DwarfFile::Load(const char* fileName)
return B_OK; return B_OK;
} }
// iterate through the debug info section error = _ParseDebugInfoSection();
DataReader dataReader(fDebugInfoSection->Data(), if (error != B_OK)
fDebugInfoSection->Size(), 4); return error;
// address size doesn't matter here
while (dataReader.HasData()) {
off_t unitHeaderOffset = dataReader.Offset();
bool dwarf64;
uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
off_t unitLengthOffset = dataReader.Offset(); if (fTypesSectionRequired) {
// the unitLength starts here fDebugTypesSection = debugInfoFile->GetSection(".debug_types");
if (fDebugTypesSection == NULL) {
if (unitLengthOffset + unitLength WARNING(".debug_types section required but missing.\n");
> (uint64)fDebugInfoSection->Size()) { return B_BAD_DATA;
WARNING("\"%s\": Invalid compilation unit length.\n", fileName);
break;
} }
error = _ParseTypesSection();
int version = dataReader.Read<uint16>(0);
off_t abbrevOffset = dwarf64
? dataReader.Read<uint64>(0)
: dataReader.Read<uint32>(0);
uint8 addressSize = dataReader.Read<uint8>(0);
if (dataReader.HasOverflow()) {
WARNING("\"%s\": Unexpected end of data in compilation unit "
"header.\n", fileName);
break;
}
TRACE_DIE("DWARF%d compilation unit: version %d, length: %" B_PRIu64
", abbrevOffset: %" B_PRIdOFF ", address size: %d\n",
dwarf64 ? 64 : 32, version, unitLength, abbrevOffset, addressSize);
if (version != 2 && version != 3) {
WARNING("\"%s\": Unsupported compilation unit version: %d\n",
fileName, version);
break;
}
if (addressSize != 4 && addressSize != 8) {
WARNING("\"%s\": Unsupported address size: %d\n", fileName,
addressSize);
break;
}
dataReader.SetAddressSize(addressSize);
off_t unitContentOffset = dataReader.Offset();
// create a compilation unit object
CompilationUnit* unit = new(std::nothrow) CompilationUnit(
unitHeaderOffset, unitContentOffset,
unitLength + (unitLengthOffset - unitHeaderOffset),
abbrevOffset, addressSize, dwarf64);
if (unit == NULL || !fCompilationUnits.AddItem(unit)) {
delete unit;
return B_NO_MEMORY;
}
// parse the debug info for the unit
fCurrentCompilationUnit = unit;
error = _ParseCompilationUnit(unit);
if (error != B_OK) if (error != B_OK)
return error; return error;
dataReader.SeekAbsolute(unitLengthOffset + unitLength);
} }
return B_OK; return B_OK;
@@ -615,10 +567,17 @@ DwarfFile::FinishLoading()
if (fFinishError != B_OK) if (fFinishError != B_OK)
return fFinishError; return fFinishError;
status_t error;
for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i); for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i);
i++) { i++) {
fCurrentCompilationUnit = unit; error = _FinishUnit(unit);
status_t error = _FinishCompilationUnit(unit); if (error != B_OK)
return fFinishError = error;
}
for (TypeUnitTable::Iterator it = fTypeUnits.GetIterator();
TypeUnitTableEntry* entry = it.Next();) {
error = _FinishUnit(entry->unit);
if (error != B_OK) if (error != B_OK)
return fFinishError = error; return fFinishError = error;
} }
@@ -935,6 +894,171 @@ DwarfFile::EvaluateDynamicValue(CompilationUnit* unit, uint8 addressSize,
} }
status_t
DwarfFile::_ParseDebugInfoSection()
{
// iterate through the debug info section
DataReader dataReader(fDebugInfoSection->Data(),
fDebugInfoSection->Size(), 4);
// address size doesn't matter here
while (dataReader.HasData()) {
off_t unitHeaderOffset = dataReader.Offset();
bool dwarf64;
uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
off_t unitLengthOffset = dataReader.Offset();
// the unitLength starts here
if (unitLengthOffset + unitLength
> (uint64)fDebugInfoSection->Size()) {
WARNING("\"%s\": Invalid compilation unit length.\n", fName);
break;
}
int version = dataReader.Read<uint16>(0);
off_t abbrevOffset = dwarf64
? dataReader.Read<uint64>(0)
: dataReader.Read<uint32>(0);
uint8 addressSize = dataReader.Read<uint8>(0);
if (dataReader.HasOverflow()) {
WARNING("\"%s\": Unexpected end of data in compilation unit "
"header.\n", fName);
break;
}
TRACE_DIE("DWARF%d compilation unit: version %d, length: %" B_PRIu64
", abbrevOffset: %" B_PRIdOFF ", address size: %d\n",
dwarf64 ? 64 : 32, version, unitLength, abbrevOffset, addressSize);
if (version < 2 || version > 4) {
WARNING("\"%s\": Unsupported compilation unit version: %d\n",
fName, version);
break;
}
if (addressSize != 4 && addressSize != 8) {
WARNING("\"%s\": Unsupported address size: %d\n", fName,
addressSize);
break;
}
dataReader.SetAddressSize(addressSize);
off_t unitContentOffset = dataReader.Offset();
// create a compilation unit object
CompilationUnit* unit = new(std::nothrow) CompilationUnit(
unitHeaderOffset, unitContentOffset,
unitLength + (unitLengthOffset - unitHeaderOffset),
abbrevOffset, addressSize, dwarf64);
if (unit == NULL || !fCompilationUnits.AddItem(unit)) {
delete unit;
return B_NO_MEMORY;
}
// parse the debug info for the unit
status_t error = _ParseCompilationUnit(unit);
if (error != B_OK)
return error;
dataReader.SeekAbsolute(unitLengthOffset + unitLength);
}
return B_OK;
}
status_t
DwarfFile::_ParseTypesSection()
{
DataReader dataReader(fDebugTypesSection->Data(),
fDebugTypesSection->Size(), 4);
while (dataReader.HasData()) {
off_t unitHeaderOffset = dataReader.Offset();
bool dwarf64;
uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
off_t unitLengthOffset = dataReader.Offset();
// the unitLength starts here
if (unitLengthOffset + unitLength
> (uint64)fDebugTypesSection->Size()) {
WARNING("Invalid type unit length, offset %#" B_PRIx64 ".\n",
unitHeaderOffset);
break;
}
int version = dataReader.Read<uint16>(0);
off_t abbrevOffset = dwarf64
? dataReader.Read<uint64>(0)
: dataReader.Read<uint32>(0);
uint8 addressSize = dataReader.Read<uint8>(0);
if (dataReader.HasOverflow()) {
WARNING("Unexpected end of data in type unit header at %#"
B_PRIx64 ".\n", unitHeaderOffset);
break;
}
TRACE_DIE("DWARF%d type unit: version %d, length: %" B_PRIu64
", abbrevOffset: %" B_PRIdOFF ", address size: %d\n",
dwarf64 ? 64 : 32, version, unitLength, abbrevOffset, addressSize);
if (version > 4) {
WARNING("\"%s\": Unsupported type unit version: %d\n",
fName, version);
break;
}
if (addressSize != 4 && addressSize != 8) {
WARNING("\"%s\": Unsupported address size: %d\n", fName,
addressSize);
break;
}
dataReader.SetAddressSize(addressSize);
uint64 signature = dataReader.Read<uint64>(0);
off_t typeOffset = dwarf64
? dataReader.Read<uint64>(0)
: dataReader.Read<uint32>(0);
off_t unitContentOffset = dataReader.Offset();
// create a type unit object
TypeUnit* unit = new(std::nothrow) TypeUnit(
unitHeaderOffset, unitContentOffset,
unitLength + (unitLengthOffset - unitHeaderOffset),
abbrevOffset, typeOffset, addressSize, signature, dwarf64);
if (unit == NULL) {
delete unit;
return B_NO_MEMORY;
}
// parse the debug info for the unit
status_t error = _ParseTypeUnit(unit);
if (error != B_OK)
return error;
// TODO: it should theoretically never happen that we get a duplicate,
// but it wouldn't hurt to check since that situation would potentially
// be problematic.
if (fTypeUnits.Lookup(signature) == NULL) {
TypeUnitTableEntry* entry = new(std::nothrow)
TypeUnitTableEntry(signature, unit);
if (entry == NULL)
return B_NO_MEMORY;
fTypeUnits.Insert(entry);
}
dataReader.SeekAbsolute(unitLengthOffset + unitLength);
}
return B_OK;
}
status_t status_t
DwarfFile::_ParseCompilationUnit(CompilationUnit* unit) DwarfFile::_ParseCompilationUnit(CompilationUnit* unit)
{ {
@@ -952,7 +1076,7 @@ DwarfFile::_ParseCompilationUnit(CompilationUnit* unit)
DebugInfoEntry* entry; DebugInfoEntry* entry;
bool endOfEntryList; bool endOfEntryList;
error = _ParseDebugInfoEntry(dataReader, abbreviationTable, entry, error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry,
endOfEntryList); endOfEntryList);
if (error != B_OK) if (error != B_OK)
return error; return error;
@@ -979,13 +1103,57 @@ DwarfFile::_ParseCompilationUnit(CompilationUnit* unit)
} }
status_t
DwarfFile::_ParseTypeUnit(TypeUnit* unit)
{
AbbreviationTable* abbreviationTable;
status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(),
abbreviationTable);
if (error != B_OK)
return error;
unit->SetAbbreviationTable(abbreviationTable);
DataReader dataReader(
(const uint8*)fDebugTypesSection->Data() + unit->ContentOffset(),
unit->ContentSize(), unit->AddressSize());
DebugInfoEntry* entry;
bool endOfEntryList;
error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry,
endOfEntryList);
if (error != B_OK)
return error;
DIETypeUnit* unitEntry = dynamic_cast<DIETypeUnit*>(entry);
if (unitEntry == NULL) {
WARNING("No type unit entry in .debug_types section.\n");
return B_BAD_DATA;
}
unit->SetUnitEntry(unitEntry);
TRACE_DIE_ONLY(
TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n",
dataReader.BytesRemaining());
if (dataReader.HasData()) {
TRACE_DIE(" ");
while (dataReader.HasData())
TRACE_DIE("%02x", dataReader.Read<uint8>(0));
TRACE_DIE("\n");
}
)
return B_OK;
}
status_t status_t
DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader, DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader,
AbbreviationTable* abbreviationTable, DebugInfoEntry*& _entry, BaseUnit* unit, AbbreviationTable* abbreviationTable,
bool& _endOfEntryList, int level) DebugInfoEntry*& _entry, bool& _endOfEntryList, int level)
{ {
off_t entryOffset = dataReader.Offset() off_t entryOffset = dataReader.Offset()
+ fCurrentCompilationUnit->RelativeContentOffset(); + unit->RelativeContentOffset();
uint32 code = dataReader.ReadUnsignedLEB128(0); uint32 code = dataReader.ReadUnsignedLEB128(0);
if (code == 0) { if (code == 0) {
@@ -1001,7 +1169,7 @@ DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader,
// get the corresponding abbreviation entry // get the corresponding abbreviation entry
AbbreviationEntry abbreviationEntry; AbbreviationEntry abbreviationEntry;
if (!abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry)) { if (!abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry)) {
WARNING("No abbreviation entry for code %" B_PRIu32 "\n", code); WARNING("No abbreviation entry for code %" B_PRIx32 "\n", code);
return B_BAD_DATA; return B_BAD_DATA;
} }
@@ -1021,12 +1189,13 @@ DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader,
abbreviationEntry.Code(), get_entry_tag_name(abbreviationEntry.Tag()), abbreviationEntry.Code(), get_entry_tag_name(abbreviationEntry.Tag()),
abbreviationEntry.Tag(), abbreviationEntry.HasChildren()); abbreviationEntry.Tag(), abbreviationEntry.HasChildren());
error = fCurrentCompilationUnit->AddDebugInfoEntry(entry, entryOffset); error = unit->AddDebugInfoEntry(entry, entryOffset);
if (error != B_OK) if (error != B_OK)
return error; return error;
// parse the attributes (supply NULL entry to avoid adding them yet) // parse the attributes (supply NULL entry to avoid adding them yet)
error = _ParseEntryAttributes(dataReader, NULL, abbreviationEntry); error = _ParseEntryAttributes(dataReader, unit, NULL, abbreviationEntry);
if (error != B_OK) if (error != B_OK)
return error; return error;
@@ -1036,7 +1205,7 @@ DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader,
DebugInfoEntry* childEntry; DebugInfoEntry* childEntry;
bool endOfEntryList; bool endOfEntryList;
status_t error = _ParseDebugInfoEntry(dataReader, status_t error = _ParseDebugInfoEntry(dataReader,
abbreviationTable, childEntry, endOfEntryList, level + 1); unit, abbreviationTable, childEntry, endOfEntryList, level + 1);
if (error != B_OK) if (error != B_OK)
return error; return error;
@@ -1072,14 +1241,20 @@ DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader,
status_t status_t
DwarfFile::_FinishCompilationUnit(CompilationUnit* unit) DwarfFile::_FinishUnit(BaseUnit* unit)
{ {
TRACE_DIE("\nfinishing compilation unit %p\n", unit); CompilationUnit* compilationUnit = dynamic_cast<CompilationUnit*>(unit);
bool isTypeUnit = compilationUnit == NULL;
TRACE_DIE("\nfinishing %s unit %p\n",
isTypeUnit ? "type" : "compilation", unit);
AbbreviationTable* abbreviationTable = unit->GetAbbreviationTable(); AbbreviationTable* abbreviationTable = unit->GetAbbreviationTable();
ElfSection* section = isTypeUnit
? fDebugTypesSection : fDebugInfoSection;
DataReader dataReader( DataReader dataReader(
(const uint8*)fDebugInfoSection->Data() + unit->HeaderOffset(), (const uint8*)section->Data() + unit->HeaderOffset(),
unit->TotalSize(), unit->AddressSize()); unit->TotalSize(), unit->AddressSize());
DebugInfoEntryInitInfo entryInitInfo; DebugInfoEntryInitInfo entryInitInfo;
@@ -1112,7 +1287,8 @@ DwarfFile::_FinishCompilationUnit(CompilationUnit* unit)
// parse the attributes -- this time pass the entry, so that the // parse the attributes -- this time pass the entry, so that the
// attribute get set on it // attribute get set on it
error = _ParseEntryAttributes(dataReader, entry, abbreviationEntry); error = _ParseEntryAttributes(dataReader, unit, entry,
abbreviationEntry);
if (error != B_OK) if (error != B_OK)
return error; return error;
@@ -1127,21 +1303,27 @@ DwarfFile::_FinishCompilationUnit(CompilationUnit* unit)
// set the compilation unit's source language // set the compilation unit's source language
unit->SetSourceLanguage(entryInitInfo.languageInfo); unit->SetSourceLanguage(entryInitInfo.languageInfo);
if (isTypeUnit)
return B_OK;
// resolve the compilation unit's address range list // resolve the compilation unit's address range list
if (TargetAddressRangeList* ranges = ResolveRangeList(unit, if (TargetAddressRangeList* ranges = ResolveRangeList(compilationUnit,
unit->UnitEntry()->AddressRangesOffset())) { compilationUnit->UnitEntry()->AddressRangesOffset())) {
unit->SetAddressRanges(ranges); compilationUnit->SetAddressRanges(ranges);
ranges->ReleaseReference(); ranges->ReleaseReference();
} }
// add compilation dir to directory list // add compilation dir to directory list
const char* compilationDir = unit->UnitEntry()->CompilationDir(); const char* compilationDir = compilationUnit->UnitEntry()
if (!unit->AddDirectory(compilationDir != NULL ? compilationDir : ".")) ->CompilationDir();
if (!compilationUnit->AddDirectory(compilationDir != NULL
? compilationDir : ".")) {
return B_NO_MEMORY; return B_NO_MEMORY;
}
// parse line info header // parse line info header
if (fDebugLineSection != NULL) if (fDebugLineSection != NULL)
_ParseLineInfo(unit); _ParseLineInfo(compilationUnit);
return B_OK; return B_OK;
} }
@@ -1149,7 +1331,7 @@ DwarfFile::_FinishCompilationUnit(CompilationUnit* unit)
status_t status_t
DwarfFile::_ParseEntryAttributes(DataReader& dataReader, DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
DebugInfoEntry* entry, AbbreviationEntry& abbreviationEntry) BaseUnit* unit, DebugInfoEntry* entry, AbbreviationEntry& abbreviationEntry)
{ {
uint32 attributeName; uint32 attributeName;
uint32 attributeForm; uint32 attributeForm;
@@ -1170,7 +1352,8 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
// first. // first.
uint64 value = 0; uint64 value = 0;
off_t blockLength = 0; off_t blockLength = 0;
bool localReference = true; off_t valueOffset = dataReader.Offset() + unit->ContentOffset();
uint8 refType = dwarf_reference_type_local;
switch (attributeForm) { switch (attributeForm) {
case DW_FORM_addr: case DW_FORM_addr:
@@ -1213,7 +1396,7 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
case DW_FORM_strp: case DW_FORM_strp:
{ {
if (fDebugStringSection != NULL) { if (fDebugStringSection != NULL) {
off_t offset = fCurrentCompilationUnit->IsDwarf64() off_t offset = unit->IsDwarf64()
? (off_t)dataReader.Read<uint64>(0) ? (off_t)dataReader.Read<uint64>(0)
: (off_t)dataReader.Read<uint32>(0); : (off_t)dataReader.Read<uint32>(0);
if (offset >= fDebugStringSection->Size()) { if (offset >= fDebugStringSection->Size()) {
@@ -1233,10 +1416,10 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
value = dataReader.ReadUnsignedLEB128(0); value = dataReader.ReadUnsignedLEB128(0);
break; break;
case DW_FORM_ref_addr: case DW_FORM_ref_addr:
value = fCurrentCompilationUnit->IsDwarf64() value = unit->IsDwarf64()
? dataReader.Read<uint64>(0) ? dataReader.Read<uint64>(0)
: (uint64)dataReader.Read<uint32>(0); : (uint64)dataReader.Read<uint32>(0);
localReference = false; refType = dwarf_reference_type_global;
break; break;
case DW_FORM_ref1: case DW_FORM_ref1:
value = dataReader.Read<uint8>(0); value = dataReader.Read<uint8>(0);
@@ -1260,10 +1443,12 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
attributeValue.SetToFlag(true); attributeValue.SetToFlag(true);
break; break;
case DW_FORM_ref_sig8: case DW_FORM_ref_sig8:
fTypesSectionRequired = true;
value = dataReader.Read<uint64>(0); value = dataReader.Read<uint64>(0);
refType = dwarf_reference_type_signature;
break; break;
case DW_FORM_sec_offset: case DW_FORM_sec_offset:
value = fCurrentCompilationUnit->IsDwarf64() value = unit->IsDwarf64()
? dataReader.Read<uint64>(0) ? dataReader.Read<uint64>(0)
: (uint64)dataReader.Read<uint32>(0); : (uint64)dataReader.Read<uint32>(0);
break; break;
@@ -1278,14 +1463,13 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
// it // it
uint8 attributeClass = get_attribute_class(attributeName, uint8 attributeClass = get_attribute_class(attributeName,
attributeForm); attributeForm);
if (attributeClass == ATTRIBUTE_CLASS_UNKNOWN) { if (attributeClass == ATTRIBUTE_CLASS_UNKNOWN) {
TRACE_DIE("skipping attribute with unrecognized class: %s (%#" TRACE_DIE("skipping attribute with unrecognized class: %s (%#"
B_PRIx32 ") %s (%#" B_PRIx32 ")\n", B_PRIx32 ") %s (%#" B_PRIx32 ")\n",
get_attribute_name_name(attributeName), attributeName, get_attribute_name_name(attributeName), attributeName,
get_attribute_form_name(attributeForm), attributeForm); get_attribute_form_name(attributeForm), attributeForm);
continue;
} }
// attributeValue.attributeClass = attributeClass;
// set the attribute value according to the attribute's class // set the attribute value according to the attribute's class
switch (attributeClass) { switch (attributeClass) {
@@ -1314,7 +1498,7 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
case ATTRIBUTE_CLASS_REFERENCE: case ATTRIBUTE_CLASS_REFERENCE:
if (entry != NULL) { if (entry != NULL) {
attributeValue.SetToReference(_ResolveReference( attributeValue.SetToReference(_ResolveReference(
fCurrentCompilationUnit, value, localReference)); unit, value, refType));
if (attributeValue.reference == NULL) { if (attributeValue.reference == NULL) {
// gcc 2 apparently somtimes produces DW_AT_sibling // gcc 2 apparently somtimes produces DW_AT_sibling
// attributes pointing to the end of the sibling list. // attributes pointing to the end of the sibling list.
@@ -1322,8 +1506,11 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
if (attributeName == DW_AT_sibling) if (attributeName == DW_AT_sibling)
continue; continue;
WARNING("Failed to resolve reference: %s (%#" B_PRIx32 WARNING("Failed to resolve reference on entry %p: "
") %s (%#" B_PRIx32 "): value: %" B_PRIu64 "\n", "(%#" B_PRIx64 ") %s (%#" B_PRIx32 ") %s "
"(%#" B_PRIx32 "): value: %#" B_PRIx64 "\n",
entry,
valueOffset,
get_attribute_name_name(attributeName), get_attribute_name_name(attributeName),
attributeName, attributeName,
get_attribute_form_name(attributeForm), get_attribute_form_name(attributeForm),
@@ -1337,6 +1524,7 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
// already set // already set
break; break;
case ATTRIBUTE_CLASS_EXPRESSION: case ATTRIBUTE_CLASS_EXPRESSION:
WARNING("Skipping unhandled attribute class expression.\n");
// TODO: implement // TODO: implement
dataReader.Skip(value); dataReader.Skip(value);
break; break;
@@ -1347,16 +1535,17 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
return B_BAD_DATA; return B_BAD_DATA;
} }
TRACE_DIE_ONLY(
char buffer[1024];
TRACE_DIE(" attr (%#" B_PRIx64 ") %s %s (%d): %s\n",
valueOffset,
get_attribute_name_name(attributeName),
get_attribute_form_name(attributeForm), attributeClass,
attributeValue.ToString(buffer, sizeof(buffer)));
)
// add the attribute // add the attribute
if (entry != NULL) { if (entry != NULL) {
TRACE_DIE_ONLY(
char buffer[1024];
TRACE_DIE(" attr %s %s (%d): %s\n",
get_attribute_name_name(attributeName),
get_attribute_form_name(attributeForm), attributeClass,
attributeValue.ToString(buffer, sizeof(buffer)));
)
DebugInfoEntrySetter attributeSetter DebugInfoEntrySetter attributeSetter
= get_attribute_name_setter(attributeName); = get_attribute_name_setter(attributeName);
if (attributeSetter != 0) { if (attributeSetter != 0) {
@@ -2378,13 +2567,27 @@ DwarfFile::_GetAbbreviationTable(off_t offset, AbbreviationTable*& _table)
DebugInfoEntry* DebugInfoEntry*
DwarfFile::_ResolveReference(CompilationUnit* unit, uint64 offset, DwarfFile::_ResolveReference(BaseUnit* unit, uint64 offset,
bool localReference) const uint8 refType) const
{ {
if (localReference) switch (refType) {
return unit->EntryForOffset(offset); case dwarf_reference_type_local:
return unit->EntryForOffset(offset);
break;
case dwarf_reference_type_global:
{
WARNING("DwarfFile: Unhandled global reference\n");
break;
}
case dwarf_reference_type_signature:
{
TypeUnitTableEntry* entry = fTypeUnits.Lookup(offset);
if (entry != NULL && entry->unit != NULL)
return entry->unit->TypeEntry();
break;
}
}
// TODO: Implement program-global references!
return NULL; return NULL;
} }
@@ -2524,7 +2727,8 @@ DwarfFile::_LocateDebugInfo()
status_t status_t
DwarfFile::_GetDebugInfoPath(const char* debugFileName, BString& _infoPath) DwarfFile::_GetDebugInfoPath(const char* debugFileName,
BString& _infoPath) const
{ {
const directory_which dirLocations[] = { B_USER_CONFIG_DIRECTORY, const directory_which dirLocations[] = { B_USER_CONFIG_DIRECTORY,
B_COMMON_DIRECTORY, B_SYSTEM_DIRECTORY }; B_COMMON_DIRECTORY, B_SYSTEM_DIRECTORY };
@@ -2571,3 +2775,10 @@ DwarfFile::_GetDebugInfoPath(const char* debugFileName, BString& _infoPath)
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
} }
TypeUnitTableEntry*
DwarfFile::_GetTypeUnit(uint64 signature) const
{
return fTypeUnits.Lookup(signature);
}
+18 -5
View File
@@ -10,8 +10,10 @@
#include <ObjectList.h> #include <ObjectList.h>
#include <Referenceable.h> #include <Referenceable.h>
#include <util/DoublyLinkedList.h> #include <util/DoublyLinkedList.h>
#include <util/OpenHashTable.h>
#include "DebugInfoEntries.h" #include "DebugInfoEntries.h"
#include "TypeUnit.h"
class AbbreviationEntry; class AbbreviationEntry;
@@ -107,15 +109,21 @@ private:
typedef DoublyLinkedList<AbbreviationTable> AbbreviationTableList; typedef DoublyLinkedList<AbbreviationTable> AbbreviationTableList;
typedef BObjectList<CompilationUnit> CompilationUnitList; typedef BObjectList<CompilationUnit> CompilationUnitList;
typedef BOpenHashTable<TypeUnitTableHashDefinition> TypeUnitTable;
private: private:
status_t _ParseDebugInfoSection();
status_t _ParseTypesSection();
status_t _ParseCompilationUnit(CompilationUnit* unit); status_t _ParseCompilationUnit(CompilationUnit* unit);
status_t _ParseTypeUnit(TypeUnit* unit);
status_t _ParseDebugInfoEntry(DataReader& dataReader, status_t _ParseDebugInfoEntry(DataReader& dataReader,
BaseUnit* unit,
AbbreviationTable* abbreviationTable, AbbreviationTable* abbreviationTable,
DebugInfoEntry*& _entry, DebugInfoEntry*& _entry,
bool& _endOfEntryList, int level = 0); bool& _endOfEntryList, int level = 0);
status_t _FinishCompilationUnit(CompilationUnit* unit); status_t _FinishUnit(BaseUnit* unit);
status_t _ParseEntryAttributes(DataReader& dataReader, status_t _ParseEntryAttributes(DataReader& dataReader,
BaseUnit* unit,
DebugInfoEntry* entry, DebugInfoEntry* entry,
AbbreviationEntry& abbreviationEntry); AbbreviationEntry& abbreviationEntry);
@@ -150,8 +158,9 @@ private:
status_t _GetAbbreviationTable(off_t offset, status_t _GetAbbreviationTable(off_t offset,
AbbreviationTable*& _table); AbbreviationTable*& _table);
DebugInfoEntry* _ResolveReference(CompilationUnit* unit, DebugInfoEntry* _ResolveReference(BaseUnit* unit,
uint64 offset, bool localReference) const; uint64 offset,
uint8 refType) const;
status_t _GetLocationExpression(CompilationUnit* unit, status_t _GetLocationExpression(CompilationUnit* unit,
const LocationDescription* location, const LocationDescription* location,
@@ -165,7 +174,9 @@ private:
status_t _LocateDebugInfo(); status_t _LocateDebugInfo();
status_t _GetDebugInfoPath(const char* fileName, status_t _GetDebugInfoPath(const char* fileName,
BString& _infoPath); BString& _infoPath) const;
TypeUnitTableEntry* _GetTypeUnit(uint64 signature) const;
private: private:
friend class DwarfFile::ExpressionEvaluationContext; friend class DwarfFile::ExpressionEvaluationContext;
@@ -184,10 +195,12 @@ private:
ElfSection* fEHFrameSection; ElfSection* fEHFrameSection;
ElfSection* fDebugLocationSection; ElfSection* fDebugLocationSection;
ElfSection* fDebugPublicTypesSection; ElfSection* fDebugPublicTypesSection;
ElfSection* fDebugTypesSection;
AbbreviationTableList fAbbreviationTables; AbbreviationTableList fAbbreviationTables;
DebugInfoEntryFactory fDebugInfoFactory; DebugInfoEntryFactory fDebugInfoFactory;
CompilationUnitList fCompilationUnits; CompilationUnitList fCompilationUnits;
CompilationUnit* fCurrentCompilationUnit; TypeUnitTable fTypeUnits;
bool fTypesSectionRequired;
bool fFinished; bool fFinished;
status_t fFinishError; status_t fFinishError;
}; };