1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 02:52:53 +02:00

Sketch out a DWARF parser.

This introduces a new library to LLVM: libDebugInfo. It will provide debug information
parsing to LLVM. Much of the design and some of the code is taken from the LLDB project.

It also contains an llvm-dwarfdump tool that can dump the abbrevs and DIEs from an
object file. It can be used to write tests for DWARF input and output easily.

llvm-svn: 139627
This commit is contained in:
Benjamin Kramer 2011-09-13 19:42:23 +00:00
parent fcc23eeec7
commit c4e7a56915
24 changed files with 2046 additions and 2 deletions

View File

@ -0,0 +1,42 @@
//===-- DIContext.h ---------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines DIContext, and abstract data structure that holds
// debug information data.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_DICONTEXT_H
#define LLVM_DEBUGINFO_DICONTEXT_H
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/DILineInfo.h"
namespace llvm {
class raw_ostream;
class DIContext {
public:
virtual ~DIContext();
/// getDWARFContext - get a context for binary DWARF data.
static DIContext *getDWARFContext(bool isLittleEndian,
StringRef infoSection,
StringRef abbrevSection,
StringRef aRangeSection = StringRef(),
StringRef lineSection = StringRef(),
StringRef stringSection = StringRef());
virtual void dump(raw_ostream &OS) = 0;
};
}
#endif

View File

@ -9,6 +9,7 @@ add_subdirectory(Analysis)
add_subdirectory(MC)
add_subdirectory(CompilerDriver)
add_subdirectory(Object)
add_subdirectory(DebugInfo)
add_subdirectory(ExecutionEngine)
add_subdirectory(Target)
add_subdirectory(AsmParser)

View File

@ -0,0 +1,13 @@
add_llvm_library(LLVMMC
DIContext.cpp
DWARFAbbreviationDeclaration.cpp
DWARFCompileUnit.cpp
DWARFContext.cpp
DWARFDebugAbbrev.cpp
DWARFDebugInfoEntry.cpp
DWARFFormValue.cpp
)
add_llvm_library_dependencies(LLVMDebugInfo
LLVMSupport
)

View File

@ -0,0 +1,24 @@
//===-- DIContext.cpp -----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DIContext.h"
#include "DWARFContext.h"
using namespace llvm;
DIContext::~DIContext() {}
DIContext *DIContext::getDWARFContext(bool isLittleEndian,
StringRef infoSection,
StringRef abbrevSection,
StringRef aRangeSection,
StringRef lineSection,
StringRef stringSection) {
return new DWARFContextInMemory(isLittleEndian, infoSection, abbrevSection,
aRangeSection, lineSection, stringSection);
}

View File

@ -0,0 +1,66 @@
//===-- DWARFAbbreviationDeclaration.cpp ----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DWARFAbbreviationDeclaration.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace dwarf;
bool
DWARFAbbreviationDeclaration::extract(DataExtractor data, uint32_t* offset_ptr){
return extract(data, offset_ptr, data.getULEB128(offset_ptr));
}
bool
DWARFAbbreviationDeclaration::extract(DataExtractor data, uint32_t* offset_ptr,
uint32_t code) {
Code = code;
Attributes.clear();
if (Code) {
Tag = data.getULEB128(offset_ptr);
HasChildren = data.getU8(offset_ptr);
while (data.isValidOffset(*offset_ptr)) {
uint16_t attr = data.getULEB128(offset_ptr);
uint16_t form = data.getULEB128(offset_ptr);
if (attr && form)
Attributes.push_back(DWARFAttribute(attr, form));
else
break;
}
return Tag != 0;
}
else {
Tag = 0;
HasChildren = false;
}
return false;
}
void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const {
OS << '[' << getCode() << "] " << TagString(getTag()) << "\tDW_CHILDREN_"
<< (hasChildren() ? "yes" : "no") << '\n';
for (unsigned i = 0, e = Attributes.size(); i != e; ++i)
OS << '\t' << AttributeString(Attributes[i].getAttribute())
<< '\t' << FormEncodingString(Attributes[i].getForm()) << '\n';
OS << '\n';
}
uint32_t
DWARFAbbreviationDeclaration::findAttributeIndex(uint16_t attr) const {
for (uint32_t i = 0, e = Attributes.size(); i != e; ++i) {
if (Attributes[i].getAttribute() == attr)
return i;
}
return -1U;
}

View File

@ -0,0 +1,54 @@
//===-- DWARFAbbreviationDeclaration.h --------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H
#define LLVM_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H
#include "DWARFAttribute.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/DataExtractor.h"
namespace llvm {
class raw_ostream;
class DWARFAbbreviationDeclaration {
uint32_t Code;
uint32_t Tag;
bool HasChildren;
SmallVector<DWARFAttribute, 8> Attributes;
public:
enum { InvalidCode = 0 };
DWARFAbbreviationDeclaration()
: Code(InvalidCode), Tag(0), HasChildren(0) {}
uint32_t getCode() const { return Code; }
uint32_t getTag() const { return Tag; }
bool hasChildren() const { return HasChildren; }
uint32_t getNumAttributes() const { return Attributes.size(); }
uint16_t getAttrByIndex(uint32_t idx) const {
return Attributes.size() > idx ? Attributes[idx].getAttribute() : 0;
}
uint16_t getFormByIndex(uint32_t idx) const {
return Attributes.size() > idx ? Attributes[idx].getForm() : 0;
}
uint32_t findAttributeIndex(uint16_t attr) const;
bool extract(DataExtractor data, uint32_t* offset_ptr);
bool extract(DataExtractor data, uint32_t* offset_ptr, uint32_t code);
bool isValid() const { return Code != 0 && Tag != 0; }
void dump(raw_ostream &OS) const;
const SmallVectorImpl<DWARFAttribute> &getAttributes() const {
return Attributes;
}
};
}
#endif

View File

@ -0,0 +1,30 @@
//===-- DWARFAttribute.h ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_DWARFATTRIBUTE_H
#define LLVM_DEBUGINFO_DWARFATTRIBUTE_H
#include "llvm/Support/DataTypes.h"
namespace llvm {
class DWARFAttribute {
uint16_t Attribute;
uint16_t Form;
public:
DWARFAttribute(uint16_t attr, uint16_t form)
: Attribute(attr), Form(form) {}
uint16_t getAttribute() const { return Attribute; }
uint16_t getForm() const { return Form; }
};
}
#endif

View File

