From 71fec49e6725dd1ce645fb42504d1264044a3137 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Tue, 16 Jul 2013 22:47:30 -0400 Subject: [PATCH] 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. --- src/apps/debugger/dwarf/Dwarf.h | 7 + .../dwarf/DwarfExpressionEvaluator.cpp | 19 +- .../debugger/dwarf/DwarfExpressionEvaluator.h | 7 +- src/apps/debugger/dwarf/DwarfFile.cpp | 433 +++++++++++++----- src/apps/debugger/dwarf/DwarfFile.h | 23 +- 5 files changed, 362 insertions(+), 127 deletions(-) diff --git a/src/apps/debugger/dwarf/Dwarf.h b/src/apps/debugger/dwarf/Dwarf.h index 06dd514b7b..09d7eba9e1 100644 --- a/src/apps/debugger/dwarf/Dwarf.h +++ b/src/apps/debugger/dwarf/Dwarf.h @@ -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 diff --git a/src/apps/debugger/dwarf/DwarfExpressionEvaluator.cpp b/src/apps/debugger/dwarf/DwarfExpressionEvaluator.cpp index e1a431d08a..f47d5423b8 100644 --- a/src/apps/debugger/dwarf/DwarfExpressionEvaluator.cpp +++ b/src/apps/debugger/dwarf/DwarfExpressionEvaluator.cpp @@ -600,18 +600,21 @@ DwarfExpressionEvaluator::_Evaluate(ValuePieceLocation* _piece) case DW_OP_call2: TRACE_EXPR(" DW_OP_call2\n"); - _Call(fDataReader.Read(0), true); + _Call(fDataReader.Read(0), dwarf_reference_type_local); break; case DW_OP_call4: TRACE_EXPR(" DW_OP_call4\n"); - _Call(fDataReader.Read(0), true); + _Call(fDataReader.Read(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(0), false); - else - _Call(fDataReader.Read(0), false); + if (fContext->AddressSize() == 4) { + _Call(fDataReader.Read(0), + dwarf_reference_type_global); + } else { + _Call(fDataReader.Read(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 diff --git a/src/apps/debugger/dwarf/DwarfExpressionEvaluator.h b/src/apps/debugger/dwarf/DwarfExpressionEvaluator.h index 71faec2057..49e95e180f 100644 --- a/src/apps/debugger/dwarf/DwarfExpressionEvaluator.h +++ b/src/apps/debugger/dwarf/DwarfExpressionEvaluator.h @@ -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; diff --git a/src/apps/debugger/dwarf/DwarfFile.cpp b/src/apps/debugger/dwarf/DwarfFile.cpp index 58fa3761e3..4386fc1cd1 100644 --- a/src/apps/debugger/dwarf/DwarfFile.cpp +++ b/src/apps/debugger/dwarf/DwarfFile.cpp @@ -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(0); - off_t abbrevOffset = dwarf64 - ? dataReader.Read(0) - : dataReader.Read(0); - uint8 addressSize = dataReader.Read(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(0); + off_t abbrevOffset = dwarf64 + ? dataReader.Read(0) + : dataReader.Read(0); + uint8 addressSize = dataReader.Read(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(0); + off_t abbrevOffset = dwarf64 + ? dataReader.Read(0) + : dataReader.Read(0); + uint8 addressSize = dataReader.Read(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(0); + + off_t typeOffset = dwarf64 + ? dataReader.Read(0) + : dataReader.Read(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(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(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(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(0) : (off_t)dataReader.Read(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(0) : (uint64)dataReader.Read(0); - localReference = false; + refType = dwarf_reference_type_global; break; case DW_FORM_ref1: value = dataReader.Read(0); @@ -1260,10 +1443,12 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader, attributeValue.SetToFlag(true); break; case DW_FORM_ref_sig8: + fTypesSectionRequired = true; value = dataReader.Read(0); + refType = dwarf_reference_type_signature; break; case DW_FORM_sec_offset: - value = fCurrentCompilationUnit->IsDwarf64() + value = unit->IsDwarf64() ? dataReader.Read(0) : (uint64)dataReader.Read(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); +} + diff --git a/src/apps/debugger/dwarf/DwarfFile.h b/src/apps/debugger/dwarf/DwarfFile.h index 52575c3732..cf0d650474 100644 --- a/src/apps/debugger/dwarf/DwarfFile.h +++ b/src/apps/debugger/dwarf/DwarfFile.h @@ -10,8 +10,10 @@ #include #include #include +#include #include "DebugInfoEntries.h" +#include "TypeUnit.h" class AbbreviationEntry; @@ -107,15 +109,21 @@ private: typedef DoublyLinkedList AbbreviationTableList; typedef BObjectList CompilationUnitList; + typedef BOpenHashTable 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; };