mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-13 09:33:50 +00:00
Add support for fetching inlining context (stack of source code locations)
by instruction address from DWARF. Add --inlining flag to llvm-dwarfdump to demonstrate and test this functionality, so that "llvm-dwarfdump --inlining --address=0x..." now works much like "addr2line -i 0x...", provided that the binary has debug info (Clang's -gline-tables-only *is* enough). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@163128 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
2d5c28da0d
commit
5eae90d727
@ -15,6 +15,7 @@
|
||||
#ifndef LLVM_DEBUGINFO_DICONTEXT_H
|
||||
#define LLVM_DEBUGINFO_DICONTEXT_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
@ -54,6 +55,23 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// DIInliningInfo - a format-neutral container for inlined code description.
|
||||
class DIInliningInfo {
|
||||
SmallVector<DILineInfo, 4> Frames;
|
||||
public:
|
||||
DIInliningInfo() {}
|
||||
DILineInfo getFrame(unsigned Index) const {
|
||||
assert(Index < Frames.size());
|
||||
return Frames[Index];
|
||||
}
|
||||
uint32_t getNumberOfFrames() const {
|
||||
return Frames.size();
|
||||
}
|
||||
void addFrame(const DILineInfo &Frame) {
|
||||
Frames.push_back(Frame);
|
||||
}
|
||||
};
|
||||
|
||||
/// DILineInfoSpecifier - controls which fields of DILineInfo container
|
||||
/// should be filled with data.
|
||||
class DILineInfoSpecifier {
|
||||
@ -86,8 +104,10 @@ public:
|
||||
|
||||
virtual void dump(raw_ostream &OS) = 0;
|
||||
|
||||
virtual DILineInfo getLineInfoForAddress(uint64_t address,
|
||||
DILineInfoSpecifier specifier = DILineInfoSpecifier()) = 0;
|
||||
virtual DILineInfo getLineInfoForAddress(uint64_t Address,
|
||||
DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
|
||||
virtual DIInliningInfo getInliningInfoForAddress(uint64_t Address,
|
||||
DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -75,6 +75,15 @@ DWARFCompileUnit::extract(uint32_t offset, DataExtractor debug_info_data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DWARFCompileUnit::extractRangeList(uint32_t RangeListOffset,
|
||||
DWARFDebugRangeList &RangeList) const {
|
||||
// Require that compile unit is extracted.
|
||||
assert(DieArray.size() > 0);
|
||||
DataExtractor RangesData(Context.getRangeSection(),
|
||||
Context.isLittleEndian(), AddrSize);
|
||||
return RangeList.extract(RangesData, &RangeListOffset);
|
||||
}
|
||||
|
||||
void DWARFCompileUnit::clear() {
|
||||
Offset = 0;
|
||||
Length = 0;
|
||||
@ -246,12 +255,21 @@ DWARFCompileUnit::buildAddressRangeTable(DWARFDebugAranges *debug_aranges,
|
||||
clearDIEs(true);
|
||||
}
|
||||
|
||||
const DWARFDebugInfoEntryMinimal*
|
||||
DWARFCompileUnit::getFunctionDIEForAddress(int64_t address) {
|
||||
DWARFDebugInfoEntryMinimal::InlinedChain
|
||||
DWARFCompileUnit::getInlinedChainForAddress(uint64_t Address) {
|
||||
// First, find a subprogram that contains the given address (the root
|
||||
// of inlined chain).
|
||||
extractDIEsIfNeeded(false);
|
||||
const DWARFDebugInfoEntryMinimal *SubprogramDIE = 0;
|
||||
for (size_t i = 0, n = DieArray.size(); i != n; i++) {
|
||||
if (DieArray[i].addressRangeContainsAddress(this, address))
|
||||
return &DieArray[i];
|
||||
if (DieArray[i].isSubprogramDIE() &&
|
||||
DieArray[i].addressRangeContainsAddress(this, Address)) {
|
||||
SubprogramDIE = &DieArray[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
// Get inlined chain rooted at this subprogram DIE.
|
||||
if (!SubprogramDIE)
|
||||
return DWARFDebugInfoEntryMinimal::InlinedChain();
|
||||
return SubprogramDIE->getInlinedChainForAddress(this, Address);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "DWARFDebugAbbrev.h"
|
||||
#include "DWARFDebugInfoEntry.h"
|
||||
#include "DWARFDebugRangeList.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
@ -45,6 +46,11 @@ public:
|
||||
/// extractDIEsIfNeeded - Parses a compile unit and indexes its DIEs if it
|
||||
/// hasn't already been done. Returns the number of DIEs parsed at this call.
|
||||
size_t extractDIEsIfNeeded(bool cu_die_only);
|
||||
/// extractRangeList - extracts the range list referenced by this compile
|
||||
/// unit from .debug_ranges section. Returns true on success.
|
||||
/// Requires that compile unit is already extracted.
|
||||
bool extractRangeList(uint32_t RangeListOffset,
|
||||
DWARFDebugRangeList &RangeList) const;
|
||||
void clear();
|
||||
void dump(raw_ostream &OS);
|
||||
uint32_t getOffset() const { return Offset; }
|
||||
@ -106,11 +112,11 @@ public:
|
||||
|
||||
void buildAddressRangeTable(DWARFDebugAranges *debug_aranges,
|
||||
bool clear_dies_if_already_not_parsed);
|
||||
/// getFunctionDIEForAddress - Returns pointer to parsed subprogram DIE,
|
||||
/// address ranges of which contain the provided address,
|
||||
/// or NULL if there is no such subprogram. The pointer
|
||||
/// is valid until DWARFCompileUnit::clear() or clearDIEs() is called.
|
||||
const DWARFDebugInfoEntryMinimal *getFunctionDIEForAddress(int64_t address);
|
||||
|
||||
/// getInlinedChainForAddress - fetches inlined chain for a given address.
|
||||
/// Returns empty chain if there is no subprogram containing address.
|
||||
DWARFDebugInfoEntryMinimal::InlinedChain getInlinedChainForAddress(
|
||||
uint64_t Address);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -183,15 +183,11 @@ static bool getFileNameForCompileUnit(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DWARFContext::getFileLineInfoForCompileUnit(DWARFCompileUnit *CU,
|
||||
uint64_t Address,
|
||||
bool NeedsAbsoluteFilePath,
|
||||
std::string &FileName,
|
||||
uint32_t &Line, uint32_t &Column) {
|
||||
// Get the line table for this compile unit.
|
||||
const DWARFDebugLine::LineTable *LineTable = getLineTableForCompileUnit(CU);
|
||||
if (!LineTable)
|
||||
static bool getFileLineInfoForCompileUnit(
|
||||
DWARFCompileUnit *CU, const DWARFDebugLine::LineTable *LineTable,
|
||||
uint64_t Address, bool NeedsAbsoluteFilePath, std::string &FileName,
|
||||
uint32_t &Line, uint32_t &Column) {
|
||||
if (CU == 0 || LineTable == 0)
|
||||
return false;
|
||||
// Get the index of row we're looking for in the line table.
|
||||
uint32_t RowIndex = LineTable->lookupAddress(Address);
|
||||
@ -217,21 +213,84 @@ DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address,
|
||||
uint32_t Line = 0;
|
||||
uint32_t Column = 0;
|
||||
if (Specifier.needs(DILineInfoSpecifier::FunctionName)) {
|
||||
const DWARFDebugInfoEntryMinimal *FunctionDIE =
|
||||
CU->getFunctionDIEForAddress(Address);
|
||||
if (FunctionDIE) {
|
||||
if (const char *Name = FunctionDIE->getSubprogramName(CU))
|
||||
// The address may correspond to instruction in some inlined function,
|
||||
// so we have to build the chain of inlined functions and take the
|
||||
// name of the topmost function in it.
|
||||
const DWARFDebugInfoEntryMinimal::InlinedChain &InlinedChain =
|
||||
CU->getInlinedChainForAddress(Address);
|
||||
if (InlinedChain.size() > 0) {
|
||||
const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain[0];
|
||||
if (const char *Name = TopFunctionDIE.getSubroutineName(CU))
|
||||
FunctionName = Name;
|
||||
}
|
||||
}
|
||||
if (Specifier.needs(DILineInfoSpecifier::FileLineInfo)) {
|
||||
const DWARFDebugLine::LineTable *LineTable =
|
||||
getLineTableForCompileUnit(CU);
|
||||
const bool NeedsAbsoluteFilePath =
|
||||
Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath);
|
||||
getFileLineInfoForCompileUnit(CU, Address, NeedsAbsoluteFilePath,
|
||||
getFileLineInfoForCompileUnit(CU, LineTable, Address,
|
||||
NeedsAbsoluteFilePath,
|
||||
FileName, Line, Column);
|
||||
}
|
||||
return DILineInfo(StringRef(FileName), StringRef(FunctionName),
|
||||
Line, Column);
|
||||
}
|
||||
|
||||
DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address,
|
||||
DILineInfoSpecifier Specifier) {
|
||||
DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
|
||||
if (!CU)
|
||||
return DIInliningInfo();
|
||||
|
||||
const DWARFDebugInfoEntryMinimal::InlinedChain &InlinedChain =
|
||||
CU->getInlinedChainForAddress(Address);
|
||||
if (InlinedChain.size() == 0)
|
||||
return DIInliningInfo();
|
||||
|
||||
DIInliningInfo InliningInfo;
|
||||
uint32_t CallFile = 0, CallLine = 0, CallColumn = 0;
|
||||
const DWARFDebugLine::LineTable *LineTable = 0;
|
||||
for (uint32_t i = 0, n = InlinedChain.size(); i != n; i++) {
|
||||
const DWARFDebugInfoEntryMinimal &FunctionDIE = InlinedChain[i];
|
||||
std::string FileName = "<invalid>";
|
||||
std::string FunctionName = "<invalid>";
|
||||
uint32_t Line = 0;
|
||||
uint32_t Column = 0;
|
||||
// Get function name if necessary.
|
||||
if (Specifier.needs(DILineInfoSpecifier::FunctionName)) {
|
||||
if (const char *Name = FunctionDIE.getSubroutineName(CU))
|
||||
FunctionName = Name;
|
||||
}
|
||||
if (Specifier.needs(DILineInfoSpecifier::FileLineInfo)) {
|
||||
const bool NeedsAbsoluteFilePath =
|
||||
Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath);
|
||||
if (i == 0) {
|
||||
// For the topmost frame, initialize the line table of this
|
||||
// compile unit and fetch file/line info from it.
|
||||
LineTable = getLineTableForCompileUnit(CU);
|
||||
// For the topmost routine, get file/line info from line table.
|
||||
getFileLineInfoForCompileUnit(CU, LineTable, Address,
|
||||
NeedsAbsoluteFilePath,
|
||||
FileName, Line, Column);
|
||||
} else {
|
||||
// Otherwise, use call file, call line and call column from
|
||||
// previous DIE in inlined chain.
|
||||
getFileNameForCompileUnit(CU, LineTable, CallFile,
|
||||
NeedsAbsoluteFilePath, FileName);
|
||||
Line = CallLine;
|
||||
Column = CallColumn;
|
||||
}
|
||||
// Get call file/line/column of a current DIE.
|
||||
if (i + 1 < n) {
|
||||
FunctionDIE.getCallerFrame(CU, CallFile, CallLine, CallColumn);
|
||||
}
|
||||
}
|
||||
DILineInfo Frame(StringRef(FileName), StringRef(FunctionName),
|
||||
Line, Column);
|
||||
InliningInfo.addFrame(Frame);
|
||||
}
|
||||
return InliningInfo;
|
||||
}
|
||||
|
||||
void DWARFContextInMemory::anchor() { }
|
||||
|
@ -66,6 +66,8 @@ public:
|
||||
|
||||
virtual DILineInfo getLineInfoForAddress(uint64_t Address,
|
||||
DILineInfoSpecifier Specifier = DILineInfoSpecifier());
|
||||
virtual DIInliningInfo getInliningInfoForAddress(uint64_t Address,
|
||||
DILineInfoSpecifier Specifier = DILineInfoSpecifier());
|
||||
|
||||
bool isLittleEndian() const { return IsLittleEndian; }
|
||||
|
||||
@ -86,14 +88,6 @@ private:
|
||||
/// Return the compile unit which contains instruction with provided
|
||||
/// address.
|
||||
DWARFCompileUnit *getCompileUnitForAddress(uint64_t Address);
|
||||
|
||||
/// Fetches filename, line and column number for given address and
|
||||
/// compile unit. Returns true on success.
|
||||
bool getFileLineInfoForCompileUnit(DWARFCompileUnit *CU,
|
||||
uint64_t Address,
|
||||
bool NeedsAbsoluteFilePath,
|
||||
std::string &FileName,
|
||||
uint32_t &Line, uint32_t &Column);
|
||||
};
|
||||
|
||||
/// DWARFContextInMemory is the simplest possible implementation of a
|
||||
|
@ -364,6 +364,16 @@ DWARFDebugInfoEntryMinimal::extract(const DWARFCompileUnit *cu,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DWARFDebugInfoEntryMinimal::isSubprogramDIE() const {
|
||||
return getTag() == DW_TAG_subprogram;
|
||||
}
|
||||
|
||||
bool DWARFDebugInfoEntryMinimal::isSubroutineDIE() const {
|
||||
uint32_t Tag = getTag();
|
||||
return Tag == DW_TAG_subprogram ||
|
||||
Tag == DW_TAG_inlined_subroutine;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
DWARFDebugInfoEntryMinimal::getAttributeValue(const DWARFCompileUnit *cu,
|
||||
const uint16_t attr,
|
||||
@ -446,24 +456,31 @@ DWARFDebugInfoEntryMinimal::getAttributeValueAsReference(
|
||||
return fail_value;
|
||||
}
|
||||
|
||||
bool DWARFDebugInfoEntryMinimal::getLowAndHighPC(const DWARFCompileUnit *CU,
|
||||
uint64_t &LowPC, uint64_t &HighPC) const {
|
||||
HighPC = -1ULL;
|
||||
LowPC = getAttributeValueAsUnsigned(CU, DW_AT_low_pc, -1ULL);
|
||||
if (LowPC != -1ULL)
|
||||
HighPC = getAttributeValueAsUnsigned(CU, DW_AT_high_pc, -1ULL);
|
||||
return (HighPC != -1ULL);
|
||||
}
|
||||
|
||||
void
|
||||
DWARFDebugInfoEntryMinimal::buildAddressRangeTable(const DWARFCompileUnit *cu,
|
||||
DWARFDebugAranges *debug_aranges)
|
||||
DWARFDebugInfoEntryMinimal::buildAddressRangeTable(const DWARFCompileUnit *CU,
|
||||
DWARFDebugAranges *DebugAranges)
|
||||
const {
|
||||
if (AbbrevDecl) {
|
||||
uint16_t tag = AbbrevDecl->getTag();
|
||||
if (tag == DW_TAG_subprogram) {
|
||||
uint64_t hi_pc = -1ULL;
|
||||
uint64_t lo_pc = getAttributeValueAsUnsigned(cu, DW_AT_low_pc, -1ULL);
|
||||
if (lo_pc != -1ULL)
|
||||
hi_pc = getAttributeValueAsUnsigned(cu, DW_AT_high_pc, -1ULL);
|
||||
if (hi_pc != -1ULL)
|
||||
debug_aranges->appendRange(cu->getOffset(), lo_pc, hi_pc);
|
||||
if (isSubprogramDIE()) {
|
||||
uint64_t LowPC, HighPC;
|
||||
if (getLowAndHighPC(CU, LowPC, HighPC)) {
|
||||
DebugAranges->appendRange(CU->getOffset(), LowPC, HighPC);
|
||||
}
|
||||
// FIXME: try to append ranges from .debug_ranges section.
|
||||
}
|
||||
|
||||
const DWARFDebugInfoEntryMinimal *child = getFirstChild();
|
||||
while (child) {
|
||||
child->buildAddressRangeTable(cu, debug_aranges);
|
||||
child->buildAddressRangeTable(CU, DebugAranges);
|
||||
child = child->getSibling();
|
||||
}
|
||||
}
|
||||
@ -471,51 +488,90 @@ DWARFDebugInfoEntryMinimal::buildAddressRangeTable(const DWARFCompileUnit *cu,
|
||||
|
||||
bool
|
||||
DWARFDebugInfoEntryMinimal::addressRangeContainsAddress(
|
||||
const DWARFCompileUnit *cu, const uint64_t address) const {
|
||||
if (!isNULL() && getTag() == DW_TAG_subprogram) {
|
||||
uint64_t hi_pc = -1ULL;
|
||||
uint64_t lo_pc = getAttributeValueAsUnsigned(cu, DW_AT_low_pc, -1ULL);
|
||||
if (lo_pc != -1ULL)
|
||||
hi_pc = getAttributeValueAsUnsigned(cu, DW_AT_high_pc, -1ULL);
|
||||
if (hi_pc != -1ULL) {
|
||||
return (lo_pc <= address && address < hi_pc);
|
||||
}
|
||||
const DWARFCompileUnit *CU, const uint64_t Address) const {
|
||||
if (isNULL())
|
||||
return false;
|
||||
uint64_t LowPC, HighPC;
|
||||
if (getLowAndHighPC(CU, LowPC, HighPC))
|
||||
return (LowPC <= Address && Address <= HighPC);
|
||||
// Try to get address ranges from .debug_ranges section.
|
||||
uint32_t RangesOffset = getAttributeValueAsReference(CU, DW_AT_ranges, -1U);
|
||||
if (RangesOffset != -1U) {
|
||||
DWARFDebugRangeList RangeList;
|
||||
if (CU->extractRangeList(RangesOffset, RangeList))
|
||||
return RangeList.containsAddress(CU->getBaseAddress(), Address);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char*
|
||||
DWARFDebugInfoEntryMinimal::getSubprogramName(
|
||||
const DWARFCompileUnit *cu) const {
|
||||
if (isNULL() || getTag() != DW_TAG_subprogram)
|
||||
DWARFDebugInfoEntryMinimal::getSubroutineName(
|
||||
const DWARFCompileUnit *CU) const {
|
||||
if (!isSubroutineDIE())
|
||||
return 0;
|
||||
// Try to get mangled name if possible.
|
||||
if (const char *name =
|
||||
getAttributeValueAsString(cu, DW_AT_MIPS_linkage_name, 0))
|
||||
getAttributeValueAsString(CU, DW_AT_MIPS_linkage_name, 0))
|
||||
return name;
|
||||
if (const char *name = getAttributeValueAsString(cu, DW_AT_linkage_name, 0))
|
||||
if (const char *name = getAttributeValueAsString(CU, DW_AT_linkage_name, 0))
|
||||
return name;
|
||||
if (const char *name = getAttributeValueAsString(cu, DW_AT_name, 0))
|
||||
if (const char *name = getAttributeValueAsString(CU, DW_AT_name, 0))
|
||||
return name;
|
||||
// Try to get name from specification DIE.
|
||||
uint32_t spec_ref =
|
||||
getAttributeValueAsReference(cu, DW_AT_specification, -1U);
|
||||
getAttributeValueAsReference(CU, DW_AT_specification, -1U);
|
||||
if (spec_ref != -1U) {
|
||||
DWARFDebugInfoEntryMinimal spec_die;
|
||||
if (spec_die.extract(cu, &spec_ref)) {
|
||||
if (const char *name = spec_die.getSubprogramName(cu))
|
||||
if (spec_die.extract(CU, &spec_ref)) {
|
||||
if (const char *name = spec_die.getSubroutineName(CU))
|
||||
return name;
|
||||
}
|
||||
}
|
||||
// Try to get name from abstract origin DIE.
|
||||
uint32_t abs_origin_ref =
|
||||
getAttributeValueAsReference(cu, DW_AT_abstract_origin, -1U);
|
||||
getAttributeValueAsReference(CU, DW_AT_abstract_origin, -1U);
|
||||
if (abs_origin_ref != -1U) {
|
||||
DWARFDebugInfoEntryMinimal abs_origin_die;
|
||||
if (abs_origin_die.extract(cu, &abs_origin_ref)) {
|
||||
if (const char *name = abs_origin_die.getSubprogramName(cu))
|
||||
if (abs_origin_die.extract(CU, &abs_origin_ref)) {
|
||||
if (const char *name = abs_origin_die.getSubroutineName(CU))
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DWARFDebugInfoEntryMinimal::getCallerFrame(
|
||||
const DWARFCompileUnit *CU, uint32_t &CallFile, uint32_t &CallLine,
|
||||
uint32_t &CallColumn) const {
|
||||
CallFile = getAttributeValueAsUnsigned(CU, DW_AT_call_file, 0);
|
||||
CallLine = getAttributeValueAsUnsigned(CU, DW_AT_call_line, 0);
|
||||
CallColumn = getAttributeValueAsUnsigned(CU, DW_AT_call_column, 0);
|
||||
}
|
||||
|
||||
DWARFDebugInfoEntryMinimal::InlinedChain
|
||||
DWARFDebugInfoEntryMinimal::getInlinedChainForAddress(
|
||||
const DWARFCompileUnit *CU, const uint64_t Address) const {
|
||||
DWARFDebugInfoEntryMinimal::InlinedChain InlinedChain;
|
||||
if (isNULL())
|
||||
return InlinedChain;
|
||||
for (const DWARFDebugInfoEntryMinimal *DIE = this; DIE; ) {
|
||||
// Append current DIE to inlined chain only if it has correct tag
|
||||
// (e.g. it is not a lexical block).
|
||||
if (DIE->isSubroutineDIE()) {
|
||||
InlinedChain.push_back(*DIE);
|
||||
}
|
||||
// Try to get child which also contains provided address.
|
||||
const DWARFDebugInfoEntryMinimal *Child = DIE->getFirstChild();
|
||||
while (Child) {
|
||||
if (Child->addressRangeContainsAddress(CU, Address)) {
|
||||
// Assume there is only one such child.
|
||||
break;
|
||||
}
|
||||
Child = Child->getSibling();
|
||||
}
|
||||
DIE = Child;
|
||||
}
|
||||
// Reverse the obtained chain to make the root of inlined chain last.
|
||||
std::reverse(InlinedChain.begin(), InlinedChain.end());
|
||||
return InlinedChain;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#define LLVM_DEBUGINFO_DWARFDEBUGINFOENTRY_H
|
||||
|
||||
#include "DWARFAbbreviationDeclaration.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
namespace llvm {
|
||||
@ -19,6 +20,7 @@ class DWARFDebugAranges;
|
||||
class DWARFCompileUnit;
|
||||
class DWARFContext;
|
||||
class DWARFFormValue;
|
||||
class DWARFInlinedSubroutineChain;
|
||||
|
||||
/// DWARFDebugInfoEntryMinimal - A DIE with only the minimum required data.
|
||||
class DWARFDebugInfoEntryMinimal {
|
||||
@ -52,6 +54,13 @@ public:
|
||||
|
||||
uint32_t getTag() const { return AbbrevDecl ? AbbrevDecl->getTag() : 0; }
|
||||
bool isNULL() const { return AbbrevDecl == 0; }
|
||||
|
||||
/// Returns true if DIE represents a subprogram (not inlined).
|
||||
bool isSubprogramDIE() const;
|
||||
/// Returns true if DIE represents a subprogram or an inlined
|
||||
/// subroutine.
|
||||
bool isSubroutineDIE() const;
|
||||
|
||||
uint32_t getOffset() const { return Offset; }
|
||||
uint32_t getNumAttributes() const {
|
||||
return !isNULL() ? AbbrevDecl->getNumAttributes() : 0;
|
||||
@ -126,17 +135,40 @@ public:
|
||||
const uint16_t attr,
|
||||
int64_t fail_value) const;
|
||||
|
||||
void buildAddressRangeTable(const DWARFCompileUnit *cu,
|
||||
DWARFDebugAranges *debug_aranges) const;
|
||||
/// Retrieves DW_AT_low_pc and DW_AT_high_pc from CU.
|
||||
/// Returns true if both attributes are present.
|
||||
bool getLowAndHighPC(const DWARFCompileUnit *CU,
|
||||
uint64_t &LowPC, uint64_t &HighPC) const;
|
||||
|
||||
bool addressRangeContainsAddress(const DWARFCompileUnit *cu,
|
||||
const uint64_t address) const;
|
||||
void buildAddressRangeTable(const DWARFCompileUnit *CU,
|
||||
DWARFDebugAranges *DebugAranges) const;
|
||||
|
||||
// If a DIE represents a subprogram, returns its mangled name
|
||||
// (or short name, if mangled is missing). This name may be fetched
|
||||
// from specification or abstract origin for this subprogram.
|
||||
// Returns null if no name is found.
|
||||
const char* getSubprogramName(const DWARFCompileUnit *cu) const;
|
||||
bool addressRangeContainsAddress(const DWARFCompileUnit *CU,
|
||||
const uint64_t Address) const;
|
||||
|
||||
/// If a DIE represents a subprogram (or inlined subroutine),
|
||||
/// returns its mangled name (or short name, if mangled is missing).
|
||||
/// This name may be fetched from specification or abstract origin
|
||||
/// for this subprogram. Returns null if no name is found.
|
||||
const char* getSubroutineName(const DWARFCompileUnit *CU) const;
|
||||
|
||||
/// Retrieves values of DW_AT_call_file, DW_AT_call_line and
|
||||
/// DW_AT_call_column from DIE (or zeroes if they are missing).
|
||||
void getCallerFrame(const DWARFCompileUnit *CU, uint32_t &CallFile,
|
||||
uint32_t &CallLine, uint32_t &CallColumn) const;
|
||||
|
||||
/// InlinedChain - represents a chain of inlined_subroutine
|
||||
/// DIEs, (possibly ending with subprogram DIE), all of which are contained
|
||||
/// in some concrete inlined instance tree. Address range for each DIE
|
||||
/// (except the last DIE) in this chain is contained in address
|
||||
/// range for next DIE in the chain.
|
||||
typedef SmallVector<DWARFDebugInfoEntryMinimal, 4> InlinedChain;
|
||||
|
||||
/// Get inlined chain for a given address, rooted at the current DIE.
|
||||
/// Returns empty chain if address is not contained in address range
|
||||
/// of current DIE.
|
||||
InlinedChain getInlinedChainForAddress(const DWARFCompileUnit *CU,
|
||||
const uint64_t Address) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -37,10 +37,7 @@ bool DWARFDebugRangeList::extract(DataExtractor data, uint32_t *offset_ptr) {
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
// The end of any given range list is marked by an end of list entry,
|
||||
// which consists of a 0 for the beginning address offset
|
||||
// and a 0 for the ending address offset.
|
||||
if (entry.StartAddress == 0 && entry.EndAddress == 0)
|
||||
if (entry.isEndOfListEntry())
|
||||
break;
|
||||
Entries.push_back(entry);
|
||||
}
|
||||
@ -57,3 +54,14 @@ void DWARFDebugRangeList::dump(raw_ostream &OS) const {
|
||||
}
|
||||
OS << format("%08x <End of list>\n", Offset);
|
||||
}
|
||||
|
||||
bool DWARFDebugRangeList::containsAddress(uint64_t BaseAddress,
|
||||
uint64_t Address) const {
|
||||
for (int i = 0, n = Entries.size(); i != n; ++i) {
|
||||
if (Entries[i].isBaseAddressSelectionEntry(AddressSize))
|
||||
BaseAddress = Entries[i].EndAddress;
|
||||
else if (Entries[i].containsAddress(BaseAddress, Address))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -31,6 +31,29 @@ public:
|
||||
// address past the end of the address range. The ending address must
|
||||
// be greater than or equal to the beginning address.
|
||||
uint64_t EndAddress;
|
||||
// The end of any given range list is marked by an end of list entry,
|
||||
// which consists of a 0 for the beginning address offset
|
||||
// and a 0 for the ending address offset.
|
||||
bool isEndOfListEntry() const {
|
||||
return (StartAddress == 0) && (EndAddress == 0);
|
||||
}
|
||||
// A base address selection entry consists of:
|
||||
// 1. The value of the largest representable address offset
|
||||
// (for example, 0xffffffff when the size of an address is 32 bits).
|
||||
// 2. An address, which defines the appropriate base address for
|
||||
// use in interpreting the beginning and ending address offsets of
|
||||
// subsequent entries of the location list.
|
||||
bool isBaseAddressSelectionEntry(uint8_t AddressSize) const {
|
||||
assert(AddressSize == 4 || AddressSize == 8);
|
||||
if (AddressSize == 4)
|
||||
return StartAddress == -1U;
|
||||
else
|
||||
return StartAddress == -1ULL;
|
||||
}
|
||||
bool containsAddress(uint64_t BaseAddress, uint64_t Address) const {
|
||||
return (BaseAddress + StartAddress <= Address) &&
|
||||
(Address < BaseAddress + EndAddress);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
@ -44,6 +67,10 @@ public:
|
||||
void clear();
|
||||
void dump(raw_ostream &OS) const;
|
||||
bool extract(DataExtractor data, uint32_t *offset_ptr);
|
||||
/// containsAddress - Returns true if range list contains the given
|
||||
/// address. Has to be passed base address of the compile unit that
|
||||
/// references this range list.
|
||||
bool containsAddress(uint64_t BaseAddress, uint64_t Address) const;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
BIN
test/DebugInfo/Inputs/dwarfdump-inl-test.elf-x86-64
Executable file
BIN
test/DebugInfo/Inputs/dwarfdump-inl-test.elf-x86-64
Executable file
Binary file not shown.
28
test/DebugInfo/dwarfdump-inlining.test
Normal file
28
test/DebugInfo/dwarfdump-inlining.test
Normal file
@ -0,0 +1,28 @@
|
||||
RUN: llvm-dwarfdump %p/Inputs/dwarfdump-inl-test.elf-x86-64 --address=0x613 \
|
||||
RUN: --inlining --functions | FileCheck %s -check-prefix DEEP_STACK
|
||||
RUN: llvm-dwarfdump %p/Inputs/dwarfdump-inl-test.elf-x86-64 --address=0x6de \
|
||||
RUN: --inlining | FileCheck %s -check-prefix SHORTER_STACK
|
||||
RUN: llvm-dwarfdump %p/Inputs/dwarfdump-inl-test.elf-x86-64 --address=0x685 \
|
||||
RUN: --inlining | FileCheck %s -check-prefix SHORT_STACK
|
||||
RUN: llvm-dwarfdump %p/Inputs/dwarfdump-inl-test.elf-x86-64 --address=0x640 \
|
||||
RUN: --functions | FileCheck %s -check-prefix INL_FUNC_NAME
|
||||
|
||||
DEEP_STACK: inlined_h
|
||||
DEEP_STACK-NEXT: header.h:2:21
|
||||
DEEP_STACK-NEXT: inlined_g
|
||||
DEEP_STACK-NEXT: header.h:7
|
||||
DEEP_STACK-NEXT: inlined_f
|
||||
DEEP_STACK-NEXT: main.cc:3
|
||||
DEEP_STACK-NEXT: main
|
||||
DEEP_STACK-NEXT: main.cc:8
|
||||
|
||||
SHORTER_STACK: header.h:7:20
|
||||
SHORTER_STACK-NEXT: main.cc:3
|
||||
SHORTER_STACK-NEXT: main.cc:8
|
||||
|
||||
SHORT_STACK: main.cc:3:20
|
||||
SHORT_STACK-NEXT: main.cc:8
|
||||
|
||||
INL_FUNC_NAME: inlined_g
|
||||
INL_FUNC_NAME-NEXT: header.h:7:20
|
||||
|
@ -44,6 +44,18 @@ PrintFunctions("functions", cl::init(false),
|
||||
cl::desc("Print function names as well as line information "
|
||||
"for a given address"));
|
||||
|
||||
static cl::opt<bool>
|
||||
PrintInlining("inlining", cl::init(false),
|
||||
cl::desc("Print all inlined frames for a given address"));
|
||||
|
||||
static void PrintDILineInfo(DILineInfo dli) {
|
||||
if (PrintFunctions)
|
||||
outs() << (dli.getFunctionName() ? dli.getFunctionName() : "<unknown>")
|
||||
<< "\n";
|
||||
outs() << (dli.getFileName() ? dli.getFileName() : "<unknown>") << ':'
|
||||
<< dli.getLine() << ':' << dli.getColumn() << '\n';
|
||||
}
|
||||
|
||||
static void DumpInput(const StringRef &Filename) {
|
||||
OwningPtr<MemoryBuffer> Buff;
|
||||
|
||||
@ -101,16 +113,27 @@ static void DumpInput(const StringRef &Filename) {
|
||||
dictx->dump(outs());
|
||||
} else {
|
||||
// Print line info for the specified address.
|
||||
int spec_flags = DILineInfoSpecifier::FileLineInfo |
|
||||
DILineInfoSpecifier::AbsoluteFilePath;
|
||||
int SpecFlags = DILineInfoSpecifier::FileLineInfo |
|
||||
DILineInfoSpecifier::AbsoluteFilePath;
|
||||
if (PrintFunctions)
|
||||
spec_flags |= DILineInfoSpecifier::FunctionName;
|
||||
DILineInfo dli = dictx->getLineInfoForAddress(Address, spec_flags);
|
||||
if (PrintFunctions)
|
||||
outs() << (dli.getFunctionName() ? dli.getFunctionName() : "<unknown>")
|
||||
<< "\n";
|
||||
outs() << (dli.getFileName() ? dli.getFileName() : "<unknown>") << ':'
|
||||
<< dli.getLine() << ':' << dli.getColumn() << '\n';
|
||||
SpecFlags |= DILineInfoSpecifier::FunctionName;
|
||||
if (PrintInlining) {
|
||||
DIInliningInfo InliningInfo = dictx->getInliningInfoForAddress(
|
||||
Address, SpecFlags);
|
||||
uint32_t n = InliningInfo.getNumberOfFrames();
|
||||
if (n == 0) {
|
||||
// Print one empty debug line info in any case.
|
||||
PrintDILineInfo(DILineInfo());
|
||||
} else {
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
DILineInfo dli = InliningInfo.getFrame(i);
|
||||
PrintDILineInfo(dli);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DILineInfo dli = dictx->getLineInfoForAddress(Address, SpecFlags);
|
||||
PrintDILineInfo(dli);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user