@ -0,0 +1,203 @@
//===-- DWARFCompileUnit.cpp ----------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DWARFCompileUnit.h"
#include "DWARFContext.h"
#include "DWARFFormValue.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace dwarf;
DataExtractor DWARFCompileUnit::getDebugInfoExtractor() const {
return DataExtractor(Context.getInfoSection(),
Context.isLittleEndian(), getAddressByteSize());
}
bool DWARFCompileUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) {
clear();
Offset = *offset_ptr;
if (debug_info.isValidOffset(*offset_ptr)) {
uint64_t abbrOffset;
const DWARFDebugAbbrev *abbr = Context.getDebugAbbrev();
Length = debug_info.getU32(offset_ptr);
Version = debug_info.getU16(offset_ptr);
abbrOffset = debug_info.getU32(offset_ptr);
AddrSize = debug_info.getU8(offset_ptr);
bool lengthOK = debug_info.isValidOffset(getNextCompileUnitOffset()-1);
bool versionOK = DWARFContext::isSupportedVersion(Version);
bool abbrOffsetOK = Context.getAbbrevSection().size() > abbrOffset;
bool addrSizeOK = AddrSize == 4 || AddrSize == 8;
if (lengthOK && versionOK && addrSizeOK && abbrOffsetOK && abbr != NULL) {
Abbrevs = abbr->getAbbreviationDeclarationSet(abbrOffset);
return true;
}
// reset the offset to where we tried to parse from if anything went wrong
*offset_ptr = Offset;
}
return false;
}
uint32_t
DWARFCompileUnit::extract(uint32_t offset, DataExtractor debug_info_data,
const DWARFAbbreviationDeclarationSet *abbrevs) {
clear();
Offset = offset;
if (debug_info_data.isValidOffset(offset)) {
Length = debug_info_data.getU32(&offset);
Version = debug_info_data.getU16(&offset);
bool abbrevsOK = debug_info_data.getU32(&offset) == abbrevs->getOffset();
Abbrevs = abbrevs;
AddrSize = debug_info_data.getU8 (&offset);
bool versionOK = DWARFContext::isSupportedVersion(Version);
bool addrSizeOK = AddrSize == 4 || AddrSize == 8;
if (versionOK && addrSizeOK && abbrevsOK &&
debug_info_data.isValidOffset(offset))
return offset;
}
return 0;
}
void DWARFCompileUnit::clear() {
Offset = 0;
Length = 0;
Version = 0;
Abbrevs = 0;
AddrSize = 0;
BaseAddr = 0;
DieArray.clear();
}
void DWARFCompileUnit::dump(raw_ostream &OS) {
OS << format("0x%08x", Offset) << ": Compile Unit:"
<< " length = " << format("0x%08x", Length)
<< " version = " << format("0x%04x", Version)
<< " abbr_offset = " << format("0x%04x", Abbrevs->getOffset())
<< " addr_size = " << format("0x%02x", AddrSize)
<< " (next CU at " << format("0x%08x", getNextCompileUnitOffset())
<< ")\n";
extractDIEsIfNeeded(false);
for (unsigned i = 0, e = DieArray.size(); i != e; ++i)
DieArray[i].dump(OS, this, 10);
}
void DWARFCompileUnit::setDIERelations() {
if (DieArray.empty())
return;
DWARFDebugInfoEntryMinimal *die_array_begin = &DieArray.front();
DWARFDebugInfoEntryMinimal *die_array_end = &DieArray.back();
DWARFDebugInfoEntryMinimal *curr_die;
// We purposely are skipping the last element in the array in the loop below
// so that we can always have a valid next item
for (curr_die = die_array_begin; curr_die < die_array_end; ++curr_die) {
// Since our loop doesn't include the last element, we can always
// safely access the next die in the array.
DWARFDebugInfoEntryMinimal *next_die = curr_die + 1;
const DWARFAbbreviationDeclaration *curr_die_abbrev =
curr_die->getAbbreviationDeclarationPtr();
if (curr_die_abbrev) {
// Normal DIE
if (curr_die_abbrev->hasChildren())
next_die->setParent(curr_die);
else
curr_die->setSibling(next_die);
} else {
// NULL DIE that terminates a sibling chain
DWARFDebugInfoEntryMinimal *parent = curr_die->getParent();
if (parent)
parent->setSibling(next_die);
}
}
// Since we skipped the last element, we need to fix it up!
if (die_array_begin < die_array_end)
curr_die->setParent(die_array_begin);
}
size_t DWARFCompileUnit::extractDIEsIfNeeded(bool cu_die_only) {
const size_t initial_die_array_size = DieArray.size();
if ((cu_die_only && initial_die_array_size > 0) ||
initial_die_array_size > 1)
return 0; // Already parsed
// Set the offset to that of the first DIE and calculate the start of the
// next compilation unit header.
uint32_t offset = getFirstDIEOffset();
uint32_t next_cu_offset = getNextCompileUnitOffset();
DWARFDebugInfoEntryMinimal die;
// Keep a flat array of the DIE for binary lookup by DIE offset
uint32_t depth = 0;
// We are in our compile unit, parse starting at the offset
// we were told to parse
const uint8_t *fixed_form_sizes =
DWARFFormValue::getFixedFormSizesForAddressSize(getAddressByteSize());
while (offset < next_cu_offset &&
die.extractFast(this, fixed_form_sizes, &offset)) {
if (depth == 0) {
uint64_t base_addr =
die.getAttributeValueAsUnsigned(this, DW_AT_low_pc, -1U);
if (base_addr == -1U)
base_addr = die.getAttributeValueAsUnsigned(this, DW_AT_entry_pc, 0);
setBaseAddress(base_addr);
}
if (cu_die_only) {
addDIE(die);
return 1;
}
else if (depth == 0 && initial_die_array_size == 1) {
// Don't append the CU die as we already did that
} else {
addDIE (die);
}
const DWARFAbbreviationDeclaration *abbrDecl =
die.getAbbreviationDeclarationPtr();
if (abbrDecl) {
// Normal DIE
if (abbrDecl->hasChildren())
++depth;
} else {
// NULL DIE.
if (depth > 0)
--depth;
if (depth == 0)
break; // We are done with this compile unit!
}
}
// Give a little bit of info if we encounter corrupt DWARF (our offset
// should always terminate at or before the start of the next compilation
// unit header).
if (offset > next_cu_offset) {
fprintf (stderr, "warning: DWARF compile unit extends beyond its bounds cu 0x%8.8x at 0x%8.8x'\n", getOffset(), offset);
}
setDIERelations();
return DieArray.size();
}

View File

@ -0,0 +1,98 @@
//===-- DWARFCompileUnit.h --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H
#define LLVM_DEBUGINFO_DWARFCOMPILEUNIT_H
#include "DWARFDebugAbbrev.h"
#include "DWARFDebugInfoEntry.h"
#include <vector>
namespace llvm {
class DWARFContext;
class raw_ostream;
class DWARFCompileUnit {
DWARFContext &Context;
uint32_t Offset;
uint32_t Length;
uint16_t Version;
const DWARFAbbreviationDeclarationSet *Abbrevs;
uint8_t AddrSize;
uint64_t BaseAddr;
// The compile unit debug information entry item.
std::vector<DWARFDebugInfoEntryMinimal> DieArray;
public:
DWARFCompileUnit(DWARFContext &context) : Context(context) {
clear();
}
DWARFContext &getContext() const { return Context; }
DataExtractor getDebugInfoExtractor() const;
bool extract(DataExtractor debug_info, uint32_t* offset_ptr);
uint32_t extract(uint32_t offset, DataExtractor debug_info_data,
const DWARFAbbreviationDeclarationSet *abbrevs);
/// extractDIEsIfNeeded - Parses a compile unit and indexes its DIEs if it
/// hasn't already been done.
size_t extractDIEsIfNeeded(bool cu_die_only);
void clear();
void dump(raw_ostream &OS);
uint32_t getOffset() const { return Offset; }
/// Size in bytes of the compile unit header.
uint32_t getSize() const { return 11; }
bool containsDIEOffset(uint32_t die_offset) const {
return die_offset >= getFirstDIEOffset() &&
die_offset < getNextCompileUnitOffset();
}
uint32_t getFirstDIEOffset() const { return Offset + getSize(); }
uint32_t getNextCompileUnitOffset() const { return Offset + Length + 4; }
/// Size in bytes of the .debug_info data associated with this compile unit.
size_t getDebugInfoSize() const { return Length + 4 - getSize(); }
uint32_t getLength() const { return Length; }
uint16_t getVersion() const { return Version; }
const DWARFAbbreviationDeclarationSet *getAbbreviations() const {
return Abbrevs;
}
uint8_t getAddressByteSize() const { return AddrSize; }
uint64_t getBaseAddress() const { return BaseAddr; }
void setBaseAddress(uint64_t base_addr) {
BaseAddr = base_addr;
}
/// setDIERelations - We read in all of the DIE entries into our flat list
/// of DIE entries and now we need to go back through all of them and set the
/// parent, sibling and child pointers for quick DIE navigation.
void setDIERelations();
void addDIE(DWARFDebugInfoEntryMinimal &die) {
// The average bytes per DIE entry has been seen to be
// around 14-20 so lets pre-reserve the needed memory for
// our DIE entries accordingly. Search forward for "Compute
// average bytes per DIE" to see #if'ed out code that does
// that determination.
// Only reserve the memory if we are adding children of
// the main compile unit DIE. The compile unit DIE is always
// the first entry, so if our size is 1, then we are adding
// the first compile unit child DIE and should reserve
// the memory.
if (DieArray.empty())
DieArray.reserve(getDebugInfoSize() / 14);
DieArray.push_back(die);
}
};
}
#endif

View File

@ -0,0 +1,43 @@
//===-- DWARFContext.cpp --------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DWARFContext.h"
using namespace llvm;
void DWARFContext::dump(raw_ostream &OS) {
getDebugAbbrev()->dump(OS);
for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i)
getCompileUnitAtIndex(i)->dump(OS);
}
const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() {
if (Abbrev)
return Abbrev.get();
DataExtractor abbrData(getAbbrevSection(), isLittleEndian(), 0);
Abbrev.reset(new DWARFDebugAbbrev());
Abbrev->parse(abbrData);
return Abbrev.get();
}
void DWARFContext::parseCompileUnits() {
uint32_t offset = 0;
const DataExtractor &debug_info_data = DataExtractor(getInfoSection(),
isLittleEndian(), 0);
while (debug_info_data.isValidOffset(offset)) {
CUs.push_back(DWARFCompileUnit(*this));
if (!CUs.back().extract(debug_info_data, &offset)) {
CUs.pop_back();
break;
}
offset = CUs.back().getNextCompileUnitOffset();
}
}

View File

@ -0,0 +1,104 @@
//===-- DWARFContext.h ------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===/
#ifndef LLVM_DEBUGINFO_DWARFCONTEXT_H
#define LLVM_DEBUGINFO_DWARFCONTEXT_H
#include "DWARFCompileUnit.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
namespace llvm {
class DWARFDebugAbbrev;
/// DWARFContext
/// This data structure is the top level entity that deals with dwarf debug
/// information parsing. The actual data is supplied through pure virtual
/// methods that a concrete implementation provides.
class DWARFContext : public DIContext {
bool IsLittleEndian;
SmallVector<DWARFCompileUnit, 1> CUs;
OwningPtr<DWARFDebugAbbrev> Abbrev;
DWARFContext(DWARFContext &); // = delete
DWARFContext &operator=(DWARFContext &); // = delete
/// Read compile units from the debug_info section and store them in CUs.
void parseCompileUnits();
protected:
DWARFContext(bool isLittleEndian) : IsLittleEndian(isLittleEndian) {}
public:
virtual void dump(raw_ostream &OS);
/// Get the number of compile units in this context.
unsigned getNumCompileUnits() {
if (CUs.empty())
parseCompileUnits();
return CUs.size();
}
/// Get the compile unit at the specified index for this compile unit.
DWARFCompileUnit *getCompileUnitAtIndex(unsigned index) {
if (CUs.empty())
parseCompileUnits();
return &CUs[index];
}
/// Get a pointer to the parsed DebugAbbrev object.
const DWARFDebugAbbrev *getDebugAbbrev();
bool isLittleEndian() const { return IsLittleEndian; }
virtual StringRef getInfoSection() = 0;
virtual StringRef getAbbrevSection() = 0;
virtual StringRef getARangeSection() = 0;
virtual StringRef getLineSection() = 0;
virtual StringRef getStringSection() = 0;
static bool isSupportedVersion(unsigned version) {
return version == 2 || version == 3;
}
};
/// DWARFContextInMemory is the simplest possible implementation of a
/// DWARFContext. It assumes all content is available in memory and stores
/// pointers to it.
class DWARFContextInMemory : public DWARFContext {
StringRef InfoSection;
StringRef AbbrevSection;
StringRef ARangeSection;
StringRef LineSection;
StringRef StringSection;
public:
DWARFContextInMemory(bool isLittleEndian,
StringRef infoSection,
StringRef abbrevSection,
StringRef aRangeSection,
StringRef lineSection,
StringRef stringSection)
: DWARFContext(isLittleEndian),
InfoSection(infoSection),
AbbrevSection(abbrevSection),
ARangeSection(aRangeSection),
LineSection(lineSection),
StringSection(stringSection)
{}
virtual StringRef getInfoSection() { return InfoSection; }
virtual StringRef getAbbrevSection() { return AbbrevSection; }
virtual StringRef getARangeSection() { return ARangeSection; }
virtual StringRef getLineSection() { return LineSection; }
virtual StringRef getStringSection() { return StringSection; }
};
}
#endif

View File

@ -0,0 +1,108 @@
//===-- DWARFDebugAbbrev.cpp ----------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DWARFDebugAbbrev.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
bool DWARFAbbreviationDeclarationSet::extract(DataExtractor data,
uint32_t* offset_ptr) {
const uint32_t beginOffset = *offset_ptr;
Offset = beginOffset;
clear();
DWARFAbbreviationDeclaration abbrevDeclaration;
uint32_t prevAbbrAode = 0;
while (abbrevDeclaration.extract(data, offset_ptr)) {
Decls.push_back(abbrevDeclaration);
if (IdxOffset == 0) {
IdxOffset = abbrevDeclaration.getCode();
} else {
if (prevAbbrAode + 1 != abbrevDeclaration.getCode())
IdxOffset = UINT32_MAX;// Out of order indexes, we can't do O(1) lookups
}
prevAbbrAode = abbrevDeclaration.getCode();
}
return beginOffset != *offset_ptr;
}
void DWARFAbbreviationDeclarationSet::dump(raw_ostream &OS) const {
for (unsigned i = 0, e = Decls.size(); i != e; ++i)
Decls[i].dump(OS);
}
const DWARFAbbreviationDeclaration*
DWARFAbbreviationDeclarationSet::getAbbreviationDeclaration(uint32_t abbrCode)
const {
if (IdxOffset == UINT32_MAX) {
DWARFAbbreviationDeclarationCollConstIter pos;
DWARFAbbreviationDeclarationCollConstIter end = Decls.end();
for (pos = Decls.begin(); pos != end; ++pos) {
if (pos->getCode() == abbrCode)
return &(*pos);
}
} else {
uint32_t idx = abbrCode - IdxOffset;
if (idx < Decls.size())
return &Decls[idx];
}
return NULL;
}
DWARFDebugAbbrev::DWARFDebugAbbrev() :
m_abbrevCollMap(),
m_prev_abbr_offset_pos(m_abbrevCollMap.end()) {}
void DWARFDebugAbbrev::parse(DataExtractor data) {
uint32_t offset = 0;
while (data.isValidOffset(offset)) {
uint32_t initial_cu_offset = offset;
DWARFAbbreviationDeclarationSet abbrevDeclSet;
if (abbrevDeclSet.extract(data, &offset))
m_abbrevCollMap[initial_cu_offset] = abbrevDeclSet;
else
break;
}
m_prev_abbr_offset_pos = m_abbrevCollMap.end();
}
void DWARFDebugAbbrev::dump(raw_ostream &OS) const {
if (m_abbrevCollMap.empty()) {
OS << "< EMPTY >\n";
return;
}
DWARFAbbreviationDeclarationCollMapConstIter pos;
for (pos = m_abbrevCollMap.begin(); pos != m_abbrevCollMap.end(); ++pos) {
OS << format("Abbrev table for offset: 0x%8.8x\n", pos->first);
pos->second.dump(OS);
}
}
const DWARFAbbreviationDeclarationSet*
DWARFDebugAbbrev::getAbbreviationDeclarationSet(uint64_t cu_abbr_offset) const {
DWARFAbbreviationDeclarationCollMapConstIter end = m_abbrevCollMap.end();
DWARFAbbreviationDeclarationCollMapConstIter pos;
if (m_prev_abbr_offset_pos != end &&
m_prev_abbr_offset_pos->first == cu_abbr_offset) {
return &(m_prev_abbr_offset_pos->second);
} else {
pos = m_abbrevCollMap.find(cu_abbr_offset);
m_prev_abbr_offset_pos = pos;
}
if (pos != m_abbrevCollMap.end())
return &(pos->second);
return NULL;
}

