* 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
This commit is contained in:
@@ -5,6 +5,22 @@
|
||||
|
||||
#include "CompilationUnit.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#ifndef COMPILATION_UNIT_H
|
||||
#define COMPILATION_UNIT_H
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include <ObjectList.h>
|
||||
|
||||
#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<BString> DirectoryList;
|
||||
typedef BObjectList<File> FileList;
|
||||
|
||||
private:
|
||||
dwarf_off_t fHeaderOffset;
|
||||
dwarf_off_t fContentOffset;
|
||||
@@ -59,6 +75,8 @@ private:
|
||||
DIECompileUnitBase* fUnitEntry;
|
||||
Array<DebugInfoEntry*> fEntries;
|
||||
Array<dwarf_off_t> fEntryOffsets;
|
||||
DirectoryList fDirectories;
|
||||
FileList fFiles;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -135,6 +135,15 @@ public:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint64 ReadInitialLength(bool& _dwarf64)
|
||||
{
|
||||
uint64 length = Read<uint32>(0);
|
||||
_dwarf64 = (length == 0xffffffff);
|
||||
if (_dwarf64)
|
||||
length = Read<uint64>(0);
|
||||
return length;
|
||||
}
|
||||
|
||||
bool Skip(off_t bytes)
|
||||
{
|
||||
if (bytes < 0)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -94,6 +94,22 @@ DebugInfoEntry::AbstractOrigin() const
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DebugInfoEntry::GetDeclarationLocation(uint32& _file, uint32& _line,
|
||||
uint32& _column) const
|
||||
{
|
||||
DeclarationLocation* location = const_cast<DebugInfoEntry*>(this)
|
||||
->GetDeclarationLocation();
|
||||
if (location == NULL)
|
||||
return false;
|
||||
|
||||
_file = location->file;
|
||||
_line = location->line;
|
||||
_column = location->column;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DebugInfoEntry::AddChild(DebugInfoEntry* child)
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<uint32>(0);
|
||||
bool dwarf64 = (unitLength == 0xffffffff);
|
||||
if (dwarf64)
|
||||
unitLength = dataReader.Read<uint64>(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<const DIECompileUnitBase*>(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<uint16>(0);
|
||||
|
||||
// header_length (4/8)
|
||||
uint64 headerLength = dwarf64
|
||||
? dataReader.Read<uint64>(0) : (uint64)dataReader.Read<uint32>(0);
|
||||
|
||||
// minimum instruction length
|
||||
uint8 minInstructionLength = dataReader.Read<uint8>(0);
|
||||
|
||||
// default is statement
|
||||
bool defaultIsStatement = dataReader.Read<uint8>(0) != 0;
|
||||
|
||||
// line_base (sbyte)
|
||||
int8 lineBase = (int8)dataReader.Read<uint8>(0);
|
||||
|
||||
// line_range (ubyte)
|
||||
uint8 lineRange = dataReader.Read<uint8>(0);
|
||||
|
||||
// opcode_base (ubyte)
|
||||
uint8 opcodeBase = dataReader.Read<uint8>(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)
|
||||
{
|
||||
|
||||
@@ -33,6 +33,8 @@ public:
|
||||
|
||||
int32 CountCompilationUnits() const;
|
||||
CompilationUnit* CompilationUnitAt(int32 index) const;
|
||||
CompilationUnit* CompilationUnitForDIE(
|
||||
const DebugInfoEntry* entry) const;
|
||||
|
||||
private:
|
||||
typedef DoublyLinkedList<AbbreviationTable> 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;
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user