From 91c6759f30951d992778f67e76836d6a1cf52fe7 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 30 Jun 2009 12:48:46 +0000 Subject: [PATCH] * Added parsing the .debug_line header for each compilation unit and attaching the include directory and source file names to CompilationUnit. * Added DwarfUtils::GetDeclarationLocation() which retrieves the respective source file name and line/column index for a given DIE. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31325 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/debugger/dwarf/CompilationUnit.cpp | 82 ++++++++++++- src/apps/debugger/dwarf/CompilationUnit.h | 18 +++ src/apps/debugger/dwarf/DataReader.h | 9 ++ src/apps/debugger/dwarf/DebugInfoEntries.h | 3 + src/apps/debugger/dwarf/DebugInfoEntry.cpp | 16 +++ src/apps/debugger/dwarf/DebugInfoEntry.h | 3 + src/apps/debugger/dwarf/DwarfFile.cpp | 128 +++++++++++++++++++- src/apps/debugger/dwarf/DwarfFile.h | 5 + src/apps/debugger/dwarf/DwarfUtils.cpp | 55 +++++++++ src/apps/debugger/dwarf/DwarfUtils.h | 7 ++ 10 files changed, 319 insertions(+), 7 deletions(-) diff --git a/src/apps/debugger/dwarf/CompilationUnit.cpp b/src/apps/debugger/dwarf/CompilationUnit.cpp index a7e1ef60ae..810b53280e 100644 --- a/src/apps/debugger/dwarf/CompilationUnit.cpp +++ b/src/apps/debugger/dwarf/CompilationUnit.cpp @@ -5,6 +5,22 @@ #include "CompilationUnit.h" +#include + + +struct CompilationUnit::File { + BString fileName; + const char* dirName; + + + File(const char* fileName, const char* dirName) + : + fileName(fileName), + dirName(dirName) + { + } +}; + CompilationUnit::CompilationUnit(dwarf_off_t headerOffset, dwarf_off_t contentOffset, dwarf_off_t totalSize, @@ -15,7 +31,9 @@ CompilationUnit::CompilationUnit(dwarf_off_t headerOffset, fTotalSize(totalSize), fAbbreviationOffset(abbreviationOffset), fAbbreviationTable(NULL), - fUnitEntry(NULL) + fUnitEntry(NULL), + fDirectories(10, true), + fFiles(10, true) { } @@ -88,3 +106,65 @@ CompilationUnit::EntryForOffset(dwarf_off_t offset) const return fEntryOffsets[lower] == offset ? fEntries[lower] : NULL; } + + +bool +CompilationUnit::AddDirectory(const char* directory) +{ + BString* directoryString = new(std::nothrow) BString(directory); + if (directoryString == NULL || directoryString->Length() == 0 + || !fDirectories.AddItem(directoryString)) { + delete directoryString; + return false; + } + + return true; +} + + +int32 +CompilationUnit::CountDirectories() const +{ + return fDirectories.CountItems(); +} + + +const char* +CompilationUnit::DirectoryAt(int32 index) const +{ + BString* directory = fDirectories.ItemAt(index); + return directory != NULL ? directory->String() : NULL; +} + + +bool +CompilationUnit::AddFile(const char* fileName, int32 dirIndex) +{ + File* file = new(std::nothrow) File(fileName, DirectoryAt(dirIndex)); + if (file == NULL || file->fileName.Length() == 0 || !fFiles.AddItem(file)) { + delete file; + return false; + } + + return true; +} + + +int32 +CompilationUnit::CountFiles() const +{ + return fFiles.CountItems(); +} + + +const char* +CompilationUnit::FileAt(int32 index, const char** _directory) const +{ + if (File* file = fFiles.ItemAt(index)) { + if (_directory != NULL) + *_directory = file->dirName; + return file->fileName.String(); + } + + return NULL; +} diff --git a/src/apps/debugger/dwarf/CompilationUnit.h b/src/apps/debugger/dwarf/CompilationUnit.h index d206507094..8864358a51 100644 --- a/src/apps/debugger/dwarf/CompilationUnit.h +++ b/src/apps/debugger/dwarf/CompilationUnit.h @@ -5,6 +5,8 @@ #ifndef COMPILATION_UNIT_H #define COMPILATION_UNIT_H +#include + #include #include "Array.h" @@ -50,6 +52,20 @@ public: dwarf_off_t& offset) const; DebugInfoEntry* EntryForOffset(dwarf_off_t offset) const; + bool AddDirectory(const char* directory); + int32 CountDirectories() const; + const char* DirectoryAt(int32 index) const; + + bool AddFile(const char* fileName, int32 dirIndex); + int32 CountFiles() const; + const char* FileAt(int32 index, + const char** _directory = NULL) const; + +private: + struct File; + typedef BObjectList DirectoryList; + typedef BObjectList FileList; + private: dwarf_off_t fHeaderOffset; dwarf_off_t fContentOffset; @@ -59,6 +75,8 @@ private: DIECompileUnitBase* fUnitEntry; Array fEntries; Array fEntryOffsets; + DirectoryList fDirectories; + FileList fFiles; }; diff --git a/src/apps/debugger/dwarf/DataReader.h b/src/apps/debugger/dwarf/DataReader.h index 01c3225f05..33852879ef 100644 --- a/src/apps/debugger/dwarf/DataReader.h +++ b/src/apps/debugger/dwarf/DataReader.h @@ -135,6 +135,15 @@ public: return NULL; } + uint64 ReadInitialLength(bool& _dwarf64) + { + uint64 length = Read(0); + _dwarf64 = (length == 0xffffffff); + if (_dwarf64) + length = Read(0); + return length; + } + bool Skip(off_t bytes) { if (bytes < 0) diff --git a/src/apps/debugger/dwarf/DebugInfoEntries.h b/src/apps/debugger/dwarf/DebugInfoEntries.h index 2b71d6cb21..73af051cae 100644 --- a/src/apps/debugger/dwarf/DebugInfoEntries.h +++ b/src/apps/debugger/dwarf/DebugInfoEntries.h @@ -153,6 +153,9 @@ public: dwarf_addr_t HighPC() const { return fHighPC; } dwarf_addr_t AddressRangeBase() const; + dwarf_off_t StatementListOffset() const + { return fStatementListOffset; } + virtual status_t AddChild(DebugInfoEntry* child); virtual status_t AddAttribute_name(uint16 attributeName, diff --git a/src/apps/debugger/dwarf/DebugInfoEntry.cpp b/src/apps/debugger/dwarf/DebugInfoEntry.cpp index 025229ce09..a9d4b18a31 100644 --- a/src/apps/debugger/dwarf/DebugInfoEntry.cpp +++ b/src/apps/debugger/dwarf/DebugInfoEntry.cpp @@ -94,6 +94,22 @@ DebugInfoEntry::AbstractOrigin() const } +bool +DebugInfoEntry::GetDeclarationLocation(uint32& _file, uint32& _line, + uint32& _column) const +{ + DeclarationLocation* location = const_cast(this) + ->GetDeclarationLocation(); + if (location == NULL) + return false; + + _file = location->file; + _line = location->line; + _column = location->column; + return true; +} + + status_t DebugInfoEntry::AddChild(DebugInfoEntry* child) { diff --git a/src/apps/debugger/dwarf/DebugInfoEntry.h b/src/apps/debugger/dwarf/DebugInfoEntry.h index 4e55dd0e36..ba048e4b53 100644 --- a/src/apps/debugger/dwarf/DebugInfoEntry.h +++ b/src/apps/debugger/dwarf/DebugInfoEntry.h @@ -59,6 +59,9 @@ public: virtual DebugInfoEntry* Specification() const; virtual DebugInfoEntry* AbstractOrigin() const; + bool GetDeclarationLocation(uint32& _file, + uint32& _line, uint32& _column) const; + virtual status_t AddChild(DebugInfoEntry* child); virtual status_t AddAttribute_decl_file(uint16 attributeName, diff --git a/src/apps/debugger/dwarf/DwarfFile.cpp b/src/apps/debugger/dwarf/DwarfFile.cpp index 53409ef3f2..183d697e8f 100644 --- a/src/apps/debugger/dwarf/DwarfFile.cpp +++ b/src/apps/debugger/dwarf/DwarfFile.cpp @@ -27,6 +27,7 @@ DwarfFile::DwarfFile() fDebugAbbrevSection(NULL), fDebugStringSection(NULL), fDebugRangesSection(NULL), + fDebugLineSection(NULL), fCompilationUnits(20, true), fCurrentCompilationUnit(NULL), fFinished(false), @@ -45,6 +46,7 @@ DwarfFile::~DwarfFile() fElfFile->PutSection(fDebugAbbrevSection); fElfFile->PutSection(fDebugStringSection); fElfFile->PutSection(fDebugRangesSection); + fElfFile->PutSection(fDebugLineSection); delete fElfFile; } @@ -72,8 +74,6 @@ DwarfFile::Load(const char* fileName) fDebugInfoSection = fElfFile->GetSection(".debug_info"); fDebugAbbrevSection = fElfFile->GetSection(".debug_abbrev"); fDebugStringSection = fElfFile->GetSection(".debug_str"); - fDebugRangesSection = fElfFile->GetSection(".debug_ranges"); - // not mandatory if (fDebugInfoSection == NULL || fDebugAbbrevSection == NULL || fDebugStringSection == NULL) { fprintf(stderr, "DwarfManager::File::Load(\"%s\"): no " @@ -82,15 +82,17 @@ DwarfFile::Load(const char* fileName) return B_ERROR; } + // not mandatory sections + fDebugRangesSection = fElfFile->GetSection(".debug_ranges"); + fDebugLineSection = fElfFile->GetSection(".debug_line"); + // 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); + bool dwarf64; + uint64 unitLength = dataReader.ReadInitialLength(dwarf64); dwarf_off_t unitLengthOffset = dataReader.Offset(); // the unitLength starts here @@ -189,6 +191,30 @@ DwarfFile::CompilationUnitAt(int32 index) const } +CompilationUnit* +DwarfFile::CompilationUnitForDIE(const DebugInfoEntry* entry) const +{ + // find the root of the tree the entry lives in + while (entry != NULL && entry->Parent() != NULL) + entry = entry->Parent(); + + // that should be the compilation unit entry + const DIECompileUnitBase* unitEntry + = dynamic_cast(entry); + if (unitEntry == NULL) + return NULL; + + // find the compilation unit + for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i); + i++) { + if (unit->UnitEntry() == unitEntry) + return unit; + } + + return NULL; +} + + status_t DwarfFile::_ParseCompilationUnit(CompilationUnit* unit) { @@ -372,6 +398,9 @@ printf("entry %p at %lu\n", entry, offset); } } + if (fDebugLineSection != NULL) + _ParseLineInfo(unit); + return B_OK; } @@ -584,6 +613,93 @@ printf(" -> no attribute setter!\n"); } +status_t +DwarfFile::_ParseLineInfo(CompilationUnit* unit) +{ + dwarf_off_t offset = unit->UnitEntry()->StatementListOffset(); +printf("DwarfFile::_ParseLineInfo(%p), offset: %lu\n", unit, offset); + + DataReader dataReader((uint8*)fDebugLineSection->Data() + offset, + fDebugLineSection->Size() - offset); + + // unit length + bool dwarf64; + uint64 unitLength = dataReader.ReadInitialLength(dwarf64); + + // version (uhalf) + uint16 version = dataReader.Read(0); + + // header_length (4/8) + uint64 headerLength = dwarf64 + ? dataReader.Read(0) : (uint64)dataReader.Read(0); + + // minimum instruction length + uint8 minInstructionLength = dataReader.Read(0); + + // default is statement + bool defaultIsStatement = dataReader.Read(0) != 0; + + // line_base (sbyte) + int8 lineBase = (int8)dataReader.Read(0); + + // line_range (ubyte) + uint8 lineRange = dataReader.Read(0); + + // opcode_base (ubyte) + uint8 opcodeBase = dataReader.Read(0); + + // standard_opcode_lengths (ubyte[]) + dataReader.Skip(opcodeBase - 1); + + if (dataReader.HasOverflow()) + return B_BAD_DATA; + + if (version != 2 && version != 3) + return B_UNSUPPORTED; + + printf(" unitLength: %llu\n", unitLength); + printf(" version: %u\n", version); + printf(" headerLength: %llu\n", headerLength); + printf(" minInstructionLength: %u\n", minInstructionLength); + printf(" defaultIsStatement: %d\n", defaultIsStatement); + printf(" lineBase: %d\n", lineBase); + printf(" lineRange: %u\n", lineRange); + printf(" opcodeBase: %u\n", opcodeBase); + + // include directories + printf(" include directories:\n"); + while (const char* directory = dataReader.ReadString()) { + if (*directory == '\0') + break; + printf(" \"%s\"\n", directory); + + if (!unit->AddDirectory(directory)) + return B_NO_MEMORY; + } + + // file names + printf(" files:\n"); + while (const char* file = dataReader.ReadString()) { + if (*file == '\0') + break; + uint64 dirIndex = dataReader.ReadUnsignedLEB128(0); + uint64 modificationTime = dataReader.ReadUnsignedLEB128(0); + uint64 fileLength = dataReader.ReadUnsignedLEB128(0); + + if (dataReader.HasOverflow()) + return B_BAD_DATA; + + printf(" \"%s\", dir index: %llu, mtime: %llu, length: %llu\n", file, + dirIndex, modificationTime, fileLength); + + if (!unit->AddFile(file, dirIndex - 1)) + return B_NO_MEMORY; + } + + return B_OK; +} + + status_t DwarfFile::_GetAbbreviationTable(off_t offset, AbbreviationTable*& _table) { diff --git a/src/apps/debugger/dwarf/DwarfFile.h b/src/apps/debugger/dwarf/DwarfFile.h index 48f1e053de..b177320400 100644 --- a/src/apps/debugger/dwarf/DwarfFile.h +++ b/src/apps/debugger/dwarf/DwarfFile.h @@ -33,6 +33,8 @@ public: int32 CountCompilationUnits() const; CompilationUnit* CompilationUnitAt(int32 index) const; + CompilationUnit* CompilationUnitForDIE( + const DebugInfoEntry* entry) const; private: typedef DoublyLinkedList AbbreviationTableList; @@ -49,6 +51,8 @@ private: DebugInfoEntry* entry, AbbreviationEntry& abbreviationEntry); + status_t _ParseLineInfo(CompilationUnit* unit); + status_t _GetAbbreviationTable(off_t offset, AbbreviationTable*& _table); @@ -64,6 +68,7 @@ private: ElfSection* fDebugAbbrevSection; ElfSection* fDebugStringSection; ElfSection* fDebugRangesSection; + ElfSection* fDebugLineSection; AbbreviationTableList fAbbreviationTables; DebugInfoEntryFactory fDebugInfoFactory; CompilationUnitList fCompilationUnits; diff --git a/src/apps/debugger/dwarf/DwarfUtils.cpp b/src/apps/debugger/dwarf/DwarfUtils.cpp index 5a2e584c77..459d93186b 100644 --- a/src/apps/debugger/dwarf/DwarfUtils.cpp +++ b/src/apps/debugger/dwarf/DwarfUtils.cpp @@ -7,6 +7,9 @@ #include +#include "CompilationUnit.h" +#include "DwarfFile.h" + /*static*/ void DwarfUtils::GetDIEName(const DebugInfoEntry* entry, BString& _name) @@ -77,3 +80,55 @@ DwarfUtils::GetFullyQualifiedDIEName(const DebugInfoEntry* entry, } else _name = name; } + + +/*static*/ bool +DwarfUtils::GetDeclarationLocation(DwarfFile* dwarfFile, + const DebugInfoEntry* entry, const char*& _directory, const char*& _file, + uint32& _line, uint32& _column) +{ + uint32 file; + uint32 line; + uint32 column; + if (!entry->GetDeclarationLocation(file, line, column)) + return false; + + // if no info yet, try the abstract origin (if any) + if (file == 0) { + if (DebugInfoEntry* abstractOrigin = entry->AbstractOrigin()) { + if (abstractOrigin->GetDeclarationLocation(file, line, column) + && file != 0) { + entry = abstractOrigin; + } + } + } + + // if no info yet, try the specification (if any) + if (file == 0) { + if (DebugInfoEntry* specification = entry->Specification()) { + if (specification->GetDeclarationLocation(file, line, column) + && file != 0) { + entry = specification; + } + } + } + + if (file == 0) + return false; + + // get the compilation unit + CompilationUnit* unit = dwarfFile->CompilationUnitForDIE(entry); + if (unit == NULL) + return false; + + const char* directoryName; + const char* fileName = unit->FileAt(file - 1, &directoryName); + if (fileName == NULL) + return false; + + _directory = directoryName; + _file = fileName; + _line = line; + _column = column; + return true; +} diff --git a/src/apps/debugger/dwarf/DwarfUtils.h b/src/apps/debugger/dwarf/DwarfUtils.h index ef198cbf65..9d5e794d27 100644 --- a/src/apps/debugger/dwarf/DwarfUtils.h +++ b/src/apps/debugger/dwarf/DwarfUtils.h @@ -10,6 +10,7 @@ class BString; class DebugInfoEntry; +class DwarfFile; class DwarfUtils { @@ -21,6 +22,12 @@ public: static void GetFullyQualifiedDIEName( const DebugInfoEntry* entry, BString& _name); + + static bool GetDeclarationLocation(DwarfFile* dwarfFile, + const DebugInfoEntry* entry, + const char*& _directory, + const char*& _file, + uint32& _line, uint32& _column); };