View File

@ -0,0 +1,71 @@
//===-- DWARFDebugAbbrev.h --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_DWARFDEBUGABBREV_H
#define LLVM_DEBUGINFO_DWARFDEBUGABBREV_H
#include "DWARFAbbreviationDeclaration.h"
#include <list>
#include <map>
#include <vector>
namespace llvm {
typedef std::vector<DWARFAbbreviationDeclaration>
DWARFAbbreviationDeclarationColl;
typedef DWARFAbbreviationDeclarationColl::iterator
DWARFAbbreviationDeclarationCollIter;
typedef DWARFAbbreviationDeclarationColl::const_iterator
DWARFAbbreviationDeclarationCollConstIter;
class DWARFAbbreviationDeclarationSet {
uint64_t Offset;
uint32_t IdxOffset;
std::vector<DWARFAbbreviationDeclaration> Decls;
public:
DWARFAbbreviationDeclarationSet()
: Offset(0), IdxOffset(0) {}
DWARFAbbreviationDeclarationSet(uint64_t offset, uint32_t idxOffset)
: Offset(offset), IdxOffset(idxOffset) {}
void clear() {
IdxOffset = 0;
Decls.clear();
}
uint64_t getOffset() const { return Offset; }
void dump(raw_ostream &OS) const;
bool extract(DataExtractor data, uint32_t* offset_ptr);
const DWARFAbbreviationDeclaration *
getAbbreviationDeclaration(uint32_t abbrCode) const;
};
typedef std::map<uint64_t, DWARFAbbreviationDeclarationSet>
DWARFAbbreviationDeclarationCollMap;
typedef DWARFAbbreviationDeclarationCollMap::iterator
DWARFAbbreviationDeclarationCollMapIter;
typedef DWARFAbbreviationDeclarationCollMap::const_iterator
DWARFAbbreviationDeclarationCollMapConstIter;
class DWARFDebugAbbrev {
public:
DWARFDebugAbbrev();
const DWARFAbbreviationDeclarationSet *
getAbbreviationDeclarationSet(uint64_t cu_abbr_offset) const;
void dump(raw_ostream &OS) const;
void parse(DataExtractor data);
protected:
DWARFAbbreviationDeclarationCollMap m_abbrevCollMap;
mutable DWARFAbbreviationDeclarationCollMapConstIter m_prev_abbr_offset_pos;
};
}
#endif

View File

