Get function start line number from DWARF info

DWARF info contains info about the line number at which a function starts (DW_AT_decl_line).

This patch creates a function to look up the start line number for a function, and returns it in
DILineInfo when looking up debug info for a particular address.

Patch by Simon Que!

Reviewed By: dblaikie

Differential Revision: https://reviews.llvm.org/D27962

llvm-svn: 294231
This commit is contained in:
David Blaikie 2017-02-06 20:19:02 +00:00
parent 1b4eed4c1e
commit efc4eba816
6 changed files with 52 additions and 16 deletions

View File

@ -34,24 +34,28 @@ struct DILineInfo {
std::string FunctionName;
uint32_t Line;
uint32_t Column;
uint32_t StartLine;
// DWARF-specific.
uint32_t Discriminator;
DILineInfo()
: FileName("<invalid>"), FunctionName("<invalid>"), Line(0), Column(0),
Discriminator(0) {}
StartLine(0), Discriminator(0) {}
bool operator==(const DILineInfo &RHS) const {
return Line == RHS.Line && Column == RHS.Column &&
FileName == RHS.FileName && FunctionName == RHS.FunctionName;
FileName == RHS.FileName && FunctionName == RHS.FunctionName &&
StartLine == RHS.StartLine && Discriminator == RHS.Discriminator;
}
bool operator!=(const DILineInfo &RHS) const {
return !(*this == RHS);
}
bool operator<(const DILineInfo &RHS) const {
return std::tie(FileName, FunctionName, Line, Column) <
std::tie(RHS.FileName, RHS.FunctionName, RHS.Line, RHS.Column);
return std::tie(FileName, FunctionName, Line, Column, StartLine,
Discriminator) <
std::tie(RHS.FileName, RHS.FunctionName, RHS.Line, RHS.Column,
RHS.StartLine, RHS.Discriminator);
}
};

View File

@ -233,6 +233,12 @@ public:
/// references if necessary. Returns null if no name is found.
const char *getName(DINameKind Kind) const;
/// Returns the declaration line (start line) for a DIE, assuming it specifies
/// a subprogram. This may be fetched from specification or abstract origin
/// for this subprogram by resolving DW_AT_sepcification or
/// DW_AT_abstract_origin references if necessary.
uint64_t getDeclLine() 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). This function looks for
/// DW_AT_call attributes in this DIE only, it will not resolve the attribute

View File

@ -439,23 +439,32 @@ DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) {
return getCompileUnitForOffset(CUOffset);
}
static bool getFunctionNameForAddress(DWARFCompileUnit *CU, uint64_t Address,
FunctionNameKind Kind,
std::string &FunctionName) {
if (Kind == FunctionNameKind::None)
return false;
static bool getFunctionNameAndStartLineForAddress(DWARFCompileUnit *CU,
uint64_t Address,
FunctionNameKind Kind,
std::string &FunctionName,
uint32_t &StartLine) {
// 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.SmallVectorImpl<DWARFDie> &InlinedChain
// name of the topmost function in it.
SmallVector<DWARFDie, 4> InlinedChain;
CU->getInlinedChainForAddress(Address, InlinedChain);
if (InlinedChain.size() == 0)
if (InlinedChain.empty())
return false;
if (const char *Name = InlinedChain[0].getSubroutineName(Kind)) {
const DWARFDie &DIE = InlinedChain[0];
bool FoundResult = false;
const char *Name = nullptr;
if (Kind != FunctionNameKind::None && (Name = DIE.getSubroutineName(Kind))) {
FunctionName = Name;
return true;
FoundResult = true;
}
return false;
if (auto DeclLineResult = DIE.getDeclLine()) {
StartLine = DeclLineResult;
FoundResult = true;
}
return FoundResult;
}
DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address,
@ -465,7 +474,9 @@ DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address,
DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
if (!CU)
return Result;
getFunctionNameForAddress(CU, Address, Spec.FNKind, Result.FunctionName);
getFunctionNameAndStartLineForAddress(CU, Address, Spec.FNKind,
Result.FunctionName,
Result.StartLine);
if (Spec.FLIKind != FileLineInfoKind::None) {
if (const DWARFLineTable *LineTable = getLineTableForUnit(CU))
LineTable->getFileLineInfoForAddress(Address, CU->getCompilationDir(),
@ -483,13 +494,16 @@ DWARFContext::getLineInfoForAddressRange(uint64_t Address, uint64_t Size,
return Lines;
std::string FunctionName = "<invalid>";
getFunctionNameForAddress(CU, Address, Spec.FNKind, FunctionName);
uint32_t StartLine = 0;
getFunctionNameAndStartLineForAddress(CU, Address, Spec.FNKind, FunctionName,
StartLine);
// If the Specifier says we don't need FileLineInfo, just
// return the top-most function at the starting address.
if (Spec.FLIKind == FileLineInfoKind::None) {
DILineInfo Result;
Result.FunctionName = FunctionName;
Result.StartLine = StartLine;
Lines.push_back(std::make_pair(Address, Result));
return Lines;
}
@ -510,6 +524,7 @@ DWARFContext::getLineInfoForAddressRange(uint64_t Address, uint64_t Size,
Result.FunctionName = FunctionName;
Result.Line = Row.Line;
Result.Column = Row.Column;
Result.StartLine = StartLine;
Lines.push_back(std::make_pair(Row.Address, Result));
}
@ -549,6 +564,8 @@ DWARFContext::getInliningInfoForAddress(uint64_t Address,
// Get function name if necessary.
if (const char *Name = FunctionDIE.getSubroutineName(Spec.FNKind))
Frame.FunctionName = Name;
if (auto DeclLineResult = FunctionDIE.getDeclLine())
Frame.StartLine = DeclLineResult;
if (Spec.FLIKind != FileLineInfoKind::None) {
if (i == 0) {
// For the topmost frame, initialize the line table of this

View File

@ -291,6 +291,10 @@ DWARFDie::getName(DINameKind Kind) const {
return nullptr;
}
uint64_t DWARFDie::getDeclLine() const {
return toUnsigned(findRecursively(DW_AT_decl_line), 0);
}
void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
uint32_t &CallColumn) const {
CallFile = toUnsigned(find(DW_AT_call_file), 0);

View File

@ -84,6 +84,8 @@ void DIPrinter::print(const DILineInfo &Info, bool Inlined) {
return;
}
OS << " Filename: " << Filename << "\n";
if (Info.StartLine)
OS << "Function start line: " << Info.StartLine << "\n";
OS << " Line: " << Info.Line << "\n";
OS << " Column: " << Info.Column << "\n";
if (Info.Discriminator)

View File

@ -15,6 +15,7 @@ RUN: llvm-symbolizer -verbose -print-address -obj=%p/Inputs/discrim < %p/Inputs/
#CHECK: 0x4004f2
#CHECK-NEXT: main
#CHECK-NEXT: Filename: /tmp{{[\\/]}}discrim.c
#CHECK-NEXT: Function start line: 4
#CHECK-NEXT: Line: 6
#CHECK-NEXT: Column: 7
#CHECK-NOT: Discriminator: 0
@ -22,6 +23,7 @@ RUN: llvm-symbolizer -verbose -print-address -obj=%p/Inputs/discrim < %p/Inputs/
#CHECK: 0x400509
#CHECK-NEXT: main
#CHECK-NEXT: Filename: /tmp{{[\\/]}}discrim.c
#CHECK-NEXT: Function start line: 4
#CHECK-NEXT: Line: 7
#CHECK-NEXT: Column: 3
#CHECK-NEXT: Discriminator: 1
@ -29,6 +31,7 @@ RUN: llvm-symbolizer -verbose -print-address -obj=%p/Inputs/discrim < %p/Inputs/
#CHECK: 0x40050d
#CHECK-NEXT: main
#CHECK-NEXT: Filename: /tmp{{[\\/]}}discrim.c
#CHECK-NEXT: Function start line: 4
#CHECK-NEXT: Line: 7
#CHECK-NEXT: Column: 3
#CHECK-NEXT: Discriminator: 2