* Renaming and coding moving.
* Added locking to DwarfManager. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31279 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
671ef9b084
commit
7a7112b32d
|
@ -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 :
|
|||
:
|
||||
<nogrist>Debugger_demangler.o
|
||||
<nogrist>Debugger_disasm_x86.o
|
||||
<nogrist>Debugger_dwarf.o
|
||||
<nogrist>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 ;
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "AbbreviationTable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
|
||||
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<uint8>(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;
|
||||
}
|
|
@ -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 <util/DoublyLinkedList.h>
|
||||
#include <util/OpenHashTable.h>
|
||||
|
||||
#include "DataReader.h"
|
||||
#include "Dwarf.h"
|
||||
|
||||
|
||||
struct AbbreviationTableEntry : HashTableLink<AbbreviationTableEntry> {
|
||||
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<uint8>(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<AbbreviationTableEntry>* GetLink(
|
||||
AbbreviationTableEntry* value) const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class AbbreviationTable : public DoublyLinkedListLinkImpl<AbbreviationTable> {
|
||||
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<AbbreviationTableHashDefinition> 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
|
|
@ -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 {
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "attribute_classes.h"
|
||||
#include "AttributeClasses.h"
|
||||
|
||||
|
||||
const char*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 <util/DoublyLinkedList.h>
|
||||
|
||||
#include "Array.h"
|
||||
#include "DwarfTypes.h"
|
||||
|
||||
|
||||
class AbbreviationTable;
|
||||
class DebugInfoEntry;
|
||||
|
||||
|
||||
class CompilationUnit : public DoublyLinkedListLinkImpl<CompilationUnit> {
|
||||
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<DebugInfoEntry*> fEntries;
|
||||
Array<dwarf_off_t> fEntryOffsets;
|
||||
};
|
||||
|
||||
|
||||
#endif // COMPILATION_UNIT_H
|
|
@ -8,7 +8,7 @@
|
|||
#include <new>
|
||||
|
||||
#include "AttributeValue.h"
|
||||
#include "dwarf.h"
|
||||
#include "Dwarf.h"
|
||||
#include "SourceLanguageInfo.h"
|
||||
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <new>
|
||||
|
||||
#include "AttributeValue.h"
|
||||
#include "dwarf.h"
|
||||
#include "Dwarf.h"
|
||||
|
||||
|
||||
#define DEFINE_DEBUG_INFO_ENTRY_ATTR_SETTER(name) \
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "DwarfTypes.h"
|
||||
|
||||
|
||||
#define DECLARE_DEBUG_INFO_ENTRY_ATTR_SETTER(name) \
|
||||
|
|
|
@ -0,0 +1,592 @@
|
|||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "DwarfFile.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
#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<uint32>(0);
|
||||
bool dwarf64 = (unitLength == 0xffffffff);
|
||||
if (dwarf64)
|
||||
unitLength = dataReader.Read<uint64>(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<uint16>(0);
|
||||
off_t abbrevOffset = dwarf64
|
||||
? dataReader.Read<uint64>(0)
|
||||
: dataReader.Read<uint32>(0);
|
||||
uint8 addressSize = dataReader.Read<uint8>(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<DIECompileUnitBase*>(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<uint8>(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<DebugInfoEntry> 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<dwarf_addr_t>(0);
|
||||
break;
|
||||
case DW_FORM_block2:
|
||||
blockLength = dataReader.Read<uint16>(0);
|
||||
break;
|
||||
case DW_FORM_block4:
|
||||
blockLength = dataReader.Read<uint32>(0);
|
||||
break;
|
||||
case DW_FORM_data2:
|
||||
value = dataReader.Read<uint16>(0);
|
||||
break;
|
||||
case DW_FORM_data4:
|
||||
value = dataReader.Read<uint32>(0);
|
||||
break;
|
||||
case DW_FORM_data8:
|
||||
value = dataReader.Read<uint64>(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<uint8>(0);
|
||||
break;
|
||||
case DW_FORM_data1:
|
||||
value = dataReader.Read<uint8>(0);
|
||||
break;
|
||||
case DW_FORM_flag:
|
||||
attributeValue.flag = dataReader.Read<uint8>(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<dwarf_off_t>(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<dwarf_off_t>(0);
|
||||
localReference = false;
|
||||
break;
|
||||
case DW_FORM_ref1:
|
||||
value = dataReader.Read<uint8>(0);
|
||||
break;
|
||||
case DW_FORM_ref2:
|
||||
value = dataReader.Read<uint16>(0);
|
||||
break;
|
||||
case DW_FORM_ref4:
|
||||
value = dataReader.Read<uint32>(0);
|
||||
break;
|
||||
case DW_FORM_ref8:
|
||||
value = dataReader.Read<uint64>(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;
|
||||
}
|
|
@ -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 <util/DoublyLinkedList.h>
|
||||
|
||||
#include "DebugInfoEntries.h"
|
||||
|
||||
|
||||
class AbbreviationEntry;
|
||||
class AbbreviationTable;
|
||||
class CompilationUnit;
|
||||
class DataReader;
|
||||
class ElfFile;
|
||||
class ElfSection;
|
||||
|
||||
|
||||
class DwarfFile : public DoublyLinkedListLinkImpl<DwarfFile> {
|
||||
public:
|
||||
DwarfFile();
|
||||
~DwarfFile();
|
||||
|
||||
status_t Load(const char* fileName);
|
||||
status_t FinishLoading();
|
||||
|
||||
const char* Name() const { return fName; }
|
||||
|
||||
private:
|
||||
typedef DoublyLinkedList<AbbreviationTable> AbbreviationTableList;
|
||||
typedef DoublyLinkedList<CompilationUnit> 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
|
|
@ -5,926 +5,17 @@
|
|||
|
||||
#include "DwarfManager.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <new>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <util/OpenHashTable.h>
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#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<AbbreviationTableEntry> {
|
||||
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<uint8>(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<AbbreviationTableEntry>* GetLink(
|
||||
AbbreviationTableEntry* value) const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
typedef OpenHashTable<AbbreviationTableHashDefinition> AbbreviationEntryTable;
|
||||
|
||||
|
||||
class AbbreviationTable : public DoublyLinkedListLinkImpl<AbbreviationTable> {
|
||||
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<uint8>(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> {
|
||||
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<DebugInfoEntry*> fEntries;
|
||||
Array<dwarf_off_t> fEntryOffsets;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - File
|
||||
|
||||
|
||||
struct DwarfManager::File : DoublyLinkedListLinkImpl<File> {
|
||||
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<uint32>(0);
|
||||
bool dwarf64 = (unitLength == 0xffffffff);
|
||||
if (dwarf64)
|
||||
unitLength = dataReader.Read<uint64>(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<uint16>(0);
|
||||
off_t abbrevOffset = dwarf64
|
||||
? dataReader.Read<uint64>(0)
|
||||
: dataReader.Read<uint32>(0);
|
||||
uint8 addressSize = dataReader.Read<uint8>(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<AbbreviationTable> AbbreviationTableList;
|
||||
typedef DoublyLinkedList<CompilationUnit> 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<DIECompileUnitBase*>(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<uint8>(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<DebugInfoEntry> 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<dwarf_addr_t>(0);
|
||||
break;
|
||||
case DW_FORM_block2:
|
||||
blockLength = dataReader.Read<uint16>(0);
|
||||
break;
|
||||
case DW_FORM_block4:
|
||||
blockLength = dataReader.Read<uint32>(0);
|
||||
break;
|
||||
case DW_FORM_data2:
|
||||
value = dataReader.Read<uint16>(0);
|
||||
break;
|
||||
case DW_FORM_data4:
|
||||
value = dataReader.Read<uint32>(0);
|
||||
break;
|
||||
case DW_FORM_data8:
|
||||
value = dataReader.Read<uint64>(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<uint8>(0);
|
||||
break;
|
||||
case DW_FORM_data1:
|
||||
value = dataReader.Read<uint8>(0);
|
||||
break;
|
||||
case DW_FORM_flag:
|
||||
attributeValue.flag = dataReader.Read<uint8>(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<dwarf_off_t>(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<dwarf_off_t>(0);
|
||||
localReference = false;
|
||||
break;
|
||||
case DW_FORM_ref1:
|
||||
value = dataReader.Read<uint8>(0);
|
||||
break;
|
||||
case DW_FORM_ref2:
|
||||
value = dataReader.Read<uint16>(0);
|
||||
break;
|
||||
case DW_FORM_ref4:
|
||||
value = dataReader.Read<uint32>(0);
|
||||
break;
|
||||
case DW_FORM_ref8:
|
||||
value = dataReader.Read<uint64>(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<DwarfManager> 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<DwarfManager> 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;
|
||||
|
|
|
@ -5,13 +5,14 @@
|
|||
#ifndef DWARF_MANAGER_H
|
||||
#define DWARF_MANAGER_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <SupportDefs.h>
|
||||
#include <Locker.h>
|
||||
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
|
||||
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<File> FileList;
|
||||
typedef DoublyLinkedList<DwarfFile> FileList;
|
||||
|
||||
private:
|
||||
BLocker fLock;
|
||||
FileList fFiles;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 <SupportDefs.h>
|
||||
|
||||
|
@ -19,4 +19,4 @@ typedef uint32 dwarf_size_t;
|
|||
#define DWARF_ADDRESS_MAX 0xffffffff
|
||||
|
||||
|
||||
#endif // TYPES_H
|
||||
#endif // DWARF_TYPES_H
|
|
@ -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
|
||||
;
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "SourceLanguageInfo.h"
|
||||
|
||||
#include "dwarf.h"
|
||||
#include "Dwarf.h"
|
||||
|
||||
|
||||
UnknownSourceLanguageInfo::UnknownSourceLanguageInfo()
|
||||
|
|
|
@ -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 {
|
|
@ -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 <SupportDefs.h>
|
||||
|
||||
|
@ -11,4 +11,4 @@
|
|||
const char* get_entry_tag_name(uint16 tag);
|
||||
|
||||
|
||||
#endif // TAG_NAMES_H
|
||||
#endif // DWARF_TAG_NAMES_H
|
Loading…
Reference in New Issue