@ -0,0 +1,410 @@
//===-- DWARFDebugInfoEntry.cpp --------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DWARFDebugInfoEntry.h"
#include "DWARFCompileUnit.h"
#include "DWARFContext.h"
#include "DWARFDebugAbbrev.h"
#include "DWARFFormValue.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace dwarf;
void DWARFDebugInfoEntryMinimal::dump(raw_ostream &OS,
const DWARFCompileUnit *cu,
unsigned recurseDepth,
unsigned indent) const {
DataExtractor debug_info_data = cu->getDebugInfoExtractor();
uint32_t offset = Offset;
if (debug_info_data.isValidOffset(offset)) {
uint64_t abbrCode = debug_info_data.getULEB128(&offset);
OS.indent(indent) << format("\n0x%8.8x: ", Offset);
if (abbrCode) {
if (AbbrevDecl) {
OS << TagString(AbbrevDecl->getTag())
<< format(" [%u] %c\n", abbrCode,
AbbrevDecl->hasChildren() ? '*': ' ');
// Dump all data in the .debug_info for the attributes
const uint32_t numAttributes = AbbrevDecl->getNumAttributes();
for (uint32_t i = 0; i != numAttributes; ++i) {
uint16_t attr = AbbrevDecl->getAttrByIndex(i);
uint16_t form = AbbrevDecl->getFormByIndex(i);
dumpAttribute(OS, cu, &offset, attr, form, indent);
}
const DWARFDebugInfoEntryMinimal *child = getFirstChild();
if (recurseDepth > 0 && child) {
indent += 2;
while (child) {
child->dump(OS, cu, recurseDepth-1, indent);
child = child->getSibling();
}
indent -= 2;
}
} else {
OS << "Abbreviation code not found in 'debug_abbrev' class for code: "
<< abbrCode << '\n';
}
} else {
OS << "NULL\n";
}
}
}
void DWARFDebugInfoEntryMinimal::dumpAttribute(raw_ostream &OS,
const DWARFCompileUnit *cu,
uint32_t* offset_ptr,
uint16_t attr,
uint16_t form,
unsigned indent) const {
OS.indent(indent) << format("0x%8.8x: ", *offset_ptr)
<< AttributeString(attr)
<< " [" << FormEncodingString(form) << ']';
DWARFFormValue formValue(form);
if (!formValue.extractValue(cu->getDebugInfoExtractor(), offset_ptr, cu))
return;
OS << "\t(";
formValue.dump(OS, 0, cu);
OS << ")\n";
}
bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFCompileUnit *cu,
const uint8_t *fixed_form_sizes,
uint32_t *offset_ptr) {
Offset = *offset_ptr;
DataExtractor debug_info_data = cu->getDebugInfoExtractor();
uint64_t abbrCode = debug_info_data.getULEB128(offset_ptr);
assert (fixed_form_sizes); // For best performance this should be specified!
if (abbrCode) {
uint32_t offset = *offset_ptr;
AbbrevDecl = cu->getAbbreviations()->getAbbreviationDeclaration(abbrCode);
// Skip all data in the .debug_info for the attributes
const uint32_t numAttributes = AbbrevDecl->getNumAttributes();
uint32_t i;
uint16_t form;
for (i=0; i<numAttributes; ++i) {
form = AbbrevDecl->getFormByIndex(i);
const uint8_t fixed_skip_size = fixed_form_sizes[form];
if (fixed_skip_size)
offset += fixed_skip_size;
else {
bool form_is_indirect = false;
do {
form_is_indirect = false;
uint32_t form_size = 0;
switch (form) {
// Blocks if inlined data that have a length field and the data bytes
// inlined in the .debug_info.
case DW_FORM_block:
form_size = debug_info_data.getULEB128(&offset);
break;
case DW_FORM_block1:
form_size = debug_info_data.getU8(&offset);
break;
case DW_FORM_block2:
form_size = debug_info_data.getU16(&offset);
break;
case DW_FORM_block4:
form_size = debug_info_data.getU32(&offset);
break;
// Inlined NULL terminated C-strings
case DW_FORM_string:
debug_info_data.getCStr(&offset);
break;
// Compile unit address sized values
case DW_FORM_addr:
case DW_FORM_ref_addr:
form_size = cu->getAddressByteSize();
break;
// 1 byte values
case DW_FORM_data1:
case DW_FORM_flag:
case DW_FORM_ref1:
form_size = 1;
break;
// 2 byte values
case DW_FORM_data2:
case DW_FORM_ref2:
form_size = 2;
break;
// 4 byte values
case DW_FORM_strp:
case DW_FORM_data4:
case DW_FORM_ref4:
form_size = 4;
break;
// 8 byte values
case DW_FORM_data8:
case DW_FORM_ref8:
form_size = 8;
break;
// signed or unsigned LEB 128 values
case DW_FORM_sdata:
case DW_FORM_udata:
case DW_FORM_ref_udata:
debug_info_data.getULEB128(&offset);
break;
case DW_FORM_indirect:
form_is_indirect = true;
form = debug_info_data.getULEB128(&offset);
break;
default:
*offset_ptr = Offset;
return false;
}
offset += form_size;
} while (form_is_indirect);
}
}
*offset_ptr = offset;
return true;
} else {
AbbrevDecl = NULL;
return true; // NULL debug tag entry
}
return false;
}
bool
DWARFDebugInfoEntryMinimal::extract(const DWARFCompileUnit *cu,
uint32_t *offset_ptr) {
DataExtractor debug_info_data = cu->getDebugInfoExtractor();
const uint32_t cu_end_offset = cu->getNextCompileUnitOffset();
const uint8_t cu_addr_size = cu->getAddressByteSize();
uint32_t offset = *offset_ptr;
if ((offset < cu_end_offset) && debug_info_data.isValidOffset(offset)) {
Offset = offset;
uint64_t abbrCode = debug_info_data.getULEB128(&offset);
if (abbrCode) {
AbbrevDecl = cu->getAbbreviations()->getAbbreviationDeclaration(abbrCode);
if (AbbrevDecl) {
uint16_t tag = AbbrevDecl->getTag();
bool isCompileUnitTag = tag == DW_TAG_compile_unit;
if(cu && isCompileUnitTag)
const_cast<DWARFCompileUnit*>(cu)->setBaseAddress(0);
// Skip all data in the .debug_info for the attributes
const uint32_t numAttributes = AbbrevDecl->getNumAttributes();
for (uint32_t i = 0; i != numAttributes; ++i) {
uint16_t attr = AbbrevDecl->getAttrByIndex(i);
uint16_t form = AbbrevDecl->getFormByIndex(i);
if (isCompileUnitTag &&
((attr == DW_AT_entry_pc) || (attr == DW_AT_low_pc))) {
DWARFFormValue form_value(form);
if (form_value.extractValue(debug_info_data, &offset, cu)) {
if (attr == DW_AT_low_pc || attr == DW_AT_entry_pc)
const_cast<DWARFCompileUnit*>(cu)
->setBaseAddress(form_value.getUnsigned());
}
} else {
bool form_is_indirect = false;
do {
form_is_indirect = false;
register uint32_t form_size = 0;
switch (form) {
// Blocks if inlined data that have a length field and the data
// bytes // inlined in the .debug_info
case DW_FORM_block:
form_size = debug_info_data.getULEB128(&offset);
break;
case DW_FORM_block1:
form_size = debug_info_data.getU8(&offset);
break;
case DW_FORM_block2:
form_size = debug_info_data.getU16(&offset);
break;
case DW_FORM_block4:
form_size = debug_info_data.getU32(&offset);
break;
// Inlined NULL terminated C-strings
case DW_FORM_string:
debug_info_data.getCStr(&offset);
break;
// Compile unit address sized values
case DW_FORM_addr:
case DW_FORM_ref_addr:
form_size = cu_addr_size;
break;
// 1 byte values
case DW_FORM_data1:
case DW_FORM_flag:
case DW_FORM_ref1:
form_size = 1;
break;
// 2 byte values
case DW_FORM_data2:
case DW_FORM_ref2:
form_size = 2;
break;
// 4 byte values
case DW_FORM_strp:
form_size = 4;
break;
case DW_FORM_data4:
case DW_FORM_ref4:
form_size = 4;
break;
// 8 byte values
case DW_FORM_data8:
case DW_FORM_ref8:
form_size = 8;
break;
// signed or unsigned LEB 128 values
case DW_FORM_sdata:
case DW_FORM_udata:
case DW_FORM_ref_udata:
debug_info_data.getULEB128(&offset);
break;
case DW_FORM_indirect:
form = debug_info_data.getULEB128(&offset);
form_is_indirect = true;
break;
default:
*offset_ptr = offset;
return false;
}
offset += form_size;
} while (form_is_indirect);
}
}
*offset_ptr = offset;
return true;
}
} else {
AbbrevDecl = NULL;
*offset_ptr = offset;
return true; // NULL debug tag entry
}
}
return false;
}
uint32_t
DWARFDebugInfoEntryMinimal::getAttributeValue(const DWARFCompileUnit *cu,
const uint16_t attr,
DWARFFormValue &form_value,
uint32_t *end_attr_offset_ptr)
const {
if (AbbrevDecl) {
uint32_t attr_idx = AbbrevDecl->findAttributeIndex(attr);
if (attr_idx != -1U) {
uint32_t offset = getOffset();
DataExtractor debug_info_data = cu->getDebugInfoExtractor();
// Skip the abbreviation code so we are at the data for the attributes
debug_info_data.getULEB128(&offset);
uint32_t idx = 0;
while (idx < attr_idx)
DWARFFormValue::skipValue(AbbrevDecl->getFormByIndex(idx++),
debug_info_data, &offset, cu);
const uint32_t attr_offset = offset;
form_value = DWARFFormValue(AbbrevDecl->getFormByIndex(idx));
if (form_value.extractValue(debug_info_data, &offset, cu))
{
if (end_attr_offset_ptr)
*end_attr_offset_ptr = offset;
return attr_offset;
}
}
}
return 0;
}
const char*
DWARFDebugInfoEntryMinimal::getAttributeValueAsString(
const DWARFCompileUnit* cu,
const uint16_t attr,
const char* fail_value) const {
DWARFFormValue form_value;
if (getAttributeValue(cu, attr, form_value)) {
DataExtractor stringExtractor(cu->getContext().getStringSection(),
false, 0);
return form_value.getAsCString(&stringExtractor);
}
return fail_value;
}
uint64_t
DWARFDebugInfoEntryMinimal::getAttributeValueAsUnsigned(
const DWARFCompileUnit* cu,
const uint16_t attr,
uint64_t fail_value) const {
DWARFFormValue form_value;
if (getAttributeValue(cu, attr, form_value))
return form_value.getUnsigned();
return fail_value;
}
int64_t
DWARFDebugInfoEntryMinimal::getAttributeValueAsSigned(
const DWARFCompileUnit* cu,
const uint16_t attr,
int64_t fail_value) const {
DWARFFormValue form_value;
if (getAttributeValue(cu, attr, form_value))
return form_value.getSigned();
return fail_value;
}
uint64_t
DWARFDebugInfoEntryMinimal::getAttributeValueAsReference(const DWARFCompileUnit* cu,
const uint16_t attr,
uint64_t fail_value) const {
DWARFFormValue form_value;
if (getAttributeValue(cu, attr, form_value))
return form_value.getReference(cu);
return fail_value;
}

View File

