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:
parent
4bf8368675
commit
71fec49e67
|
@ -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
|
||||
|
|
|
@ -600,18 +600,21 @@ DwarfExpressionEvaluator::_Evaluate(ValuePieceLocation* _piece)
|
|||
|
||||
case DW_OP_call2:
|
||||
TRACE_EXPR(" DW_OP_call2\n");
|
||||
_Call(fDataReader.Read<uint16>(0), true);
|
||||
_Call(fDataReader.Read<uint16>(0), dwarf_reference_type_local);
|
||||
break;
|
||||
case DW_OP_call4:
|
||||
TRACE_EXPR(" DW_OP_call4\n");
|
||||
_Call(fDataReader.Read<uint32>(0), true);
|
||||
_Call(fDataReader.Read<uint32>(0), dwarf_reference_type_local);
|
||||
break;
|
||||
case DW_OP_call_ref:
|
||||
TRACE_EXPR(" DW_OP_call_ref\n");
|
||||
if (fContext->AddressSize() == 4)
|
||||
_Call(fDataReader.Read<uint32>(0), false);
|
||||
else
|
||||
_Call(fDataReader.Read<uint64>(0), false);
|
||||
if (fContext->AddressSize() == 4) {
|
||||
_Call(fDataReader.Read<uint32>(0),
|
||||
dwarf_reference_type_global);
|
||||
} else {
|
||||
_Call(fDataReader.Read<uint64>(0),
|
||||
dwarf_reference_type_global);
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_OP_piece:
|
||||
|
@ -746,7 +749,7 @@ DwarfExpressionEvaluator::_PushRegister(uint32 reg, target_addr_t offset)
|
|||
|
||||
|
||||
void
|
||||
DwarfExpressionEvaluator::_Call(uint64 offset, bool local)
|
||||
DwarfExpressionEvaluator::_Call(uint64 offset, uint8 refType)
|
||||
{
|
||||
if (fDataReader.HasOverflow())
|
||||
throw EvaluationException("unexpected end of expression");
|
||||
|
@ -754,7 +757,7 @@ DwarfExpressionEvaluator::_Call(uint64 offset, bool local)
|
|||
// get the expression to "call"
|
||||
const void* block;
|
||||
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");
|
||||
|
||||
// no expression is OK, then this is just a no-op
|
||||
|
|
|
@ -37,8 +37,9 @@ public:
|
|||
virtual bool GetTLSAddress(target_addr_t localAddress,
|
||||
target_addr_t& _address) = 0;
|
||||
|
||||
virtual status_t GetCallTarget(uint64 offset, bool local,
|
||||
const void*& _block, off_t& _size) = 0;
|
||||
virtual status_t GetCallTarget(uint64 offset,
|
||||
uint8 refType, const void*& _block,
|
||||
off_t& _size) = 0;
|
||||
// returns error, when an error resolving
|
||||
// the entry occurs; returns B_OK and a NULL
|
||||
// block, when the entry doesn't have a
|
||||
|
@ -81,7 +82,7 @@ private:
|
|||
void _DereferenceAddressSpaceAddress(
|
||||
uint8 addressSize);
|
||||
void _PushRegister(uint32 reg, target_addr_t offset);
|
||||
void _Call(uint64 offset, bool local);
|
||||
void _Call(uint64 offset, uint8 refType);
|
||||
|
||||
private:
|
||||
DwarfExpressionEvaluationContext* fContext;
|
||||
|
|
|
@ -147,11 +147,11 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual status_t GetCallTarget(uint64 offset, bool local,
|
||||
virtual status_t GetCallTarget(uint64 offset, uint8 refType,
|
||||
const void*& _block, off_t& _size)
|
||||
{
|
||||
// resolve the entry
|
||||
DebugInfoEntry* entry = fFile->_ResolveReference(fUnit, offset, local);
|
||||
DebugInfoEntry* entry = fFile->_ResolveReference(fUnit, offset, refType);
|
||||
if (entry == NULL)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
|
@ -459,8 +459,9 @@ DwarfFile::DwarfFile()
|
|||
fEHFrameSection(NULL),
|
||||
fDebugLocationSection(NULL),
|
||||
fDebugPublicTypesSection(NULL),
|
||||
fDebugTypesSection(NULL),
|
||||
fCompilationUnits(20, true),
|
||||
fCurrentCompilationUnit(NULL),
|
||||
fTypesSectionRequired(false),
|
||||
fFinished(false),
|
||||
fFinishError(B_OK)
|
||||
{
|
||||
|
@ -501,12 +502,16 @@ DwarfFile::Load(const char* fileName)
|
|||
if (fName == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t error = fTypeUnits.Init();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// load the ELF file
|
||||
fElfFile = new(std::nothrow) ElfFile;
|
||||
if (fElfFile == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t error = fElfFile->Init(fileName);
|
||||
error = fElfFile->Init(fileName);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
|
@ -535,72 +540,19 @@ DwarfFile::Load(const char* fileName)
|
|||
return B_OK;
|
||||
}
|
||||
|
||||
// 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);
|
||||
error = _ParseDebugInfoSection();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
off_t unitLengthOffset = dataReader.Offset();
|
||||
// the unitLength starts here
|
||||
|
||||
if (unitLengthOffset + unitLength
|
||||
> (uint64)fDebugInfoSection->Size()) {
|
||||
WARNING("\"%s\": Invalid compilation unit length.\n", fileName);
|
||||
break;
|
||||
if (fTypesSectionRequired) {
|
||||
fDebugTypesSection = debugInfoFile->GetSection(".debug_types");
|
||||
if (fDebugTypesSection == NULL) {
|
||||
WARNING(".debug_types section required but missing.\n");
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
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);
|
||||
error = _ParseTypesSection();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
dataReader.SeekAbsolute(unitLengthOffset + unitLength);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
|
@ -615,10 +567,17 @@ DwarfFile::FinishLoading()
|
|||
if (fFinishError != B_OK)
|
||||
return fFinishError;
|
||||
|
||||
status_t error;
|
||||
for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i);
|
||||
i++) {
|
||||
fCurrentCompilationUnit = unit;
|
||||
status_t error = _FinishCompilationUnit(unit);
|
||||
error = _FinishUnit(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)
|
||||
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
|
||||
DwarfFile::_ParseCompilationUnit(CompilationUnit* unit)
|
||||
{
|
||||
|
@ -952,7 +1076,7 @@ DwarfFile::_ParseCompilationUnit(CompilationUnit* unit)
|
|||
|
||||
DebugInfoEntry* entry;
|
||||
bool endOfEntryList;
|
||||
error = _ParseDebugInfoEntry(dataReader, abbreviationTable, entry,
|
||||
error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry,
|
||||
endOfEntryList);
|
||||
if (error != B_OK)
|
||||
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
|
||||
DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader,
|
||||
AbbreviationTable* abbreviationTable, DebugInfoEntry*& _entry,
|
||||
bool& _endOfEntryList, int level)
|
||||
BaseUnit* unit, AbbreviationTable* abbreviationTable,
|
||||
DebugInfoEntry*& _entry, bool& _endOfEntryList, int level)
|
||||
{
|
||||
off_t entryOffset = dataReader.Offset()
|
||||
+ fCurrentCompilationUnit->RelativeContentOffset();
|
||||
+ unit->RelativeContentOffset();
|
||||
|
||||
uint32 code = dataReader.ReadUnsignedLEB128(0);
|
||||
if (code == 0) {
|
||||
|
@ -1001,7 +1169,7 @@ DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader,
|
|||
// get the corresponding abbreviation entry
|
||||
AbbreviationEntry 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;
|
||||
}
|
||||
|
||||
|
@ -1021,12 +1189,13 @@ DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader,
|
|||
abbreviationEntry.Code(), get_entry_tag_name(abbreviationEntry.Tag()),
|
||||
abbreviationEntry.Tag(), abbreviationEntry.HasChildren());
|
||||
|
||||
error = fCurrentCompilationUnit->AddDebugInfoEntry(entry, entryOffset);
|
||||
error = unit->AddDebugInfoEntry(entry, entryOffset);
|
||||
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// 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)
|
||||
return error;
|
||||
|
||||
|
@ -1036,7 +1205,7 @@ DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader,
|
|||
DebugInfoEntry* childEntry;
|
||||
bool endOfEntryList;
|
||||
status_t error = _ParseDebugInfoEntry(dataReader,
|
||||
abbreviationTable, childEntry, endOfEntryList, level + 1);
|
||||
unit, abbreviationTable, childEntry, endOfEntryList, level + 1);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
|
@ -1072,14 +1241,20 @@ DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader,
|
|||
|
||||
|
||||
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();
|
||||
|
||||
ElfSection* section = isTypeUnit
|
||||
? fDebugTypesSection : fDebugInfoSection;
|
||||
DataReader dataReader(
|
||||
(const uint8*)fDebugInfoSection->Data() + unit->HeaderOffset(),
|
||||
(const uint8*)section->Data() + unit->HeaderOffset(),
|
||||
unit->TotalSize(), unit->AddressSize());
|
||||
|
||||
DebugInfoEntryInitInfo entryInitInfo;
|
||||
|
@ -1112,7 +1287,8 @@ DwarfFile::_FinishCompilationUnit(CompilationUnit* unit)
|
|||
|
||||
// parse the attributes -- this time pass the entry, so that the
|
||||
// attribute get set on it
|
||||
error = _ParseEntryAttributes(dataReader, entry, abbreviationEntry);
|
||||
error = _ParseEntryAttributes(dataReader, unit, entry,
|
||||
abbreviationEntry);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
|
@ -1127,21 +1303,27 @@ DwarfFile::_FinishCompilationUnit(CompilationUnit* unit)
|
|||
// set the compilation unit's source language
|
||||
unit->SetSourceLanguage(entryInitInfo.languageInfo);
|
||||
|
||||
if (isTypeUnit)
|
||||
return B_OK;
|
||||
|
||||
// resolve the compilation unit's address range list
|
||||
if (TargetAddressRangeList* ranges = ResolveRangeList(unit,
|
||||
unit->UnitEntry()->AddressRangesOffset())) {
|
||||
unit->SetAddressRanges(ranges);
|
||||
if (TargetAddressRangeList* ranges = ResolveRangeList(compilationUnit,
|
||||
compilationUnit->UnitEntry()->AddressRangesOffset())) {
|
||||
compilationUnit->SetAddressRanges(ranges);
|
||||
ranges->ReleaseReference();
|
||||
}
|
||||
|
||||
// add compilation dir to directory list
|
||||
const char* compilationDir = unit->UnitEntry()->CompilationDir();
|
||||
if (!unit->AddDirectory(compilationDir != NULL ? compilationDir : "."))
|
||||
const char* compilationDir = compilationUnit->UnitEntry()
|
||||
->CompilationDir();
|
||||
if (!compilationUnit->AddDirectory(compilationDir != NULL
|
||||
? compilationDir : ".")) {
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
// parse line info header
|
||||
if (fDebugLineSection != NULL)
|
||||
_ParseLineInfo(unit);
|
||||
_ParseLineInfo(compilationUnit);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -1149,7 +1331,7 @@ DwarfFile::_FinishCompilationUnit(CompilationUnit* unit)
|
|||
|
||||
status_t
|
||||
DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
|
||||
DebugInfoEntry* entry, AbbreviationEntry& abbreviationEntry)
|
||||
BaseUnit* unit, DebugInfoEntry* entry, AbbreviationEntry& abbreviationEntry)
|
||||
{
|
||||
uint32 attributeName;
|
||||
uint32 attributeForm;
|
||||
|
@ -1170,7 +1352,8 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
|
|||
// first.
|
||||
uint64 value = 0;
|
||||
off_t blockLength = 0;
|
||||
bool localReference = true;
|
||||
off_t valueOffset = dataReader.Offset() + unit->ContentOffset();
|
||||
uint8 refType = dwarf_reference_type_local;
|
||||
|
||||
switch (attributeForm) {
|
||||
case DW_FORM_addr:
|
||||
|
@ -1213,7 +1396,7 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
|
|||
case DW_FORM_strp:
|
||||
{
|
||||
if (fDebugStringSection != NULL) {
|
||||
off_t offset = fCurrentCompilationUnit->IsDwarf64()
|
||||
off_t offset = unit->IsDwarf64()
|
||||
? (off_t)dataReader.Read<uint64>(0)
|
||||
: (off_t)dataReader.Read<uint32>(0);
|
||||
if (offset >= fDebugStringSection->Size()) {
|
||||
|
@ -1233,10 +1416,10 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
|
|||
value = dataReader.ReadUnsignedLEB128(0);
|
||||
break;
|
||||
case DW_FORM_ref_addr:
|
||||
value = fCurrentCompilationUnit->IsDwarf64()
|
||||
value = unit->IsDwarf64()
|
||||
? dataReader.Read<uint64>(0)
|
||||
: (uint64)dataReader.Read<uint32>(0);
|
||||
localReference = false;
|
||||
refType = dwarf_reference_type_global;
|
||||
break;
|
||||
case DW_FORM_ref1:
|
||||
value = dataReader.Read<uint8>(0);
|
||||
|
@ -1260,10 +1443,12 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
|
|||
attributeValue.SetToFlag(true);
|
||||
break;
|
||||
case DW_FORM_ref_sig8:
|
||||
fTypesSectionRequired = true;
|
||||
value = dataReader.Read<uint64>(0);
|
||||
refType = dwarf_reference_type_signature;
|
||||
break;
|
||||
case DW_FORM_sec_offset:
|
||||
value = fCurrentCompilationUnit->IsDwarf64()
|
||||
value = unit->IsDwarf64()
|
||||
? dataReader.Read<uint64>(0)
|
||||
: (uint64)dataReader.Read<uint32>(0);
|
||||
break;
|
||||
|
@ -1278,14 +1463,13 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
|
|||
// it
|
||||
uint8 attributeClass = get_attribute_class(attributeName,
|
||||
attributeForm);
|
||||
|
||||
if (attributeClass == ATTRIBUTE_CLASS_UNKNOWN) {
|
||||
TRACE_DIE("skipping attribute with unrecognized class: %s (%#"
|
||||
B_PRIx32 ") %s (%#" B_PRIx32 ")\n",
|
||||
get_attribute_name_name(attributeName), attributeName,
|
||||
get_attribute_form_name(attributeForm), attributeForm);
|
||||
continue;
|
||||
}
|
||||
// attributeValue.attributeClass = attributeClass;
|
||||
|
||||
// set the attribute value according to the attribute's class
|
||||
switch (attributeClass) {
|
||||
|
@ -1314,7 +1498,7 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
|
|||
case ATTRIBUTE_CLASS_REFERENCE:
|
||||
if (entry != NULL) {
|
||||
attributeValue.SetToReference(_ResolveReference(
|
||||
fCurrentCompilationUnit, value, localReference));
|
||||
unit, value, refType));
|
||||
if (attributeValue.reference == NULL) {
|
||||
// gcc 2 apparently somtimes produces DW_AT_sibling
|
||||
// attributes pointing to the end of the sibling list.
|
||||
|
@ -1322,8 +1506,11 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
|
|||
if (attributeName == DW_AT_sibling)
|
||||
continue;
|
||||
|
||||
WARNING("Failed to resolve reference: %s (%#" B_PRIx32
|
||||
") %s (%#" B_PRIx32 "): value: %" B_PRIu64 "\n",
|
||||
WARNING("Failed to resolve reference on entry %p: "
|
||||
"(%#" B_PRIx64 ") %s (%#" B_PRIx32 ") %s "
|
||||
"(%#" B_PRIx32 "): value: %#" B_PRIx64 "\n",
|
||||
entry,
|
||||
valueOffset,
|
||||
get_attribute_name_name(attributeName),
|
||||
attributeName,
|
||||
get_attribute_form_name(attributeForm),
|
||||
|
@ -1337,6 +1524,7 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
|
|||
// already set
|
||||
break;
|
||||
case ATTRIBUTE_CLASS_EXPRESSION:
|
||||
WARNING("Skipping unhandled attribute class expression.\n");
|
||||
// TODO: implement
|
||||
dataReader.Skip(value);
|
||||
break;
|
||||
|
@ -1347,16 +1535,17 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
|
|||
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
|
||||
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
|
||||
= get_attribute_name_setter(attributeName);
|
||||
if (attributeSetter != 0) {
|
||||
|
@ -2378,13 +2567,27 @@ DwarfFile::_GetAbbreviationTable(off_t offset, AbbreviationTable*& _table)
|
|||
|
||||
|
||||
DebugInfoEntry*
|
||||
DwarfFile::_ResolveReference(CompilationUnit* unit, uint64 offset,
|
||||
bool localReference) const
|
||||
DwarfFile::_ResolveReference(BaseUnit* unit, uint64 offset,
|
||||
uint8 refType) const
|
||||
{
|
||||
if (localReference)
|
||||
return unit->EntryForOffset(offset);
|
||||
switch (refType) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2524,7 +2727,8 @@ DwarfFile::_LocateDebugInfo()
|
|||
|
||||
|
||||
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,
|
||||
B_COMMON_DIRECTORY, B_SYSTEM_DIRECTORY };
|
||||
|
@ -2571,3 +2775,10 @@ DwarfFile::_GetDebugInfoPath(const char* debugFileName, BString& _infoPath)
|
|||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
TypeUnitTableEntry*
|
||||
DwarfFile::_GetTypeUnit(uint64 signature) const
|
||||
{
|
||||
return fTypeUnits.Lookup(signature);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,10 @@
|
|||
#include <ObjectList.h>
|
||||
#include <Referenceable.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
#include <util/OpenHashTable.h>
|
||||
|
||||
#include "DebugInfoEntries.h"
|
||||
#include "TypeUnit.h"
|
||||
|
||||
|
||||
class AbbreviationEntry;
|
||||
|
@ -107,15 +109,21 @@ private:
|
|||
|
||||
typedef DoublyLinkedList<AbbreviationTable> AbbreviationTableList;
|
||||
typedef BObjectList<CompilationUnit> CompilationUnitList;
|
||||
typedef BOpenHashTable<TypeUnitTableHashDefinition> TypeUnitTable;
|
||||
|
||||
private:
|
||||
status_t _ParseDebugInfoSection();
|
||||
status_t _ParseTypesSection();
|
||||
status_t _ParseCompilationUnit(CompilationUnit* unit);
|
||||
status_t _ParseTypeUnit(TypeUnit* unit);
|
||||
status_t _ParseDebugInfoEntry(DataReader& dataReader,
|
||||
BaseUnit* unit,
|
||||
AbbreviationTable* abbreviationTable,
|
||||
DebugInfoEntry*& _entry,
|
||||
bool& _endOfEntryList, int level = 0);
|
||||
status_t _FinishCompilationUnit(CompilationUnit* unit);
|
||||
status_t _FinishUnit(BaseUnit* unit);
|
||||
status_t _ParseEntryAttributes(DataReader& dataReader,
|
||||
BaseUnit* unit,
|
||||
DebugInfoEntry* entry,
|
||||
AbbreviationEntry& abbreviationEntry);
|
||||
|
||||
|
@ -150,8 +158,9 @@ private:
|
|||
status_t _GetAbbreviationTable(off_t offset,
|
||||
AbbreviationTable*& _table);
|
||||
|
||||
DebugInfoEntry* _ResolveReference(CompilationUnit* unit,
|
||||
uint64 offset, bool localReference) const;
|
||||
DebugInfoEntry* _ResolveReference(BaseUnit* unit,
|
||||
uint64 offset,
|
||||
uint8 refType) const;
|
||||
|
||||
status_t _GetLocationExpression(CompilationUnit* unit,
|
||||
const LocationDescription* location,
|
||||
|
@ -165,7 +174,9 @@ private:
|
|||
|
||||
status_t _LocateDebugInfo();
|
||||
status_t _GetDebugInfoPath(const char* fileName,
|
||||
BString& _infoPath);
|
||||
BString& _infoPath) const;
|
||||
|
||||
TypeUnitTableEntry* _GetTypeUnit(uint64 signature) const;
|
||||
|
||||
private:
|
||||
friend class DwarfFile::ExpressionEvaluationContext;
|
||||
|
@ -184,10 +195,12 @@ private:
|
|||
ElfSection* fEHFrameSection;
|
||||
ElfSection* fDebugLocationSection;
|
||||
ElfSection* fDebugPublicTypesSection;
|
||||
ElfSection* fDebugTypesSection;
|
||||
AbbreviationTableList fAbbreviationTables;
|
||||
DebugInfoEntryFactory fDebugInfoFactory;
|
||||
CompilationUnitList fCompilationUnits;
|
||||
CompilationUnit* fCurrentCompilationUnit;
|
||||
TypeUnitTable fTypeUnits;
|
||||
bool fTypesSectionRequired;
|
||||
bool fFinished;
|
||||
status_t fFinishError;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue