forked from OSchip/llvm-project
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:
parent
88a1d9fc00
commit
aa2f78f5e6
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
)
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
set(LLVM_LINK_COMPONENTS
|
||||
DebugInfo
|
||||
Object
|
||||
)
|
||||
|
||||
add_llvm_tool(llvm-dwarfdump
|
||||
llvm-dwarfdump.cpp
|
||||
)
|
|
@ -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
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue