Index: include/llvm/DebugInfo/DIContext.h =================================================================== --- include/llvm/DebugInfo/DIContext.h +++ include/llvm/DebugInfo/DIContext.h @@ -34,13 +34,14 @@ std::string FunctionName; uint32_t Line; uint32_t Column; + uint32_t StartLine; // DWARF-specific. uint32_t Discriminator; DILineInfo() : FileName(""), FunctionName(""), Line(0), Column(0), - Discriminator(0) {} + Discriminator(0), StartLine(0) {} bool operator==(const DILineInfo &RHS) const { return Line == RHS.Line && Column == RHS.Column && Index: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ lib/DebugInfo/DWARF/DWARFContext.cpp @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" +#include "llvm/Demangle/Demangle.h" #include "llvm/Object/MachO.h" #include "llvm/Object/RelocVisitor.h" #include "llvm/Support/Compression.h" @@ -77,6 +78,45 @@ Accel.dump(OS); } +// Given a function name and its compilation unit, determines the starting line +// of the function in source code, indicated by the DIE value DW_AT_decl_line. +static uint32_t getStartLine(const std::string& FunctionName, + DWARFCompileUnit* CU) { + // Find DIE with start info. + size_t buf_len = 1024; + char* demangle_func_buf = reinterpret_cast(malloc(buf_len)); + + // itaniumDemangle() returns nullptr in the event of an error. + char* demangle_result = itaniumDemangle(FunctionName.c_str(), + demangle_func_buf, &buf_len, nullptr); + std::string demangled_func_name; + if (demangle_result) { + demangled_func_name = demangle_result; + // Drop the function signature part, and keep only the name. + size_t func_name_len = demangled_func_name.find("("); + if (func_name_len != std::string::npos) { + demangled_func_name.resize(func_name_len); + } + // The buffer might have been realloc'd by itaniumDemangle(). + demangle_func_buf = demangle_result; + } + free(demangle_func_buf); + + for (size_t i = 0; i < CU->getNumDIEs(); ++i) { + const DWARFDie die = CU->getDIEAtIndex(i); + if (!die.isSubprogramDIE()) { + continue; + } + std::string func_name = die.getAttributeValueAsString(DW_AT_name, ""); + if ((func_name.empty() || func_name != FunctionName) && + (demangled_func_name.empty() || func_name != demangled_func_name)) { + continue; + } + return die.getAttributeValueAsUnsignedConstant(DW_AT_decl_line, -2U); + } + return -1U; +} + void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH, bool SummarizeTypes) { if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) { @@ -501,6 +541,7 @@ LineTable->getFileLineInfoForAddress(Address, CU->getCompilationDir(), Spec.FLIKind, Result); } + Result.StartLine = getStartLine(Result.FunctionName, CU); return Result; } @@ -521,6 +562,7 @@ DILineInfo Result; Result.FunctionName = FunctionName; Lines.push_back(std::make_pair(Address, Result)); + Result.StartLine = getStartLine(FunctionName, CU); return Lines; } @@ -540,6 +582,7 @@ Result.FunctionName = FunctionName; Result.Line = Row.Line; Result.Column = Row.Column; + Result.StartLine = getStartLine(FunctionName, CU); Lines.push_back(std::make_pair(Row.Address, Result)); } @@ -597,6 +640,7 @@ Frame.Line = CallLine; Frame.Column = CallColumn; } + Frame.StartLine = getStartLine(Frame.FunctionName, CU); // Get call file/line/column of a current DIE. if (i + 1 < n) { FunctionDIE.getCallerFrame(CallFile, CallLine, CallColumn);