@ -0,0 +1,131 @@
//===-- DWARFDebugInfoEntry.h -----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_DWARFDEBUGINFOENTRY_H
#define LLVM_DEBUGINFO_DWARFDEBUGINFOENTRY_H
#include "DWARFAbbreviationDeclaration.h"
#include "llvm/Support/DataTypes.h"
namespace llvm {
class DWARFCompileUnit;
class DWARFContext;
class DWARFFormValue;
/// DWARFDebugInfoEntryMinimal - A DIE with only the minimum required data.
class DWARFDebugInfoEntryMinimal {
/// Offset within the .debug_info of the start of this entry.
uint64_t Offset;
/// How many to subtract from "this" to get the parent.
/// If zero this die has no parent.
uint32_t ParentIdx;
/// How many to add to "this" to get the sibling.
uint32_t SiblingIdx;
const DWARFAbbreviationDeclaration *AbbrevDecl;
public:
void dump(raw_ostream &OS, const DWARFCompileUnit *cu,
unsigned recurseDepth, unsigned indent = 0) const;
void dumpAttribute(raw_ostream &OS, const DWARFCompileUnit *cu,
uint32_t *offset_ptr, uint16_t attr, uint16_t form,
unsigned indent = 0) const;
bool extractFast(const DWARFCompileUnit *cu, const uint8_t *fixed_form_sizes,
uint32_t *offset_ptr);
/// Extract a debug info entry for a given compile unit from the
/// .debug_info and .debug_abbrev data starting at the given offset.
bool extract(const DWARFCompileUnit *cu, uint32_t *offset_ptr);
uint32_t getTag() const { return AbbrevDecl ? AbbrevDecl->getTag() : 0; }
bool isNULL() const { return AbbrevDecl == 0; }
uint64_t getOffset() const { return Offset; }
uint32_t getNumAttributes() const {
return !isNULL() ? AbbrevDecl->getNumAttributes() : 0;
}
bool hasChildren() const { return !isNULL() && AbbrevDecl->hasChildren(); }
// We know we are kept in a vector of contiguous entries, so we know
// our parent will be some index behind "this".
DWARFDebugInfoEntryMinimal *getParent() {
return ParentIdx > 0 ? this - ParentIdx : 0;
}
const DWARFDebugInfoEntryMinimal *getParent() const {
return ParentIdx > 0 ? this - ParentIdx : 0;
}
// We know we are kept in a vector of contiguous entries, so we know
// our sibling will be some index after "this".
DWARFDebugInfoEntryMinimal *getSibling() {
return SiblingIdx > 0 ? this + SiblingIdx : 0;
}
const DWARFDebugInfoEntryMinimal *getSibling() const {
return SiblingIdx > 0 ? this + SiblingIdx : 0;
}
// We know we are kept in a vector of contiguous entries, so we know
// we don't need to store our child pointer, if we have a child it will
// be the next entry in the list...
DWARFDebugInfoEntryMinimal *getFirstChild() {
return hasChildren() ? this + 1 : 0;
}
const DWARFDebugInfoEntryMinimal *getFirstChild() const {
return hasChildren() ? this + 1 : 0;
}
void setParent(DWARFDebugInfoEntryMinimal *parent) {
if (parent) {
// We know we are kept in a vector of contiguous entries, so we know
// our parent will be some index behind "this".
ParentIdx = this - parent;
}
else
ParentIdx = 0;
}
void setSibling(DWARFDebugInfoEntryMinimal *sibling) {
if (sibling)
{
// We know we are kept in a vector of contiguous entries, so we know
// our sibling will be some index after "this".
SiblingIdx = sibling - this;
sibling->setParent(getParent());
}
else
SiblingIdx = 0;
}
const DWARFAbbreviationDeclaration *getAbbreviationDeclarationPtr() const {
return AbbrevDecl;
}
uint32_t getAttributeValue(const DWARFCompileUnit *cu,
const uint16_t attr, DWARFFormValue &formValue,
uint32_t *end_attr_offset_ptr = 0) const;
const char* getAttributeValueAsString(const DWARFCompileUnit* cu,
const uint16_t attr,
const char *fail_value) const;
uint64_t getAttributeValueAsUnsigned(const DWARFCompileUnit *cu,
const uint16_t attr,
uint64_t fail_value) const;
uint64_t getAttributeValueAsReference(const DWARFCompileUnit *cu,
const uint16_t attr,
uint64_t fail_value) const;
int64_t getAttributeValueAsSigned(const DWARFCompileUnit* cu,
const uint16_t attr,
int64_t fail_value) const;
};
}
#endif

View File

