Index: llvm/trunk/include/llvm/DebugInfo/DIContext.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DIContext.h +++ llvm/trunk/include/llvm/DebugInfo/DIContext.h @@ -34,24 +34,28 @@ 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) {} + 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); } }; Index: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDie.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDie.h +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -233,6 +233,12 @@ /// 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 Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -439,23 +439,32 @@ 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 &InlinedChain + // name of the topmost function in it. SmallVector 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 @@ 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 @@ return Lines; std::string FunctionName = ""; - 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 @@ 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 @@ // 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 Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -291,6 +291,10 @@ 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); Index: llvm/trunk/lib/DebugInfo/Symbolize/DIPrinter.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/Symbolize/DIPrinter.cpp +++ llvm/trunk/lib/DebugInfo/Symbolize/DIPrinter.cpp @@ -84,6 +84,8 @@ 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) Index: llvm/trunk/test/tools/llvm-symbolizer/sym-verbose.test =================================================================== --- llvm/trunk/test/tools/llvm-symbolizer/sym-verbose.test +++ llvm/trunk/test/tools/llvm-symbolizer/sym-verbose.test @@ -15,6 +15,7 @@ #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 @@ #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 @@ #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