From 7a7112b32d3c8f51a0e89ef2fc9d20a6a4c04159 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 27 Jun 2009 22:12:26 +0000 Subject: [PATCH] * Renaming and coding moving. * Added locking to DwarfManager. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31279 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/debugger/Jamfile | 12 +- src/apps/debugger/dwarf/AbbreviationTable.cpp | 123 +++ src/apps/debugger/dwarf/AbbreviationTable.h | 125 +++ ...ibute_classes.cpp => AttributeClasses.cpp} | 4 +- ...attribute_classes.h => AttributeClasses.h} | 0 src/apps/debugger/dwarf/AttributeValue.cpp | 2 +- src/apps/debugger/dwarf/AttributeValue.h | 4 +- src/apps/debugger/dwarf/CompilationUnit.cpp | 82 ++ src/apps/debugger/dwarf/CompilationUnit.h | 61 ++ src/apps/debugger/dwarf/DebugInfoEntries.cpp | 2 +- src/apps/debugger/dwarf/DebugInfoEntry.cpp | 2 +- src/apps/debugger/dwarf/DebugInfoEntry.h | 2 +- src/apps/debugger/dwarf/{dwarf.h => Dwarf.h} | 0 src/apps/debugger/dwarf/DwarfFile.cpp | 592 +++++++++++ src/apps/debugger/dwarf/DwarfFile.h | 67 ++ src/apps/debugger/dwarf/DwarfManager.cpp | 927 +----------------- src/apps/debugger/dwarf/DwarfManager.h | 15 +- .../debugger/dwarf/{types.h => DwarfTypes.h} | 6 +- src/apps/debugger/dwarf/Jamfile | 25 + .../debugger/dwarf/SourceLanguageInfo.cpp | 2 +- .../dwarf/{tag_names.cpp => TagNames.cpp} | 4 +- .../dwarf/{tag_names.h => TagNames.h} | 6 +- 22 files changed, 1114 insertions(+), 949 deletions(-) create mode 100644 src/apps/debugger/dwarf/AbbreviationTable.cpp create mode 100644 src/apps/debugger/dwarf/AbbreviationTable.h rename src/apps/debugger/dwarf/{attribute_classes.cpp => AttributeClasses.cpp} (99%) rename src/apps/debugger/dwarf/{attribute_classes.h => AttributeClasses.h} (100%) create mode 100644 src/apps/debugger/dwarf/CompilationUnit.cpp create mode 100644 src/apps/debugger/dwarf/CompilationUnit.h rename src/apps/debugger/dwarf/{dwarf.h => Dwarf.h} (100%) create mode 100644 src/apps/debugger/dwarf/DwarfFile.cpp create mode 100644 src/apps/debugger/dwarf/DwarfFile.h rename src/apps/debugger/dwarf/{types.h => DwarfTypes.h} (82%) create mode 100644 src/apps/debugger/dwarf/Jamfile rename src/apps/debugger/dwarf/{tag_names.cpp => TagNames.cpp} (97%) rename src/apps/debugger/dwarf/{tag_names.h => TagNames.h} (70%) diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index 9d3e369766..1a3a95a819 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -10,7 +10,6 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) arch ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) arch x86 ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) debug_info ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) debugger_interface ] ; -SEARCH_SOURCE += [ FDirName $(SUBDIR) dwarf ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) elf ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) gui team_window ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) model ] ; @@ -55,15 +54,6 @@ Application Debugger : DebugEvent.cpp DebuggerInterface.cpp - # dwarf - attribute_classes.cpp - AttributeValue.cpp - DebugInfoEntries.cpp - DebugInfoEntry.cpp - DwarfManager.cpp - SourceLanguageInfo.cpp - tag_names.cpp - # elf ElfFile.cpp @@ -95,6 +85,7 @@ Application Debugger : : Debugger_demangler.o Debugger_disasm_x86.o + Debugger_dwarf.o DebugAnalyzer_gui_table.o libudis86.a @@ -110,4 +101,5 @@ Application Debugger : HaikuSubInclude arch x86 disasm ; HaikuSubInclude demangler ; +HaikuSubInclude dwarf ; HaikuSubInclude gui running_teams_window ; diff --git a/src/apps/debugger/dwarf/AbbreviationTable.cpp b/src/apps/debugger/dwarf/AbbreviationTable.cpp new file mode 100644 index 0000000000..15de90cfbc --- /dev/null +++ b/src/apps/debugger/dwarf/AbbreviationTable.cpp @@ -0,0 +1,123 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "AbbreviationTable.h" + +#include + +#include + + +AbbreviationTable::AbbreviationTable(off_t offset) + : + fOffset(offset), + fData(NULL), + fSize(0) +{ +} + + +AbbreviationTable::~AbbreviationTable() +{ +} + + +status_t +AbbreviationTable::Init(const void* section, off_t sectionSize) +{ + if (fOffset < 0 || fOffset >= sectionSize) + return B_BAD_DATA; + + fData = (uint8*)section + fOffset; + fSize = sectionSize - fOffset; + // That's only the maximum size. Will be adjusted at the end. + + status_t error = fEntryTable.Init(); + if (error != B_OK) + return error; + + DataReader abbrevReader(fData, fSize); + + while (true) { + bool nullEntry; + status_t error = _ParseAbbreviationEntry(abbrevReader, nullEntry); + if (error != B_OK) + return error; + + if (nullEntry) + break; + } + + fSize -= abbrevReader.BytesRemaining(); + + return B_OK; +} + + +bool +AbbreviationTable::GetAbbreviationEntry(uint32 code, AbbreviationEntry& entry) +{ + AbbreviationTableEntry* tableEntry = fEntryTable.Lookup(code); + if (tableEntry == NULL) + return false; + + entry.SetTo(code, fData + tableEntry->offset, tableEntry->size); + return true; +} + + +status_t +AbbreviationTable::_ParseAbbreviationEntry(DataReader& abbrevReader, + bool& _nullEntry) +{ + uint32 code = abbrevReader.ReadUnsignedLEB128(0); + if (code == 0) { + if (abbrevReader.HasOverflow()) { + fprintf(stderr, "Invalid abbreviation table 1!\n"); + return B_BAD_DATA; + } + _nullEntry = true; + return B_OK; + } + + off_t remaining = abbrevReader.BytesRemaining(); + +/* uint32 tag =*/ abbrevReader.ReadUnsignedLEB128(0); +/* uint8 hasChildren =*/ abbrevReader.Read(DW_CHILDREN_no); + +// printf("entry: %lu, tag: %lu, children: %d\n", code, tag, +// hasChildren); + + // parse attribute specifications + while (true) { + uint32 attributeName = abbrevReader.ReadUnsignedLEB128(0); + uint32 attributeForm = abbrevReader.ReadUnsignedLEB128(0); + if (abbrevReader.HasOverflow()) { + fprintf(stderr, "Invalid abbreviation table 2!\n"); + return B_BAD_DATA; + } + + if (attributeName == 0 && attributeForm == 0) + break; + +// printf(" attr: name: %lu, form: %lu\n", attributeName, +// attributeForm); + } + + // create the entry + if (fEntryTable.Lookup(code) == NULL) { + AbbreviationTableEntry* entry = new(std::nothrow) + AbbreviationTableEntry(code, fSize - remaining, + remaining - abbrevReader.BytesRemaining()); + if (entry == NULL) + return B_NO_MEMORY; + + fEntryTable.Insert(entry); + } else + fprintf(stderr, "Duplicate abbreviation table entry %lu!\n", code); + + _nullEntry = false; + return B_OK; +} diff --git a/src/apps/debugger/dwarf/AbbreviationTable.h b/src/apps/debugger/dwarf/AbbreviationTable.h new file mode 100644 index 0000000000..17756cd633 --- /dev/null +++ b/src/apps/debugger/dwarf/AbbreviationTable.h @@ -0,0 +1,125 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef ABBREVIATION_TABLE_H +#define ABBREVIATION_TABLE_H + +#include +#include + +#include "DataReader.h" +#include "Dwarf.h" + + +struct AbbreviationTableEntry : HashTableLink { + uint32 code; + off_t offset; + off_t size; + + AbbreviationTableEntry(uint32 code, off_t offset, off_t size) + : + code(code), + offset(offset), + size(size) + { + } +}; + + +struct AbbreviationEntry { + AbbreviationEntry() + { + } + + AbbreviationEntry(uint32 code, const void* data, off_t size) + { + SetTo(code, data, size); + } + + void SetTo(uint32 code, const void* data, off_t size) + { + fCode = code; + fAttributesReader.SetTo(data, size); + fTag = fAttributesReader.ReadUnsignedLEB128(0); + fHasChildren = fAttributesReader.Read(0); + fData = fAttributesReader.Data(); + fSize = fAttributesReader.BytesRemaining(); + } + + uint32 Code() const { return fCode; } + uint32 Tag() const { return fTag; } + bool HasChildren() const { return fHasChildren == DW_CHILDREN_yes; } + + bool GetNextAttribute(uint32& name, uint32& form) + { + name = fAttributesReader.ReadUnsignedLEB128(0); + form = fAttributesReader.ReadUnsignedLEB128(0); + return !fAttributesReader.HasOverflow() && (name != 0 || form != 0); + } + +private: + uint32 fCode; + const void* fData; + off_t fSize; + uint32 fTag; + uint8 fHasChildren; + DataReader fAttributesReader; +}; + + +struct AbbreviationTableHashDefinition { + typedef uint32 KeyType; + typedef AbbreviationTableEntry ValueType; + + size_t HashKey(uint32 key) const + { + return (size_t)key; + } + + size_t Hash(AbbreviationTableEntry* value) const + { + return HashKey(value->code); + } + + bool Compare(uint32 key, AbbreviationTableEntry* value) const + { + return value->code == key; + } + + HashTableLink* GetLink( + AbbreviationTableEntry* value) const + { + return value; + } +}; + + +class AbbreviationTable : public DoublyLinkedListLinkImpl { +public: + AbbreviationTable(off_t offset); + ~AbbreviationTable(); + + status_t Init(const void* section, off_t sectionSize); + + off_t Offset() const { return fOffset; } + + bool GetAbbreviationEntry(uint32 code, + AbbreviationEntry& entry); + +private: + typedef OpenHashTable EntryTable; + +private: + status_t _ParseAbbreviationEntry( + DataReader& abbrevReader, bool& _nullEntry); + +private: + off_t fOffset; + const uint8* fData; + off_t fSize; + EntryTable fEntryTable; +}; + + +#endif // ABBREVIATION_TABLE_H diff --git a/src/apps/debugger/dwarf/attribute_classes.cpp b/src/apps/debugger/dwarf/AttributeClasses.cpp similarity index 99% rename from src/apps/debugger/dwarf/attribute_classes.cpp rename to src/apps/debugger/dwarf/AttributeClasses.cpp index 049c9b5743..438bfdabc8 100644 --- a/src/apps/debugger/dwarf/attribute_classes.cpp +++ b/src/apps/debugger/dwarf/AttributeClasses.cpp @@ -3,8 +3,8 @@ * Distributed under the terms of the MIT License. */ -#include "attribute_classes.h" -#include "dwarf.h" +#include "AttributeClasses.h" +#include "Dwarf.h" enum { diff --git a/src/apps/debugger/dwarf/attribute_classes.h b/src/apps/debugger/dwarf/AttributeClasses.h similarity index 100% rename from src/apps/debugger/dwarf/attribute_classes.h rename to src/apps/debugger/dwarf/AttributeClasses.h diff --git a/src/apps/debugger/dwarf/AttributeValue.cpp b/src/apps/debugger/dwarf/AttributeValue.cpp index 7c22108efd..36e24f4c78 100644 --- a/src/apps/debugger/dwarf/AttributeValue.cpp +++ b/src/apps/debugger/dwarf/AttributeValue.cpp @@ -7,7 +7,7 @@ #include -#include "attribute_classes.h" +#include "AttributeClasses.h" const char* diff --git a/src/apps/debugger/dwarf/AttributeValue.h b/src/apps/debugger/dwarf/AttributeValue.h index f7040034fd..ad29ab832d 100644 --- a/src/apps/debugger/dwarf/AttributeValue.h +++ b/src/apps/debugger/dwarf/AttributeValue.h @@ -5,8 +5,8 @@ #ifndef ATTRIBUTE_VALUE_H #define ATTRIBUTE_VALUE_H -#include "attribute_classes.h" -#include "types.h" +#include "AttributeClasses.h" +#include "DwarfTypes.h" class DebugInfoEntry; diff --git a/src/apps/debugger/dwarf/CompilationUnit.cpp b/src/apps/debugger/dwarf/CompilationUnit.cpp new file mode 100644 index 0000000000..cc432665cd --- /dev/null +++ b/src/apps/debugger/dwarf/CompilationUnit.cpp @@ -0,0 +1,82 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "CompilationUnit.h" + + +CompilationUnit::CompilationUnit(dwarf_off_t headerOffset, + dwarf_off_t contentOffset, dwarf_off_t totalSize, + dwarf_off_t abbreviationOffset) + : + fHeaderOffset(headerOffset), + fContentOffset(contentOffset), + fTotalSize(totalSize), + fAbbreviationOffset(abbreviationOffset), + fAbbreviationTable(NULL) +{ +} + + +CompilationUnit::~CompilationUnit() +{ +} + + +void +CompilationUnit::SetAbbreviationTable(AbbreviationTable* abbreviationTable) +{ + fAbbreviationTable = abbreviationTable; +} + + +status_t +CompilationUnit::AddDebugInfoEntry(DebugInfoEntry* entry, dwarf_off_t offset) +{ + if (!fEntries.Add(entry)) + return B_NO_MEMORY; + if (!fEntryOffsets.Add(offset)) { + fEntries.Remove(fEntries.Count() - 1); + return B_NO_MEMORY; + } + + return B_OK; +} + + +int +CompilationUnit::CountEntries() const +{ + return fEntries.Count(); +} + + +void +CompilationUnit::GetEntryAt(int index, DebugInfoEntry*& entry, + dwarf_off_t& offset) const +{ + entry = fEntries[index]; + offset = fEntryOffsets[index]; +} + + +DebugInfoEntry* +CompilationUnit::EntryForOffset(dwarf_off_t offset) const +{ + if (fEntries.IsEmpty()) + return NULL; + + // binary search + int lower = 0; + int upper = fEntries.Count() - 1; + while (lower < upper) { + int mid = (lower + upper + 1) / 2; + if (fEntryOffsets[mid] > offset) + upper = mid - 1; + else + lower = mid; + } + + return fEntryOffsets[lower] == offset ? fEntries[lower] : NULL; +} diff --git a/src/apps/debugger/dwarf/CompilationUnit.h b/src/apps/debugger/dwarf/CompilationUnit.h new file mode 100644 index 0000000000..0d9c568927 --- /dev/null +++ b/src/apps/debugger/dwarf/CompilationUnit.h @@ -0,0 +1,61 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef COMPILATION_UNIT_H +#define COMPILATION_UNIT_H + +#include + +#include "Array.h" +#include "DwarfTypes.h" + + +class AbbreviationTable; +class DebugInfoEntry; + + +class CompilationUnit : public DoublyLinkedListLinkImpl { +public: + CompilationUnit(dwarf_off_t headerOffset, + dwarf_off_t contentOffset, + dwarf_off_t totalSize, + dwarf_off_t abbreviationOffset); + ~CompilationUnit(); + + dwarf_off_t HeaderOffset() const { return fHeaderOffset; } + dwarf_off_t ContentOffset() const { return fContentOffset; } + dwarf_off_t RelativeContentOffset() const + { return fContentOffset - fHeaderOffset; } + dwarf_off_t TotalSize() const { return fTotalSize; } + dwarf_off_t ContentSize() const + { return fTotalSize + - RelativeContentOffset(); } + dwarf_off_t AbbreviationOffset() const + { return fAbbreviationOffset; } + + AbbreviationTable* GetAbbreviationTable() const + { return fAbbreviationTable; } + void SetAbbreviationTable( + AbbreviationTable* abbreviationTable); + + + status_t AddDebugInfoEntry(DebugInfoEntry* entry, + dwarf_off_t offset); + int CountEntries() const; + void GetEntryAt(int index, DebugInfoEntry*& entry, + dwarf_off_t& offset) const; + DebugInfoEntry* EntryForOffset(dwarf_off_t offset) const; + +private: + dwarf_off_t fHeaderOffset; + dwarf_off_t fContentOffset; + dwarf_off_t fTotalSize; + dwarf_off_t fAbbreviationOffset; + AbbreviationTable* fAbbreviationTable; + Array fEntries; + Array fEntryOffsets; +}; + + +#endif // COMPILATION_UNIT_H diff --git a/src/apps/debugger/dwarf/DebugInfoEntries.cpp b/src/apps/debugger/dwarf/DebugInfoEntries.cpp index cc8424ddf1..aa7983755a 100644 --- a/src/apps/debugger/dwarf/DebugInfoEntries.cpp +++ b/src/apps/debugger/dwarf/DebugInfoEntries.cpp @@ -8,7 +8,7 @@ #include #include "AttributeValue.h" -#include "dwarf.h" +#include "Dwarf.h" #include "SourceLanguageInfo.h" diff --git a/src/apps/debugger/dwarf/DebugInfoEntry.cpp b/src/apps/debugger/dwarf/DebugInfoEntry.cpp index c13eba97bb..9e6cff8a73 100644 --- a/src/apps/debugger/dwarf/DebugInfoEntry.cpp +++ b/src/apps/debugger/dwarf/DebugInfoEntry.cpp @@ -8,7 +8,7 @@ #include #include "AttributeValue.h" -#include "dwarf.h" +#include "Dwarf.h" #define DEFINE_DEBUG_INFO_ENTRY_ATTR_SETTER(name) \ diff --git a/src/apps/debugger/dwarf/DebugInfoEntry.h b/src/apps/debugger/dwarf/DebugInfoEntry.h index 962b0136e4..cf0044b4b2 100644 --- a/src/apps/debugger/dwarf/DebugInfoEntry.h +++ b/src/apps/debugger/dwarf/DebugInfoEntry.h @@ -7,7 +7,7 @@ #include -#include "types.h" +#include "DwarfTypes.h" #define DECLARE_DEBUG_INFO_ENTRY_ATTR_SETTER(name) \ diff --git a/src/apps/debugger/dwarf/dwarf.h b/src/apps/debugger/dwarf/Dwarf.h similarity index 100% rename from src/apps/debugger/dwarf/dwarf.h rename to src/apps/debugger/dwarf/Dwarf.h diff --git a/src/apps/debugger/dwarf/DwarfFile.cpp b/src/apps/debugger/dwarf/DwarfFile.cpp new file mode 100644 index 0000000000..da7229b496 --- /dev/null +++ b/src/apps/debugger/dwarf/DwarfFile.cpp @@ -0,0 +1,592 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "DwarfFile.h" + +#include + +#include + +#include "AttributeClasses.h" +#include "AttributeValue.h" +#include "AbbreviationTable.h" +#include "CompilationUnit.h" +#include "DataReader.h" +#include "ElfFile.h" +#include "TagNames.h" + + +DwarfFile::DwarfFile() + : + fName(NULL), + fElfFile(NULL), + fDebugInfoSection(NULL), + fDebugAbbrevSection(NULL), + fDebugStringSection(NULL), + fCurrentCompilationUnit(NULL), + fFinished(false), + fFinishError(B_OK) +{ +} + + +DwarfFile::~DwarfFile() +{ + while (CompilationUnit* unit = fCompilationUnits.RemoveHead()) + delete unit; + + while (AbbreviationTable* table = fAbbreviationTables.RemoveHead()) + delete table; + + if (fElfFile != NULL) { + fElfFile->PutSection(fDebugInfoSection); + fElfFile->PutSection(fDebugAbbrevSection); + fElfFile->PutSection(fDebugStringSection); + delete fElfFile; + } + + free(fName); +} + + +status_t +DwarfFile::Load(const char* fileName) +{ + fName = strdup(fileName); + if (fName == NULL) + return B_NO_MEMORY; + + // load the ELF file + fElfFile = new(std::nothrow) ElfFile; + if (fElfFile == NULL) + return B_NO_MEMORY; + + status_t error = fElfFile->Init(fileName); + if (error != B_OK) + return error; + + // get the interesting sections + fDebugInfoSection = fElfFile->GetSection(".debug_info"); + fDebugAbbrevSection = fElfFile->GetSection(".debug_abbrev"); + fDebugStringSection = fElfFile->GetSection(".debug_str"); + if (fDebugInfoSection == NULL || fDebugAbbrevSection == NULL + || fDebugStringSection == NULL) { + fprintf(stderr, "DwarfManager::File::Load(\"%s\"): no " + ".debug_info, .debug_abbrev, or .debug_str section.\n", + fileName); + return B_ERROR; + } + + // iterate through the debug info section + DataReader dataReader(fDebugInfoSection->Data(), + fDebugInfoSection->Size()); + while (dataReader.HasData()) { + dwarf_off_t unitHeaderOffset = dataReader.Offset(); + uint64 unitLength = dataReader.Read(0); + bool dwarf64 = (unitLength == 0xffffffff); + if (dwarf64) + unitLength = dataReader.Read(0); + + dwarf_off_t unitLengthOffset = dataReader.Offset(); + // the unitLength starts here + + if (unitLengthOffset + unitLength + > (uint64)fDebugInfoSection->Size()) { + printf("\"%s\": Invalid compilation unit length.\n", fileName); + break; + } + + int version = dataReader.Read(0); + off_t abbrevOffset = dwarf64 + ? dataReader.Read(0) + : dataReader.Read(0); + uint8 addressSize = dataReader.Read(0); + + if (dataReader.HasOverflow()) { + printf("\"%s\": Unexpected end of data in compilation unit " + "header.\n", fileName); + break; + } + + printf("DWARF%d compilation unit: version %d, length: %lld, " + "abbrevOffset: %lld, address size: %d\n", dwarf64 ? 64 : 32, + version, unitLength, abbrevOffset, addressSize); + + if (version != 2 && version != 3) { + printf("\"%s\": Unsupported compilation unit version: %d\n", + fileName, version); + break; + } + + if (addressSize != 4) { + printf("\"%s\": Unsupported address size: %d\n", fileName, + addressSize); + break; + } + + dwarf_off_t unitContentOffset = dataReader.Offset(); + + // create a compilation unit object + CompilationUnit* unit = new(std::nothrow) CompilationUnit( + unitHeaderOffset, unitContentOffset, + unitLength + (unitLengthOffset - unitHeaderOffset), + abbrevOffset); + if (unit == NULL) + return B_NO_MEMORY; + + fCompilationUnits.Add(unit); + + // parse the debug info for the unit + fCurrentCompilationUnit = unit; + error = _ParseCompilationUnit(unit); + if (error != B_OK) + return error; + + dataReader.SeekAbsolute(unitLengthOffset + unitLength); + } + + return B_OK; +} + + +status_t +DwarfFile::FinishLoading() +{ + if (fFinished) + return B_OK; + if (fFinishError != B_OK) + return fFinishError; + + for (CompilationUnitList::Iterator it = fCompilationUnits.GetIterator(); + CompilationUnit* unit = it.Next();) { + fCurrentCompilationUnit = unit; + status_t error = _FinishCompilationUnit(unit); + if (error != B_OK) + return fFinishError = error; + } + + fFinished = true; + return B_OK; +} + + +status_t +DwarfFile::_ParseCompilationUnit(CompilationUnit* unit) +{ + AbbreviationTable* abbreviationTable; + status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(), + abbreviationTable); + if (error != B_OK) + return error; + + unit->SetAbbreviationTable(abbreviationTable); + + DataReader dataReader( + (const uint8*)fDebugInfoSection->Data() + unit->ContentOffset(), + unit->ContentSize()); + + DebugInfoEntry* entry; + bool endOfEntryList; + error = _ParseDebugInfoEntry(dataReader, abbreviationTable, entry, + endOfEntryList); + if (error != B_OK) + return error; + + if (dynamic_cast(entry) == NULL) { + fprintf(stderr, "No compilation unit entry in .debug_info " + "section.\n"); + return B_BAD_DATA; + } + +printf("remaining bytes in unit: %lld\n", dataReader.BytesRemaining()); +if (dataReader.HasData()) { +printf(" "); +while (dataReader.HasData()) { +printf("%02x", dataReader.Read(0)); +} +printf("\n"); +} + return B_OK; +} + + +status_t +DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader, + AbbreviationTable* abbreviationTable, DebugInfoEntry*& _entry, + bool& _endOfEntryList, int level) +{ + dwarf_off_t entryOffset = dataReader.Offset() + + fCurrentCompilationUnit->RelativeContentOffset(); + + uint32 code = dataReader.ReadUnsignedLEB128(0); + if (code == 0) { + if (dataReader.HasOverflow()) { + fprintf(stderr, "Unexpected end of .debug_info section.\n"); + return B_BAD_DATA; + } + _entry = NULL; + _endOfEntryList = true; + return B_OK; + } + + // get the corresponding abbreviation entry + AbbreviationEntry abbreviationEntry; + if (!abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry)) { + fprintf(stderr, "No abbreviation entry for code %lu\n", code); + return B_BAD_DATA; + } +printf("%*sentry at %lu: %lu, tag: %s (%lu), children: %d\n", level * 2, "", +entryOffset, abbreviationEntry.Code(), get_entry_tag_name(abbreviationEntry.Tag()), +abbreviationEntry.Tag(), abbreviationEntry.HasChildren()); + + DebugInfoEntry* entry; + status_t error = fDebugInfoFactory.CreateDebugInfoEntry( + abbreviationEntry.Tag(), entry); + if (error != B_OK) + return error; + ObjectDeleter entryDeleter(entry); + + error = fCurrentCompilationUnit->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); + if (error != B_OK) + return error; + + // parse children, if the entry has any + if (abbreviationEntry.HasChildren()) { + while (true) { + DebugInfoEntry* childEntry; + bool endOfEntryList; + status_t error = _ParseDebugInfoEntry(dataReader, + abbreviationTable, childEntry, endOfEntryList, level + 1); + if (error != B_OK) + return error; + + // add the child to our entry + if (childEntry != NULL) { + if (entry != NULL) { + error = entry->AddChild(childEntry); + if (error == ENTRY_NOT_HANDLED) { + error = B_OK; +printf("%*s -> child unhandled\n", level * 2, ""); + } + + if (error != B_OK) { + delete childEntry; + return error; + } + } else + delete childEntry; + } + + if (endOfEntryList) + break; + } + } + + entryDeleter.Detach(); + _entry = entry; + _endOfEntryList = false; + return B_OK; +} + + +status_t +DwarfFile::_FinishCompilationUnit(CompilationUnit* unit) +{ +printf("\nfinishing compilation unit %p\n", unit); + AbbreviationTable* abbreviationTable = unit->GetAbbreviationTable(); + + DataReader dataReader( + (const uint8*)fDebugInfoSection->Data() + unit->HeaderOffset(), + unit->TotalSize()); +// DataReader dataReader( +// (const uint8*)fDebugInfoSection->Data() + unit->ContentOffset(), +// unit->ContentSize()); + + DebugInfoEntryInitInfo entryInitInfo; + + int entryCount = unit->CountEntries(); + for (int i = 0; i < entryCount; i++) { + // get the entry + DebugInfoEntry* entry; + dwarf_off_t offset; + unit->GetEntryAt(i, entry, offset); +printf("entry %p at %lu\n", entry, offset); + + // seek the reader to the entry + dataReader.SeekAbsolute(offset); + + // read the entry code + uint32 code = dataReader.ReadUnsignedLEB128(0); + + // get the respective abbreviation entry + AbbreviationEntry abbreviationEntry; + abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry); + + // initialization before setting the attributes + status_t error = entry->InitAfterHierarchy(entryInitInfo); + if (error != B_OK) { + fprintf(stderr, "Init after hierarchy failed!\n"); + return error; + } + + // parse the attributes -- this time pass the entry, so that the + // attribute get set on it + error = _ParseEntryAttributes(dataReader, entry, abbreviationEntry); + if (error != B_OK) + return error; + + // initialization after setting the attributes + error = entry->InitAfterAttributes(entryInitInfo); + if (error != B_OK) { + fprintf(stderr, "Init after attributes failed!\n"); + return error; + } + } + + return B_OK; +} + + +status_t +DwarfFile::_ParseEntryAttributes(DataReader& dataReader, + DebugInfoEntry* entry, AbbreviationEntry& abbreviationEntry) +{ + uint32 attributeName; + uint32 attributeForm; + while (abbreviationEntry.GetNextAttribute(attributeName, + attributeForm)) { + // resolve attribute form indirection + if (attributeForm == DW_FORM_indirect) + attributeForm = dataReader.ReadUnsignedLEB128(0); + + // prepare an AttributeValue + AttributeValue attributeValue; + attributeValue.attributeForm = attributeForm; + attributeValue.isSigned = false; + + // Read the attribute value according to the attribute's form. For + // the forms that don't map to a single attribute class only or + // those that need additional processing, we read a temporary value + // first. + uint64 value = 0; + dwarf_size_t blockLength = 0; + bool localReference = true; + + switch (attributeForm) { + case DW_FORM_addr: + value = dataReader.Read(0); + break; + case DW_FORM_block2: + blockLength = dataReader.Read(0); + break; + case DW_FORM_block4: + blockLength = dataReader.Read(0); + break; + case DW_FORM_data2: + value = dataReader.Read(0); + break; + case DW_FORM_data4: + value = dataReader.Read(0); + break; + case DW_FORM_data8: + value = dataReader.Read(0); + break; + case DW_FORM_string: + attributeValue.string = dataReader.ReadString(); + break; + case DW_FORM_block: + blockLength = dataReader.ReadUnsignedLEB128(0); + break; + case DW_FORM_block1: + blockLength = dataReader.Read(0); + break; + case DW_FORM_data1: + value = dataReader.Read(0); + break; + case DW_FORM_flag: + attributeValue.flag = dataReader.Read(0) != 0; + break; + case DW_FORM_sdata: + value = dataReader.ReadSignedLEB128(0); + attributeValue.isSigned = true; + break; + case DW_FORM_strp: + { + dwarf_off_t offset = dataReader.Read(0); + if (offset >= fDebugStringSection->Size()) { + fprintf(stderr, "Invalid DW_FORM_strp offset: %lu\n", + offset); + return B_BAD_DATA; + } + attributeValue.string + = (const char*)fDebugStringSection->Data() + offset; + break; + } + case DW_FORM_udata: + value = dataReader.ReadUnsignedLEB128(0); + break; + case DW_FORM_ref_addr: + value = dataReader.Read(0); + localReference = false; + break; + case DW_FORM_ref1: + value = dataReader.Read(0); + break; + case DW_FORM_ref2: + value = dataReader.Read(0); + break; + case DW_FORM_ref4: + value = dataReader.Read(0); + break; + case DW_FORM_ref8: + value = dataReader.Read(0); + break; + case DW_FORM_ref_udata: + value = dataReader.ReadUnsignedLEB128(0); + break; + case DW_FORM_indirect: + default: + fprintf(stderr, "Unsupported attribute form: %lu\n", + attributeForm); + return B_BAD_DATA; + } + + // get the attribute class -- skip the attribute, if we can't handle + // it + uint8 attributeClass = get_attribute_class(attributeName, + attributeForm); + if (attributeClass == ATTRIBUTE_CLASS_UNKNOWN) { + printf("skipping attribute with unrecognized class: %s (%#lx) " + "%s (%#lx)\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) { + case ATTRIBUTE_CLASS_ADDRESS: + attributeValue.address = value; + break; + case ATTRIBUTE_CLASS_BLOCK: + attributeValue.block.data = dataReader.Data(); + attributeValue.block.length = blockLength; + dataReader.Skip(blockLength); + break; + case ATTRIBUTE_CLASS_CONSTANT: + attributeValue.constant = value; + break; + case ATTRIBUTE_CLASS_LINEPTR: + case ATTRIBUTE_CLASS_LOCLISTPTR: + case ATTRIBUTE_CLASS_MACPTR: + case ATTRIBUTE_CLASS_RANGELISTPTR: + attributeValue.pointer = value; + break; + case ATTRIBUTE_CLASS_REFERENCE: + if (entry != NULL) { + attributeValue.reference = _ResolveReference(value, + localReference); + if (attributeValue.reference == NULL) { + fprintf(stderr, "Failed to resolve reference: " + "%s (%#lx) %s (%#lx): value: %llu\n", + get_attribute_name_name(attributeName), + attributeName, + get_attribute_form_name(attributeForm), + attributeForm, value); + return B_ENTRY_NOT_FOUND; + } + } + break; + case ATTRIBUTE_CLASS_FLAG: + case ATTRIBUTE_CLASS_STRING: + // already set + break; + } + + if (dataReader.HasOverflow()) { + fprintf(stderr, "Unexpected end of .debug_info section.\n"); + return B_BAD_DATA; + } + + // add the attribute + if (entry != NULL) { +char buffer[1024]; +printf(" 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 != NULL) { + status_t error = (entry->*attributeSetter)(attributeName, + attributeValue); + + if (error == ATTRIBUTE_NOT_HANDLED) { + error = B_OK; +printf(" -> unhandled\n"); + } + + if (error != B_OK) { + fprintf(stderr, "Failed to set attribute: name: %s, " + "form: %s: %s\n", + get_attribute_name_name(attributeName), + get_attribute_form_name(attributeForm), + strerror(error)); + } + } +else +printf(" -> no attribute setter!\n"); + } + } + + return B_OK; +} + + +status_t +DwarfFile::_GetAbbreviationTable(off_t offset, AbbreviationTable*& _table) +{ + // check, whether we've already loaded it + for (AbbreviationTableList::Iterator it + = fAbbreviationTables.GetIterator(); + AbbreviationTable* table = it.Next();) { + if (offset == table->Offset()) { + _table = table; + return B_OK; + } + } + + // create a new table + AbbreviationTable* table = new(std::nothrow) AbbreviationTable(offset); + if (table == NULL) + return B_NO_MEMORY; + + status_t error = table->Init(fDebugAbbrevSection->Data(), + fDebugAbbrevSection->Size()); + if (error != B_OK) { + delete table; + return error; + } + + fAbbreviationTables.Add(table); + _table = table; + return B_OK; +} + + +DebugInfoEntry* +DwarfFile::_ResolveReference(uint64 offset, bool localReference) const +{ + if (localReference) + return fCurrentCompilationUnit->EntryForOffset(offset); + + // TODO: Implement program-global references! + return NULL; +} diff --git a/src/apps/debugger/dwarf/DwarfFile.h b/src/apps/debugger/dwarf/DwarfFile.h new file mode 100644 index 0000000000..161bce3eec --- /dev/null +++ b/src/apps/debugger/dwarf/DwarfFile.h @@ -0,0 +1,67 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef DWARF_FILE_H +#define DWARF_FILE_H + +#include + +#include "DebugInfoEntries.h" + + +class AbbreviationEntry; +class AbbreviationTable; +class CompilationUnit; +class DataReader; +class ElfFile; +class ElfSection; + + +class DwarfFile : public DoublyLinkedListLinkImpl { +public: + DwarfFile(); + ~DwarfFile(); + + status_t Load(const char* fileName); + status_t FinishLoading(); + + const char* Name() const { return fName; } + +private: + typedef DoublyLinkedList AbbreviationTableList; + typedef DoublyLinkedList CompilationUnitList; + +private: + status_t _ParseCompilationUnit(CompilationUnit* unit); + status_t _ParseDebugInfoEntry(DataReader& dataReader, + AbbreviationTable* abbreviationTable, + DebugInfoEntry*& _entry, + bool& _endOfEntryList, int level = 0); + status_t _FinishCompilationUnit(CompilationUnit* unit); + status_t _ParseEntryAttributes(DataReader& dataReader, + DebugInfoEntry* entry, + AbbreviationEntry& abbreviationEntry); + + status_t _GetAbbreviationTable(off_t offset, + AbbreviationTable*& _table); + + DebugInfoEntry* _ResolveReference(uint64 offset, + bool localReference) const; + +private: + char* fName; + ElfFile* fElfFile; + ElfSection* fDebugInfoSection; + ElfSection* fDebugAbbrevSection; + ElfSection* fDebugStringSection; + AbbreviationTableList fAbbreviationTables; + DebugInfoEntryFactory fDebugInfoFactory; + CompilationUnitList fCompilationUnits; + CompilationUnit* fCurrentCompilationUnit; + bool fFinished; + status_t fFinishError; +}; + + +#endif // DWARF_FILE_H diff --git a/src/apps/debugger/dwarf/DwarfManager.cpp b/src/apps/debugger/dwarf/DwarfManager.cpp index 7166a6e62c..a6751c7e1d 100644 --- a/src/apps/debugger/dwarf/DwarfManager.cpp +++ b/src/apps/debugger/dwarf/DwarfManager.cpp @@ -5,926 +5,17 @@ #include "DwarfManager.h" -#include #include #include -#include +#include -#include "Array.h" -#include "attribute_classes.h" -#include "AttributeValue.h" -#include "DataReader.h" -#include "DebugInfoEntries.h" -#include "dwarf.h" -#include "ElfFile.h" -#include "tag_names.h" - - -struct AbbreviationTableEntry : HashTableLink { - uint32 code; - off_t offset; - off_t size; - - AbbreviationTableEntry(uint32 code, off_t offset, off_t size) - : - code(code), - offset(offset), - size(size) - { - } -}; - - -struct AbbreviationEntry { - AbbreviationEntry() - { - } - - AbbreviationEntry(uint32 code, const void* data, off_t size) - { - SetTo(code, data, size); - } - - void SetTo(uint32 code, const void* data, off_t size) - { - fCode = code; - fAttributesReader.SetTo(data, size); - fTag = fAttributesReader.ReadUnsignedLEB128(0); - fHasChildren = fAttributesReader.Read(0); - fData = fAttributesReader.Data(); - fSize = fAttributesReader.BytesRemaining(); - } - - uint32 Code() const { return fCode; } - uint32 Tag() const { return fTag; } - bool HasChildren() const { return fHasChildren == DW_CHILDREN_yes; } - - bool GetNextAttribute(uint32& name, uint32& form) - { - name = fAttributesReader.ReadUnsignedLEB128(0); - form = fAttributesReader.ReadUnsignedLEB128(0); - return !fAttributesReader.HasOverflow() && (name != 0 || form != 0); - } - -private: - uint32 fCode; - const void* fData; - off_t fSize; - uint32 fTag; - uint8 fHasChildren; - DataReader fAttributesReader; -}; - - -struct AbbreviationTableHashDefinition { - typedef uint32 KeyType; - typedef AbbreviationTableEntry ValueType; - - size_t HashKey(uint32 key) const - { - return (size_t)key; - } - - size_t Hash(AbbreviationTableEntry* value) const - { - return HashKey(value->code); - } - - bool Compare(uint32 key, AbbreviationTableEntry* value) const - { - return value->code == key; - } - - HashTableLink* GetLink( - AbbreviationTableEntry* value) const - { - return value; - } -}; - -typedef OpenHashTable AbbreviationEntryTable; - - -class AbbreviationTable : public DoublyLinkedListLinkImpl { -public: - AbbreviationTable(off_t offset) - : - fOffset(offset), - fData(NULL), - fSize(0) - { - } - - ~AbbreviationTable() - { - } - - status_t Init(const void* section, off_t sectionSize) - { - if (fOffset < 0 || fOffset >= sectionSize) - return B_BAD_DATA; - - fData = (uint8*)section + fOffset; - fSize = sectionSize - fOffset; - // That's only the maximum size. Will be adjusted at the end. - - status_t error = fEntryTable.Init(); - if (error != B_OK) - return error; - - DataReader abbrevReader(fData, fSize); - - while (true) { - bool nullEntry; - status_t error = _ParseAbbreviationEntry(abbrevReader, nullEntry); - if (error != B_OK) - return error; - - if (nullEntry) - break; - } - - fSize -= abbrevReader.BytesRemaining(); - - return B_OK; - } - - off_t Offset() const - { - return fOffset; - } - - bool GetAbbreviationEntry(uint32 code, AbbreviationEntry& entry) - { - AbbreviationTableEntry* tableEntry = fEntryTable.Lookup(code); - if (tableEntry == NULL) - return false; - - entry.SetTo(code, fData + tableEntry->offset, tableEntry->size); - return true; - } - - status_t _ParseAbbreviationEntry(DataReader& abbrevReader, bool& _nullEntry) - { - uint32 code = abbrevReader.ReadUnsignedLEB128(0); - if (code == 0) { - if (abbrevReader.HasOverflow()) { - fprintf(stderr, "Invalid abbreviation table 1!\n"); - return B_BAD_DATA; - } - _nullEntry = true; - return B_OK; - } - - off_t remaining = abbrevReader.BytesRemaining(); - -/* uint32 tag =*/ abbrevReader.ReadUnsignedLEB128(0); -/* uint8 hasChildren =*/ abbrevReader.Read(DW_CHILDREN_no); - -// printf("entry: %lu, tag: %lu, children: %d\n", code, tag, -// hasChildren); - - // parse attribute specifications - while (true) { - uint32 attributeName = abbrevReader.ReadUnsignedLEB128(0); - uint32 attributeForm = abbrevReader.ReadUnsignedLEB128(0); - if (abbrevReader.HasOverflow()) { - fprintf(stderr, "Invalid abbreviation table 2!\n"); - return B_BAD_DATA; - } - - if (attributeName == 0 && attributeForm == 0) - break; - -// printf(" attr: name: %lu, form: %lu\n", attributeName, -// attributeForm); - } - - // create the entry - if (fEntryTable.Lookup(code) == NULL) { - AbbreviationTableEntry* entry = new(std::nothrow) - AbbreviationTableEntry(code, fSize - remaining, - remaining - abbrevReader.BytesRemaining()); - if (entry == NULL) - return B_NO_MEMORY; - - fEntryTable.Insert(entry); - } else - fprintf(stderr, "Duplicate abbreviation table entry %lu!\n", code); - - _nullEntry = false; - return B_OK; - } - -private: - off_t fOffset; - const uint8* fData; - off_t fSize; - AbbreviationEntryTable fEntryTable; -}; - - -// #pragma mark - CompilationUnit - - -struct DwarfManager::CompilationUnit - : DoublyLinkedListLinkImpl { - CompilationUnit(dwarf_off_t headerOffset, dwarf_off_t contentOffset, - dwarf_off_t totalSize, dwarf_off_t abbreviationOffset) - : - fHeaderOffset(headerOffset), - fContentOffset(contentOffset), - fTotalSize(totalSize), - fAbbreviationOffset(abbreviationOffset), - fAbbreviationTable(NULL) - { - } - - ~CompilationUnit() - { - } - - dwarf_off_t HeaderOffset() const - { - return fHeaderOffset; - } - - dwarf_off_t ContentOffset() const - { - return fContentOffset; - } - - dwarf_off_t RelativeContentOffset() const - { - return fContentOffset - fHeaderOffset; - } - - dwarf_off_t TotalSize() const - { - return fTotalSize; - } - - dwarf_off_t ContentSize() const - { - return fTotalSize - RelativeContentOffset(); - } - - dwarf_off_t AbbreviationOffset() const - { - return fAbbreviationOffset; - } - - void SetAbbreviationTable(AbbreviationTable* abbreviationTable) - { - fAbbreviationTable = abbreviationTable; - } - - AbbreviationTable* GetAbbreviationTable() const - { - return fAbbreviationTable; - } - - status_t AddDebugInfoEntry(DebugInfoEntry* entry, dwarf_off_t offset) - { - if (!fEntries.Add(entry)) - return B_NO_MEMORY; - if (!fEntryOffsets.Add(offset)) { - fEntries.Remove(fEntries.Count() - 1); - return B_NO_MEMORY; - } - - return B_OK; - } - - int CountEntries() const - { - return fEntries.Count(); - } - - void GetEntryAt(int index, DebugInfoEntry*& entry, - dwarf_off_t& offset) const - { - entry = fEntries[index]; - offset = fEntryOffsets[index]; - } - - DebugInfoEntry* EntryForOffset(dwarf_off_t offset) const - { - if (fEntries.IsEmpty()) - return NULL; - - // binary search - int lower = 0; - int upper = fEntries.Count() - 1; - while (lower < upper) { - int mid = (lower + upper + 1) / 2; - if (fEntryOffsets[mid] > offset) - upper = mid - 1; - else - lower = mid; - } - - return fEntryOffsets[lower] == offset ? fEntries[lower] : NULL; - } - -private: - dwarf_off_t fHeaderOffset; - dwarf_off_t fContentOffset; - dwarf_off_t fTotalSize; - dwarf_off_t fAbbreviationOffset; - AbbreviationTable* fAbbreviationTable; - Array fEntries; - Array fEntryOffsets; -}; - - -// #pragma mark - File - - -struct DwarfManager::File : DoublyLinkedListLinkImpl { - File() - : - fName(NULL), - fElfFile(NULL), - fDebugInfoSection(NULL), - fDebugAbbrevSection(NULL), - fDebugStringSection(NULL), - fCurrentCompilationUnit(NULL), - fFinished(false), - fFinishError(B_OK) - { - } - - ~File() - { - while (CompilationUnit* unit = fCompilationUnits.RemoveHead()) - delete unit; - - while (AbbreviationTable* table = fAbbreviationTables.RemoveHead()) - delete table; - - if (fElfFile != NULL) { - fElfFile->PutSection(fDebugInfoSection); - fElfFile->PutSection(fDebugAbbrevSection); - fElfFile->PutSection(fDebugStringSection); - delete fElfFile; - } - - free(fName); - } - - status_t Load(const char* fileName) - { - fName = strdup(fileName); - if (fName == NULL) - return B_NO_MEMORY; - - // load the ELF file - fElfFile = new(std::nothrow) ElfFile; - if (fElfFile == NULL) - return B_NO_MEMORY; - - status_t error = fElfFile->Init(fileName); - if (error != B_OK) - return error; - - // get the interesting sections - fDebugInfoSection = fElfFile->GetSection(".debug_info"); - fDebugAbbrevSection = fElfFile->GetSection(".debug_abbrev"); - fDebugStringSection = fElfFile->GetSection(".debug_str"); - if (fDebugInfoSection == NULL || fDebugAbbrevSection == NULL - || fDebugStringSection == NULL) { - fprintf(stderr, "DwarfManager::File::Load(\"%s\"): no " - ".debug_info, .debug_abbrev, or .debug_str section.\n", - fileName); - return B_ERROR; - } - - // iterate through the debug info section - DataReader dataReader(fDebugInfoSection->Data(), - fDebugInfoSection->Size()); - while (dataReader.HasData()) { - dwarf_off_t unitHeaderOffset = dataReader.Offset(); - uint64 unitLength = dataReader.Read(0); - bool dwarf64 = (unitLength == 0xffffffff); - if (dwarf64) - unitLength = dataReader.Read(0); - - dwarf_off_t unitLengthOffset = dataReader.Offset(); - // the unitLength starts here - - if (unitLengthOffset + unitLength - > (uint64)fDebugInfoSection->Size()) { - printf("\"%s\": Invalid compilation unit length.\n", fileName); - break; - } - - int version = dataReader.Read(0); - off_t abbrevOffset = dwarf64 - ? dataReader.Read(0) - : dataReader.Read(0); - uint8 addressSize = dataReader.Read(0); - - if (dataReader.HasOverflow()) { - printf("\"%s\": Unexpected end of data in compilation unit " - "header.\n", fileName); - break; - } - - printf("DWARF%d compilation unit: version %d, length: %lld, " - "abbrevOffset: %lld, address size: %d\n", dwarf64 ? 64 : 32, - version, unitLength, abbrevOffset, addressSize); - - if (version != 2 && version != 3) { - printf("\"%s\": Unsupported compilation unit version: %d\n", - fileName, version); - break; - } - - if (addressSize != 4) { - printf("\"%s\": Unsupported address size: %d\n", fileName, - addressSize); - break; - } - - dwarf_off_t unitContentOffset = dataReader.Offset(); - - // create a compilation unit object - CompilationUnit* unit = new(std::nothrow) CompilationUnit( - unitHeaderOffset, unitContentOffset, - unitLength + (unitLengthOffset - unitHeaderOffset), - abbrevOffset); - if (unit == NULL) - return B_NO_MEMORY; - - fCompilationUnits.Add(unit); - - // parse the debug info for the unit - fCurrentCompilationUnit = unit; - error = _ParseCompilationUnit(unit); - if (error != B_OK) - return error; - - dataReader.SeekAbsolute(unitLengthOffset + unitLength); - } - - return B_OK; - } - - status_t FinishLoading() - { - if (fFinished) - return B_OK; - if (fFinishError != B_OK) - return fFinishError; - - for (CompilationUnitList::Iterator it = fCompilationUnits.GetIterator(); - CompilationUnit* unit = it.Next();) { - fCurrentCompilationUnit = unit; - status_t error = _FinishCompilationUnit(unit); - if (error != B_OK) - return fFinishError = error; - } - - fFinished = true; - return B_OK; - } - - const char* Name() const - { - return fName; - } - -private: - typedef DoublyLinkedList AbbreviationTableList; - typedef DoublyLinkedList CompilationUnitList; - -private: - status_t _ParseCompilationUnit(CompilationUnit* unit) - { - AbbreviationTable* abbreviationTable; - status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(), - abbreviationTable); - if (error != B_OK) - return error; - - unit->SetAbbreviationTable(abbreviationTable); - - DataReader dataReader( - (const uint8*)fDebugInfoSection->Data() + unit->ContentOffset(), - unit->ContentSize()); - - DebugInfoEntry* entry; - bool endOfEntryList; - error = _ParseDebugInfoEntry(dataReader, abbreviationTable, entry, - endOfEntryList); - if (error != B_OK) - return error; - - if (dynamic_cast(entry) == NULL) { - fprintf(stderr, "No compilation unit entry in .debug_info " - "section.\n"); - return B_BAD_DATA; - } - -printf("remaining bytes in unit: %lld\n", dataReader.BytesRemaining()); -if (dataReader.HasData()) { -printf(" "); -while (dataReader.HasData()) { - printf("%02x", dataReader.Read(0)); -} -printf("\n"); -} - return B_OK; - } - - status_t _ParseDebugInfoEntry(DataReader& dataReader, - AbbreviationTable* abbreviationTable, DebugInfoEntry*& _entry, - bool& _endOfEntryList, int level = 0) - { - dwarf_off_t entryOffset = dataReader.Offset() - + fCurrentCompilationUnit->RelativeContentOffset(); - - uint32 code = dataReader.ReadUnsignedLEB128(0); - if (code == 0) { - if (dataReader.HasOverflow()) { - fprintf(stderr, "Unexpected end of .debug_info section.\n"); - return B_BAD_DATA; - } - _entry = NULL; - _endOfEntryList = true; - return B_OK; - } - - // get the corresponding abbreviation entry - AbbreviationEntry abbreviationEntry; - if (!abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry)) { - fprintf(stderr, "No abbreviation entry for code %lu\n", code); - return B_BAD_DATA; - } -printf("%*sentry at %lu: %lu, tag: %s (%lu), children: %d\n", level * 2, "", -entryOffset, abbreviationEntry.Code(), get_entry_tag_name(abbreviationEntry.Tag()), -abbreviationEntry.Tag(), abbreviationEntry.HasChildren()); - - DebugInfoEntry* entry; - status_t error = fDebugInfoFactory.CreateDebugInfoEntry( - abbreviationEntry.Tag(), entry); - if (error != B_OK) - return error; - ObjectDeleter entryDeleter(entry); - - error = fCurrentCompilationUnit->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); - if (error != B_OK) - return error; - - // parse children, if the entry has any - if (abbreviationEntry.HasChildren()) { - while (true) { - DebugInfoEntry* childEntry; - bool endOfEntryList; - status_t error = _ParseDebugInfoEntry(dataReader, - abbreviationTable, childEntry, endOfEntryList, level + 1); - if (error != B_OK) - return error; - - // add the child to our entry - if (childEntry != NULL) { - if (entry != NULL) { - error = entry->AddChild(childEntry); - if (error == ENTRY_NOT_HANDLED) { - error = B_OK; -printf("%*s -> child unhandled\n", level * 2, ""); - } - - if (error != B_OK) { - delete childEntry; - return error; - } - } else - delete childEntry; - } - - if (endOfEntryList) - break; - } - } - - entryDeleter.Detach(); - _entry = entry; - _endOfEntryList = false; - return B_OK; - } - - status_t _FinishCompilationUnit(CompilationUnit* unit) - { -printf("\nfinishing compilation unit %p\n", unit); - AbbreviationTable* abbreviationTable = unit->GetAbbreviationTable(); - - DataReader dataReader( - (const uint8*)fDebugInfoSection->Data() + unit->HeaderOffset(), - unit->TotalSize()); -// DataReader dataReader( -// (const uint8*)fDebugInfoSection->Data() + unit->ContentOffset(), -// unit->ContentSize()); - - DebugInfoEntryInitInfo entryInitInfo; - - int entryCount = unit->CountEntries(); - for (int i = 0; i < entryCount; i++) { - // get the entry - DebugInfoEntry* entry; - dwarf_off_t offset; - unit->GetEntryAt(i, entry, offset); -printf("entry %p at %lu\n", entry, offset); - - // seek the reader to the entry - dataReader.SeekAbsolute(offset); - - // read the entry code - uint32 code = dataReader.ReadUnsignedLEB128(0); - - // get the respective abbreviation entry - AbbreviationEntry abbreviationEntry; - abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry); - - // initialization before setting the attributes - status_t error = entry->InitAfterHierarchy(entryInitInfo); - if (error != B_OK) { - fprintf(stderr, "Init after hierarchy failed!\n"); - return error; - } - - // parse the attributes -- this time pass the entry, so that the - // attribute get set on it - error = _ParseEntryAttributes(dataReader, entry, abbreviationEntry); - if (error != B_OK) - return error; - - // initialization after setting the attributes - error = entry->InitAfterAttributes(entryInitInfo); - if (error != B_OK) { - fprintf(stderr, "Init after attributes failed!\n"); - return error; - } - } - - return B_OK; - } - - status_t _ParseEntryAttributes(DataReader& dataReader, - DebugInfoEntry* entry, AbbreviationEntry& abbreviationEntry) - { - uint32 attributeName; - uint32 attributeForm; - while (abbreviationEntry.GetNextAttribute(attributeName, - attributeForm)) { - // resolve attribute form indirection - if (attributeForm == DW_FORM_indirect) - attributeForm = dataReader.ReadUnsignedLEB128(0); - - // prepare an AttributeValue - AttributeValue attributeValue; - attributeValue.attributeForm = attributeForm; - attributeValue.isSigned = false; - - // Read the attribute value according to the attribute's form. For - // the forms that don't map to a single attribute class only or - // those that need additional processing, we read a temporary value - // first. - uint64 value = 0; - dwarf_size_t blockLength = 0; - bool localReference = true; - - switch (attributeForm) { - case DW_FORM_addr: - value = dataReader.Read(0); - break; - case DW_FORM_block2: - blockLength = dataReader.Read(0); - break; - case DW_FORM_block4: - blockLength = dataReader.Read(0); - break; - case DW_FORM_data2: - value = dataReader.Read(0); - break; - case DW_FORM_data4: - value = dataReader.Read(0); - break; - case DW_FORM_data8: - value = dataReader.Read(0); - break; - case DW_FORM_string: - attributeValue.string = dataReader.ReadString(); - break; - case DW_FORM_block: - blockLength = dataReader.ReadUnsignedLEB128(0); - break; - case DW_FORM_block1: - blockLength = dataReader.Read(0); - break; - case DW_FORM_data1: - value = dataReader.Read(0); - break; - case DW_FORM_flag: - attributeValue.flag = dataReader.Read(0) != 0; - break; - case DW_FORM_sdata: - value = dataReader.ReadSignedLEB128(0); - attributeValue.isSigned = true; - break; - case DW_FORM_strp: - { - dwarf_off_t offset = dataReader.Read(0); - if (offset >= fDebugStringSection->Size()) { - fprintf(stderr, "Invalid DW_FORM_strp offset: %lu\n", - offset); - return B_BAD_DATA; - } - attributeValue.string - = (const char*)fDebugStringSection->Data() + offset; - break; - } - case DW_FORM_udata: - value = dataReader.ReadUnsignedLEB128(0); - break; - case DW_FORM_ref_addr: - value = dataReader.Read(0); - localReference = false; - break; - case DW_FORM_ref1: - value = dataReader.Read(0); - break; - case DW_FORM_ref2: - value = dataReader.Read(0); - break; - case DW_FORM_ref4: - value = dataReader.Read(0); - break; - case DW_FORM_ref8: - value = dataReader.Read(0); - break; - case DW_FORM_ref_udata: - value = dataReader.ReadUnsignedLEB128(0); - break; - case DW_FORM_indirect: - default: - fprintf(stderr, "Unsupported attribute form: %lu\n", - attributeForm); - return B_BAD_DATA; - } - - // get the attribute class -- skip the attribute, if we can't handle - // it - uint8 attributeClass = get_attribute_class(attributeName, - attributeForm); - if (attributeClass == ATTRIBUTE_CLASS_UNKNOWN) { - printf("skipping attribute with unrecognized class: %s (%#lx) " - "%s (%#lx)\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) { - case ATTRIBUTE_CLASS_ADDRESS: - attributeValue.address = value; - break; - case ATTRIBUTE_CLASS_BLOCK: - attributeValue.block.data = dataReader.Data(); - attributeValue.block.length = blockLength; - dataReader.Skip(blockLength); - break; - case ATTRIBUTE_CLASS_CONSTANT: - attributeValue.constant = value; - break; - case ATTRIBUTE_CLASS_LINEPTR: - case ATTRIBUTE_CLASS_LOCLISTPTR: - case ATTRIBUTE_CLASS_MACPTR: - case ATTRIBUTE_CLASS_RANGELISTPTR: - attributeValue.pointer = value; - break; - case ATTRIBUTE_CLASS_REFERENCE: - if (entry != NULL) { - attributeValue.reference = _ResolveReference(value, - localReference); - if (attributeValue.reference == NULL) { - fprintf(stderr, "Failed to resolve reference: " - "%s (%#lx) %s (%#lx): value: %llu\n", - get_attribute_name_name(attributeName), - attributeName, - get_attribute_form_name(attributeForm), - attributeForm, value); - return B_ENTRY_NOT_FOUND; - } - } - break; - case ATTRIBUTE_CLASS_FLAG: - case ATTRIBUTE_CLASS_STRING: - // already set - break; - } - - if (dataReader.HasOverflow()) { - fprintf(stderr, "Unexpected end of .debug_info section.\n"); - return B_BAD_DATA; - } - - // add the attribute - if (entry != NULL) { -char buffer[1024]; -printf(" 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 != NULL) { - status_t error = (entry->*attributeSetter)(attributeName, - attributeValue); - - if (error == ATTRIBUTE_NOT_HANDLED) { - error = B_OK; -printf(" -> unhandled\n"); - } - - if (error != B_OK) { - fprintf(stderr, "Failed to set attribute: name: %s, " - "form: %s: %s\n", - get_attribute_name_name(attributeName), - get_attribute_form_name(attributeForm), - strerror(error)); - } - } -else -printf(" -> no attribute setter!\n"); - } - } - - return B_OK; - } - - status_t _GetAbbreviationTable(off_t offset, AbbreviationTable*& _table) - { - // check, whether we've already loaded it - for (AbbreviationTableList::Iterator it - = fAbbreviationTables.GetIterator(); - AbbreviationTable* table = it.Next();) { - if (offset == table->Offset()) { - _table = table; - return B_OK; - } - } - - // create a new table - AbbreviationTable* table = new(std::nothrow) AbbreviationTable(offset); - if (table == NULL) - return B_NO_MEMORY; - - status_t error = table->Init(fDebugAbbrevSection->Data(), - fDebugAbbrevSection->Size()); - if (error != B_OK) { - delete table; - return error; - } - - fAbbreviationTables.Add(table); - _table = table; - return B_OK; - } - - DebugInfoEntry* _ResolveReference(uint64 offset, bool localReference) const - { - if (localReference) - return fCurrentCompilationUnit->EntryForOffset(offset); - - // TODO: Implement program-global references! - return NULL; - } - -private: - char* fName; - ElfFile* fElfFile; - ElfSection* fDebugInfoSection; - ElfSection* fDebugAbbrevSection; - ElfSection* fDebugStringSection; - AbbreviationTableList fAbbreviationTables; - DebugInfoEntryFactory fDebugInfoFactory; - CompilationUnitList fCompilationUnits; - CompilationUnit* fCurrentCompilationUnit; - bool fFinished; - status_t fFinishError; -}; +#include "DwarfFile.h" DwarfManager::DwarfManager() + : + fLock("dwarf manager") { } @@ -937,14 +28,16 @@ DwarfManager::~DwarfManager() status_t DwarfManager::Init() { - return B_OK; + return fLock.InitCheck(); } status_t DwarfManager::LoadFile(const char* fileName) { - File* file = new(std::nothrow) File; + AutoLocker locker(this); + + DwarfFile* file = new(std::nothrow) DwarfFile; if (file == NULL) return B_NO_MEMORY; @@ -963,8 +56,10 @@ DwarfManager::LoadFile(const char* fileName) status_t DwarfManager::FinishLoading() { + AutoLocker locker(this); + for (FileList::Iterator it = fFiles.GetIterator(); - File* file = it.Next();) { + DwarfFile* file = it.Next();) { status_t error = file->FinishLoading(); if (error != B_OK) return error; diff --git a/src/apps/debugger/dwarf/DwarfManager.h b/src/apps/debugger/dwarf/DwarfManager.h index ff72b65213..8f38c7f68d 100644 --- a/src/apps/debugger/dwarf/DwarfManager.h +++ b/src/apps/debugger/dwarf/DwarfManager.h @@ -5,13 +5,14 @@ #ifndef DWARF_MANAGER_H #define DWARF_MANAGER_H -#include - -#include +#include #include +class DwarfFile; + + class DwarfManager { public: DwarfManager(); @@ -19,15 +20,17 @@ public: status_t Init(); + bool Lock() { return fLock.Lock(); } + void Unlock() { fLock.Unlock(); } + status_t LoadFile(const char* fileName); status_t FinishLoading(); private: - struct CompilationUnit; - struct File; - typedef DoublyLinkedList FileList; + typedef DoublyLinkedList FileList; private: + BLocker fLock; FileList fFiles; }; diff --git a/src/apps/debugger/dwarf/types.h b/src/apps/debugger/dwarf/DwarfTypes.h similarity index 82% rename from src/apps/debugger/dwarf/types.h rename to src/apps/debugger/dwarf/DwarfTypes.h index f4587b480f..b4c1a05f78 100644 --- a/src/apps/debugger/dwarf/types.h +++ b/src/apps/debugger/dwarf/DwarfTypes.h @@ -2,8 +2,8 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef TYPES_H -#define TYPES_H +#ifndef DWARF_TYPES_H +#define DWARF_TYPES_H #include @@ -19,4 +19,4 @@ typedef uint32 dwarf_size_t; #define DWARF_ADDRESS_MAX 0xffffffff -#endif // TYPES_H +#endif // DWARF_TYPES_H diff --git a/src/apps/debugger/dwarf/Jamfile b/src/apps/debugger/dwarf/Jamfile new file mode 100644 index 0000000000..f90624529b --- /dev/null +++ b/src/apps/debugger/dwarf/Jamfile @@ -0,0 +1,25 @@ +SubDir HAIKU_TOP src apps debugger dwarf ; + +CCFLAGS += -Werror ; +C++FLAGS += -Werror ; + +UsePrivateHeaders kernel shared ; +UsePrivateSystemHeaders ; + +SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ; +SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) elf ] ; + + +MergeObject Debugger_dwarf.o + : + AbbreviationTable.cpp + AttributeClasses.cpp + AttributeValue.cpp + CompilationUnit.cpp + DebugInfoEntries.cpp + DebugInfoEntry.cpp + DwarfFile.cpp + DwarfManager.cpp + SourceLanguageInfo.cpp + TagNames.cpp +; diff --git a/src/apps/debugger/dwarf/SourceLanguageInfo.cpp b/src/apps/debugger/dwarf/SourceLanguageInfo.cpp index 2ed3fcc197..0baa48a876 100644 --- a/src/apps/debugger/dwarf/SourceLanguageInfo.cpp +++ b/src/apps/debugger/dwarf/SourceLanguageInfo.cpp @@ -5,7 +5,7 @@ #include "SourceLanguageInfo.h" -#include "dwarf.h" +#include "Dwarf.h" UnknownSourceLanguageInfo::UnknownSourceLanguageInfo() diff --git a/src/apps/debugger/dwarf/tag_names.cpp b/src/apps/debugger/dwarf/TagNames.cpp similarity index 97% rename from src/apps/debugger/dwarf/tag_names.cpp rename to src/apps/debugger/dwarf/TagNames.cpp index 96bc105448..4a9b4b5ff2 100644 --- a/src/apps/debugger/dwarf/tag_names.cpp +++ b/src/apps/debugger/dwarf/TagNames.cpp @@ -3,9 +3,9 @@ * Distributed under the terms of the MIT License. */ -#include "tag_names.h" +#include "TagNames.h" -#include "dwarf.h" +#include "Dwarf.h" struct tag_name_info { diff --git a/src/apps/debugger/dwarf/tag_names.h b/src/apps/debugger/dwarf/TagNames.h similarity index 70% rename from src/apps/debugger/dwarf/tag_names.h rename to src/apps/debugger/dwarf/TagNames.h index 7b3d6f10ad..d525f2526b 100644 --- a/src/apps/debugger/dwarf/tag_names.h +++ b/src/apps/debugger/dwarf/TagNames.h @@ -2,8 +2,8 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef TAG_NAMES_H -#define TAG_NAMES_H +#ifndef DWARF_TAG_NAMES_H +#define DWARF_TAG_NAMES_H #include @@ -11,4 +11,4 @@ const char* get_entry_tag_name(uint16 tag); -#endif // TAG_NAMES_H +#endif // DWARF_TAG_NAMES_H