@ -0,0 +1,434 @@
//===-- DWARFFormValue.cpp ------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DWARFFormValue.h"
#include "DWARFCompileUnit.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
using namespace llvm;
using namespace dwarf;
static const uint8_t form_sizes_addr4[] = {
0, // 0x00 unused
4, // 0x01 DW_FORM_addr
0, // 0x02 unused
0, // 0x03 DW_FORM_block2
0, // 0x04 DW_FORM_block4
2, // 0x05 DW_FORM_data2
4, // 0x06 DW_FORM_data4
8, // 0x07 DW_FORM_data8
0, // 0x08 DW_FORM_string
0, // 0x09 DW_FORM_block
0, // 0x0a DW_FORM_block1
1, // 0x0b DW_FORM_data1
1, // 0x0c DW_FORM_flag
0, // 0x0d DW_FORM_sdata
4, // 0x0e DW_FORM_strp
0, // 0x0f DW_FORM_udata
4, // 0x10 DW_FORM_ref_addr
1, // 0x11 DW_FORM_ref1
2, // 0x12 DW_FORM_ref2
4, // 0x13 DW_FORM_ref4
8, // 0x14 DW_FORM_ref8
0, // 0x15 DW_FORM_ref_udata
0, // 0x16 DW_FORM_indirect
};
static const uint8_t form_sizes_addr8[] = {
0, // 0x00 unused
8, // 0x01 DW_FORM_addr
0, // 0x02 unused
0, // 0x03 DW_FORM_block2
0, // 0x04 DW_FORM_block4
2, // 0x05 DW_FORM_data2
4, // 0x06 DW_FORM_data4
8, // 0x07 DW_FORM_data8
0, // 0x08 DW_FORM_string
0, // 0x09 DW_FORM_block
0, // 0x0a DW_FORM_block1
1, // 0x0b DW_FORM_data1
1, // 0x0c DW_FORM_flag
0, // 0x0d DW_FORM_sdata
4, // 0x0e DW_FORM_strp
0, // 0x0f DW_FORM_udata
8, // 0x10 DW_FORM_ref_addr
1, // 0x11 DW_FORM_ref1
2, // 0x12 DW_FORM_ref2
4, // 0x13 DW_FORM_ref4
8, // 0x14 DW_FORM_ref8
0, // 0x15 DW_FORM_ref_udata
0, // 0x16 DW_FORM_indirect
};
const uint8_t *
DWARFFormValue::getFixedFormSizesForAddressSize(uint8_t addr_size) {
switch (addr_size) {
case 4: return form_sizes_addr4;
case 8: return form_sizes_addr8;
}
return NULL;
}
bool
DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr,
const DWARFCompileUnit* cu) {
bool indirect = false;
bool is_block = false;
Value.data = NULL;
// Read the value for the form into value and follow and DW_FORM_indirect
// instances we run into
do {
indirect = false;
switch (Form) {
case DW_FORM_addr:
case DW_FORM_ref_addr:
Value.uval = data.getUnsigned(offset_ptr, cu->getAddressByteSize());
break;
case DW_FORM_block:
Value.uval = data.getULEB128(offset_ptr);
is_block = true;
break;
case DW_FORM_block1:
Value.uval = data.getU8(offset_ptr);
is_block = true;
break;
case DW_FORM_block2:
Value.uval = data.getU16(offset_ptr);
is_block = true;
break;
case DW_FORM_block4:
Value.uval = data.getU32(offset_ptr);
is_block = true;
break;
case DW_FORM_data1:
case DW_FORM_ref1:
case DW_FORM_flag:
Value.uval = data.getU8(offset_ptr);
break;
case DW_FORM_data2:
case DW_FORM_ref2:
Value.uval = data.getU16(offset_ptr);
break;
case DW_FORM_data4:
case DW_FORM_ref4:
Value.uval = data.getU32(offset_ptr);
break;
case DW_FORM_data8:
case DW_FORM_ref8:
Value.uval = data.getU64(offset_ptr);
break;
case DW_FORM_sdata:
Value.sval = data.getSLEB128(offset_ptr);
break;
case DW_FORM_strp:
Value.uval = data.getU32(offset_ptr);
break;
case DW_FORM_udata:
case DW_FORM_ref_udata:
Value.uval = data.getULEB128(offset_ptr);
break;
case DW_FORM_string:
Value.cstr = data.getCStr(offset_ptr);
// Set the string value to also be the data for inlined cstr form
// values only so we can tell the differnence between DW_FORM_string
// and DW_FORM_strp form values
Value.data = (uint8_t*)Value.cstr;
break;
case DW_FORM_indirect:
Form = data.getULEB128(offset_ptr);
indirect = true;
break;
default:
return false;
}
} while (indirect);
if (is_block) {
StringRef str = data.getData().substr(*offset_ptr, Value.uval);
Value.data = NULL;
if (!str.empty()) {
Value.data = reinterpret_cast<const uint8_t *>(str.data());
*offset_ptr += Value.uval;
}
}
return true;
}
bool
DWARFFormValue::skipValue(DataExtractor debug_info_data, uint32_t* offset_ptr,
const DWARFCompileUnit* cu) const {
return DWARFFormValue::skipValue(Form, debug_info_data, offset_ptr, cu);
}
bool
DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data,
uint32_t *offset_ptr, const DWARFCompileUnit *cu) {
bool indirect = false;
do {
indirect = false;
switch (form) {
// Blocks if inlined data that have a length field and the data bytes
// inlined in the .debug_info
case DW_FORM_block: {
uint64_t size = debug_info_data.getULEB128(offset_ptr);
*offset_ptr += size;
return true;
}
case DW_FORM_block1: {
uint8_t size = debug_info_data.getU8(offset_ptr);
*offset_ptr += size;
return true;
}
case DW_FORM_block2: {
uint16_t size = debug_info_data.getU16(offset_ptr);
*offset_ptr += size;
return true;
}
case DW_FORM_block4: {
uint32_t size = debug_info_data.getU32(offset_ptr);
*offset_ptr += size;
return true;
}
// Inlined NULL terminated C-strings
case DW_FORM_string:
debug_info_data.getCStr(offset_ptr);
return true;
// Compile unit address sized values
case DW_FORM_addr:
case DW_FORM_ref_addr:
*offset_ptr += cu->getAddressByteSize();
return true;
// 1 byte values
case DW_FORM_data1:
case DW_FORM_flag:
case DW_FORM_ref1:
*offset_ptr += 1;
return true;
// 2 byte values
case DW_FORM_data2:
case DW_FORM_ref2:
*offset_ptr += 2;
return true;
// 4 byte values
case DW_FORM_strp:
case DW_FORM_data4:
case DW_FORM_ref4:
*offset_ptr += 4;
return true;
// 8 byte values
case DW_FORM_data8:
case DW_FORM_ref8:
*offset_ptr += 8;
return true;
// signed or unsigned LEB 128 values
// case DW_FORM_APPLE_db_str:
case DW_FORM_sdata:
case DW_FORM_udata:
case DW_FORM_ref_udata:
debug_info_data.getULEB128(offset_ptr);
return true;
case DW_FORM_indirect:
indirect = true;
form = debug_info_data.getULEB128(offset_ptr);
break;
default:
return false;
}
} while (indirect);
return true;
}
void
DWARFFormValue::dump(raw_ostream &OS, const DataExtractor *debug_str_data,
const DWARFCompileUnit *cu) const {
uint64_t uvalue = getUnsigned();
bool cu_relative_offset = false;
switch (Form)
{
case DW_FORM_addr: OS << format("0x%016x", uvalue); break;
case DW_FORM_flag:
case DW_FORM_data1: OS << format("0x%02x", uvalue); break;
case DW_FORM_data2: OS << format("0x%04x", uvalue); break;
case DW_FORM_data4: OS << format("0x%08x", uvalue); break;
case DW_FORM_data8: OS << format("0x%016x", uvalue); break;
case DW_FORM_string:
OS << '"';
OS.write_escaped(getAsCString(NULL));
OS << '"';
break;
case DW_FORM_block:
case DW_FORM_block1:
case DW_FORM_block2:
case DW_FORM_block4:
if (uvalue > 0) {
switch (Form) {
case DW_FORM_block: OS << format("<0x%llx> ", uvalue); break;
case DW_FORM_block1: OS << format("<0x%2.2x> ", (uint8_t)uvalue); break;
case DW_FORM_block2: OS << format("<0x%4.4x> ", (uint16_t)uvalue); break;
case DW_FORM_block4: OS << format("<0x%8.8x> ", (uint32_t)uvalue); break;
default: break;
}
const uint8_t* data_ptr = Value.data;
if (data_ptr) {
// uvalue contains size of block
const uint8_t* end_data_ptr = data_ptr + uvalue;
while (data_ptr < end_data_ptr) {
OS << format("%2.2x ", *data_ptr);
++data_ptr;
}
}
else
OS << "NULL";
}
break;
case DW_FORM_sdata: OS << getSigned(); break;
case DW_FORM_udata: OS << getUnsigned(); break;
case DW_FORM_strp:
if (debug_str_data) {
OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)uvalue);
const char* dbg_str = getAsCString(debug_str_data);
if (dbg_str) {
OS << '"';
OS.write_escaped(dbg_str);
OS << '"';
}
} else {
OS << format("0x%08x", uvalue);
}
break;
case DW_FORM_ref_addr:
OS << format("0x%016x", uvalue);
break;
case DW_FORM_ref1:
cu_relative_offset = true;
OS << format("cu + 0x%2.2x", (uint8_t)uvalue);
break;
case DW_FORM_ref2:
cu_relative_offset = true;
OS << format("cu + 0x%4.4x", (uint16_t)uvalue);
break;
case DW_FORM_ref4:
cu_relative_offset = true;
OS << format("cu + 0x%4.4x", (uint32_t)uvalue);
break;
case DW_FORM_ref8:
cu_relative_offset = true;
OS << format("cu + 0x%8.8llx", uvalue);
break;
case DW_FORM_ref_udata:
cu_relative_offset = true;
OS << format("cu + 0x%llx", uvalue);
break;
// All DW_FORM_indirect attributes should be resolved prior to calling
// this function
case DW_FORM_indirect:
OS << "DW_FORM_indirect";
break;
default:
OS << format("DW_FORM(0x%4.4x)", Form);
break;
}
if (cu_relative_offset)
OS << format(" => {0x%8.8x}", (uvalue + (cu ? cu->getOffset() : 0)));
}
const char*
DWARFFormValue::getAsCString(const DataExtractor *debug_str_data_ptr) const {
if (isInlinedCStr()) {
return Value.cstr;
} else if (debug_str_data_ptr) {
uint32_t offset = Value.uval;
return debug_str_data_ptr->getCStr(&offset);
}
return NULL;
}
uint64_t
DWARFFormValue::getReference(const DWARFCompileUnit *cu) const {
uint64_t die_offset = Value.uval;
switch (Form) {
case DW_FORM_ref1:
case DW_FORM_ref2:
case DW_FORM_ref4:
case DW_FORM_ref8:
case DW_FORM_ref_udata:
die_offset += (cu ? cu->getOffset() : 0);
break;
default:
break;
}
return die_offset;
}
bool
DWARFFormValue::resolveCompileUnitReferences(const DWARFCompileUnit* cu) {
switch (Form) {
case DW_FORM_ref1:
case DW_FORM_ref2:
case DW_FORM_ref4:
case DW_FORM_ref8:
case DW_FORM_ref_udata:
Value.uval += cu->getOffset();
Form = DW_FORM_ref_addr;
return true;
default:
break;
}
return false;
}
const uint8_t *DWARFFormValue::BlockData() const {
if (!isInlinedCStr())
return Value.data;
return NULL;
}
bool DWARFFormValue::isBlockForm(uint16_t form) {
switch (form)
{
case DW_FORM_block:
case DW_FORM_block1:
case DW_FORM_block2:
case DW_FORM_block4:
return true;
}
return false;
}
bool DWARFFormValue::isDataForm(uint16_t form) {
switch (form)
{
case DW_FORM_sdata:
case DW_FORM_udata:
case DW_FORM_data1:
case DW_FORM_data2:
case DW_FORM_data4:
case DW_FORM_data8:
return true;
}
return false;
}

