* 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:
Ingo Weinhold 2009-06-27 22:12:26 +00:00
parent 671ef9b084
commit 7a7112b32d
22 changed files with 1114 additions and 949 deletions

View File

@ -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 ;

View File

@ -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;
}

View File

@ -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

View File

@ -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 {

View File

@ -7,7 +7,7 @@
#include <stdio.h>
#include "attribute_classes.h"
#include "AttributeClasses.h"
const char*

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -8,7 +8,7 @@
#include <new>
#include "AttributeValue.h"
#include "dwarf.h"
#include "Dwarf.h"
#include "SourceLanguageInfo.h"

View File

@ -8,7 +8,7 @@
#include <new>
#include "AttributeValue.h"
#include "dwarf.h"
#include "Dwarf.h"
#define DEFINE_DEBUG_INFO_ENTRY_ATTR_SETTER(name) \

View File

@ -7,7 +7,7 @@
#include <util/DoublyLinkedList.h>
#include "types.h"
#include "DwarfTypes.h"
#define DECLARE_DEBUG_INFO_ENTRY_ATTR_SETTER(name) \

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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;
};

View File

@ -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

View File

@ -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
;

View File

@ -5,7 +5,7 @@
#include "SourceLanguageInfo.h"
#include "dwarf.h"
#include "Dwarf.h"
UnknownSourceLanguageInfo::UnknownSourceLanguageInfo()

View File

@ -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 {

View File

@ -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