Index: include/llvm/DebugInfo/DIContext.h =================================================================== --- include/llvm/DebugInfo/DIContext.h +++ 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: include/llvm/DebugInfo/DWARF/DWARFDie.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDie.h +++ 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. + Optional 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: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ 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 (Optional 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,9 @@ // Get function name if necessary. if (const char *Name = FunctionDIE.getSubroutineName(Spec.FNKind)) Frame.FunctionName = Name; + Optional DeclLineResult = FunctionDIE.getDeclLine(); + if (DeclLineResult) + Frame.StartLine = *DeclLineResult; if (Spec.FLIKind != FileLineInfoKind::None) { if (i == 0) { // For the topmost frame, initialize the line table of this Index: lib/DebugInfo/DWARF/DWARFDie.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDie.cpp +++ lib/DebugInfo/DWARF/DWARFDie.cpp @@ -291,6 +291,25 @@ return nullptr; } +Optional DWARFDie::getDeclLine() const { + if (auto DeclLine = find(DW_AT_decl_line)) + return DeclLine->getAsUnsignedConstant(); + + // Try to get name from specification DIE. + if (auto SpecDie = getAttributeValueAsReferencedDie(DW_AT_specification)) { + if (auto DeclLine = SpecDie.getDeclLine()) + return DeclLine; + } + + // Try to get name from abstract origin DIE. + if (auto AbsDie = getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) { + if (auto DeclLine = AbsDie.getDeclLine()) + return DeclLine; + } + + return None; +} + void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine, uint32_t &CallColumn) const { CallFile = toUnsigned(find(DW_AT_call_file), 0); Index: lib/DebugInfo/Symbolize/DIPrinter.cpp =================================================================== --- lib/DebugInfo/Symbolize/DIPrinter.cpp +++ lib/DebugInfo/Symbolize/DIPrinter.cpp @@ -86,6 +86,8 @@ OS << " Filename: " << Filename << "\n"; OS << " Line: " << Info.Line << "\n"; OS << " Column: " << Info.Column << "\n"; + if (Info.StartLine) + OS << "Start line: " << Info.StartLine << "\n"; if (Info.Discriminator) OS << " Discriminator: " << Info.Discriminator << "\n"; } Index: test/tools/llvm-symbolizer/sym-verbose.test =================================================================== --- test/tools/llvm-symbolizer/sym-verbose.test +++ test/tools/llvm-symbolizer/sym-verbose.test @@ -17,6 +17,7 @@ #CHECK-NEXT: Filename: /tmp{{[\\/]}}discrim.c #CHECK-NEXT: Line: 6 #CHECK-NEXT: Column: 7 +#CHECK-NEXT: Start line: 4 #CHECK-NOT: Discriminator: 0 #CHECK: 0x400509 @@ -24,6 +25,7 @@ #CHECK-NEXT: Filename: /tmp{{[\\/]}}discrim.c #CHECK-NEXT: Line: 7 #CHECK-NEXT: Column: 3 +#CHECK-NEXT: Start line: 4 #CHECK-NEXT: Discriminator: 1 #CHECK: 0x40050d @@ -31,6 +33,7 @@ #CHECK-NEXT: Filename: /tmp{{[\\/]}}discrim.c #CHECK-NEXT: Line: 7 #CHECK-NEXT: Column: 3 +#CHECK-NEXT: Start line: 4 #CHECK-NEXT: Discriminator: 2 #CHECK: some more text