View File

@ -0,0 +1,79 @@
//===-- DWARFFormValue.h ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_DWARFFORMVALUE_H
#define LLVM_DEBUGINFO_DWARFFORMVALUE_H
#include "llvm/Support/DataExtractor.h"
namespace llvm {
class DWARFCompileUnit;
class raw_ostream;
class DWARFFormValue {
public:
struct ValueType {
ValueType() : data(NULL) {
uval = 0;
}
union {
uint64_t uval;
int64_t sval;
const char* cstr;
};
const uint8_t* data;
};
enum {
eValueTypeInvalid = 0,
eValueTypeUnsigned,
eValueTypeSigned,
eValueTypeCStr,
eValueTypeBlock
};
private:
uint16_t Form; // Form for this value.
ValueType Value; // Contains all data for the form.
public:
DWARFFormValue(uint16_t form = 0) : Form(form) {}
uint16_t getForm() const { return Form; }
const ValueType& value() const { return Value; }
void dump(raw_ostream &OS, const DataExtractor *debug_str_data,
const DWARFCompileUnit* cu) const;
bool extractValue(DataExtractor data, uint32_t *offset_ptr,
const DWARFCompileUnit *cu);
bool isInlinedCStr() const {
return Value.data != NULL && Value.data == (uint8_t*)Value.cstr;
}
const uint8_t *BlockData() const;
uint64_t getReference(const DWARFCompileUnit* cu) const;
/// Resolve any compile unit specific references so that we don't need
/// the compile unit at a later time in order to work with the form
/// value.
bool resolveCompileUnitReferences(const DWARFCompileUnit* cu);
uint64_t getUnsigned() const { return Value.uval; }
int64_t getSigned() const { return Value.sval; }
const char *getAsCString(const DataExtractor *debug_str_data_ptr) const;
bool skipValue(DataExtractor debug_info_data, uint32_t *offset_ptr,
const DWARFCompileUnit *cu) const;
static bool skipValue(uint16_t form, DataExtractor debug_info_data,
uint32_t *offset_ptr, const DWARFCompileUnit *cu);
static bool isBlockForm(uint16_t form);
static bool isDataForm(uint16_t form);
static const uint8_t *getFixedFormSizesForAddressSize(uint8_t addr_size);
};
}
#endif

14
lib/DebugInfo/Makefile Normal file
View File

@ -0,0 +1,14 @@
##===- lib/DebugInfo/Makefile ------------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../..
LIBRARYNAME = LLVMDebugInfo
BUILD_ARCHIVE := 1
include $(LEVEL)/Makefile.common

View File

@ -11,7 +11,7 @@ LEVEL = ..
include $(LEVEL)/Makefile.config
PARALLEL_DIRS := VMCore AsmParser Bitcode Archive Analysis Transforms CodeGen \
Target ExecutionEngine Linker MC CompilerDriver Object
Target ExecutionEngine Linker MC CompilerDriver Object DebugInfo
include $(LEVEL)/Makefile.common

View File

@ -39,6 +39,7 @@ add_subdirectory(llvm-diff)
add_subdirectory(macho-dump)
add_subdirectory(llvm-objdump)
add_subdirectory(llvm-rtdyld)
add_subdirectory(llvm-dwarfdump)
add_subdirectory(bugpoint)
add_subdirectory(bugpoint-passes)

View File

@ -26,7 +26,7 @@ PARALLEL_DIRS := opt llvm-as llvm-dis \
lli llvm-extract llvm-mc \
bugpoint llvm-bcanalyzer llvm-stub \
llvmc llvm-diff macho-dump llvm-objdump \
llvm-rtdyld
llvm-rtdyld llvm-dwarfdump
# Let users override the set of tools to build from the command line.
ifdef ONLY_TOOLS

View File

@ -0,0 +1,8 @@
set(LLVM_LINK_COMPONENTS
DebugInfo
Object
)
add_llvm_tool(llvm-dwarfdump
llvm-dwarfdump.cpp
)

View File

@ -0,0 +1,17 @@
##===- tools/llvm-dwarfdump/Makefile -----------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../..
TOOLNAME = llvm-dwarfdump
LINK_COMPONENTS = DebugInfo Object
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
include $(LEVEL)/Makefile.common

View File

@ -0,0 +1,93 @@
//===-- llvm-dwarfdump.cpp - Debug info dumping utility for llvm -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This program is a utility that works like "dwarfdump".
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/MemoryObject.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
#include <algorithm>
#include <cstring>
using namespace llvm;
using namespace object;
static cl::list<std::string>
InputFilenames(cl::Positional, cl::desc("<input object files>"),
cl::ZeroOrMore);
static void DumpInput(const StringRef &Filename) {
OwningPtr<MemoryBuffer> Buff;
if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
errs() << Filename << ": " << ec.message() << "\n";
return;
}
OwningPtr<ObjectFile> Obj(ObjectFile::createObjectFile(Buff.take()));
outs() << '\n';
outs() << Filename
<< ":\tfile format " << Obj->getFileFormatName() << "\n\n";
StringRef DebugInfoSection;
StringRef DebugAbbrevSection;
StringRef DebugLineSection;
error_code ec;
for (ObjectFile::section_iterator i = Obj->begin_sections(),
e = Obj->end_sections();
i != e; i.increment(ec)) {
StringRef name;
i->getName(name);
StringRef data;
i->getContents(data);
if (name.endswith("debug_info"))
DebugInfoSection = data;
else if (name.endswith("debug_abbrev"))
DebugAbbrevSection = data;
else if (name.endswith("debug_line"))
DebugLineSection = data;
}
OwningPtr<DIContext> dictx(DIContext::getDWARFContext(/*FIXME*/true,
DebugInfoSection,
DebugAbbrevSection));
dictx->dump(outs());
}
int main(int argc, char **argv) {
// Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal();
PrettyStackTraceProgram X(argc, argv);
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
cl::ParseCommandLineOptions(argc, argv, "llvm dwarf dumper\n");
// Defaults to a.out if no filenames specified.
if (InputFilenames.size() == 0)
InputFilenames.push_back("a.out");
std::for_each(InputFilenames.begin(), InputFilenames.end(), DumpInput);
return 0;
}