diff --git a/lld/Common/DWARF.cpp b/lld/Common/DWARF.cpp index 2cd8ca4575dee5..728021b78c4149 100644 --- a/lld/Common/DWARF.cpp +++ b/lld/Common/DWARF.cpp @@ -93,7 +93,7 @@ std::optional DWARFCache::getDILineInfo(uint64_t offset, DILineInfo info; for (const llvm::DWARFDebugLine::LineTable *lt : lineTables) { if (lt->getFileLineInfoForAddress( - {offset, sectionIndex}, nullptr, + {offset, sectionIndex}, false, nullptr, DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, info)) return info; } diff --git a/llvm/docs/CommandGuide/llvm-symbolizer.rst b/llvm/docs/CommandGuide/llvm-symbolizer.rst index 59c0ab6d196ace..2da1b2470a83e7 100644 --- a/llvm/docs/CommandGuide/llvm-symbolizer.rst +++ b/llvm/docs/CommandGuide/llvm-symbolizer.rst @@ -207,6 +207,33 @@ Example 7 - Addresses as symbol names: foz /tmp/test.h:1:0 +Example 8 - :option:`--skip-line-zero` output for an address with no line correspondence (an address associated with line zero): + +.. code-block:: c + + // test.c + int foo = 0; + int x = 1234; + int main() { + if (x) + return foo; + else + return x; + } + +These files are built as follows: + +.. code-block:: console + + $ clang -g -O2 -S test.c -o test.s + $ llvm-mc -filetype=obj -triple=x86_64-unknown-linux test.s -o test.o + +.. code-block:: console + + $ llvm-symbolizer --obj=test.o --skip-line-zero 0xa + main + /tmp/test.c:5:7 (approximate) + OPTIONS ------- @@ -216,6 +243,12 @@ OPTIONS This can be used to perform lookups as if the object were relocated by the offset. +.. option:: --skip-line-zero + + If an address does not have an associated line number, use the last line + number from the current sequence in the line-table. Such lines are labeled + as "approximate" in the output as they may be misleading. + .. option:: --basenames, -s Print just the file's name without any directories, instead of the diff --git a/llvm/include/llvm/DebugInfo/DIContext.h b/llvm/include/llvm/DebugInfo/DIContext.h index b75dc8db54336b..71685ba09d8dbb 100644 --- a/llvm/include/llvm/DebugInfo/DIContext.h +++ b/llvm/include/llvm/DebugInfo/DIContext.h @@ -30,6 +30,7 @@ namespace llvm { /// A format-neutral container for source line information. struct DILineInfo { + static constexpr const char *const ApproxString = "(approximate)"; // DILineInfo contains "" for function/filename it cannot fetch. static constexpr const char *const BadString = ""; // Use "??" instead of "" to make our output closer to addr2line. @@ -50,6 +51,7 @@ struct DILineInfo { // DWARF-specific. uint32_t Discriminator = 0; + bool IsApproximateLine = false; DILineInfo() : FileName(BadString), FunctionName(BadString), StartFileName(BadString) { } @@ -153,13 +155,14 @@ struct DILineInfoSpecifier { AbsoluteFilePath }; using FunctionNameKind = DINameKind; - FileLineInfoKind FLIKind; FunctionNameKind FNKind; + bool ApproximateLine; DILineInfoSpecifier(FileLineInfoKind FLIKind = FileLineInfoKind::RawValue, - FunctionNameKind FNKind = FunctionNameKind::None) - : FLIKind(FLIKind), FNKind(FNKind) {} + FunctionNameKind FNKind = FunctionNameKind::None, + bool ApproximateLine = false) + : FLIKind(FLIKind), FNKind(FNKind), ApproximateLine(ApproximateLine) {} inline bool operator==(const DILineInfoSpecifier &RHS) const { return FLIKind == RHS.FLIKind && FNKind == RHS.FNKind; diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h index ce3bae6a1760c2..ff7bf87d8e6b5a 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h @@ -240,7 +240,8 @@ class DWARFDebugLine { /// Returns the index of the row with file/line info for a given address, /// or UnknownRowIndex if there is no such row. - uint32_t lookupAddress(object::SectionedAddress Address) const; + uint32_t lookupAddress(object::SectionedAddress Address, + bool *IsApproximateLine = nullptr) const; bool lookupAddressRange(object::SectionedAddress Address, uint64_t Size, std::vector &Result) const; @@ -267,7 +268,7 @@ class DWARFDebugLine { /// Fills the Result argument with the file and line information /// corresponding to Address. Returns true on success. bool getFileLineInfoForAddress(object::SectionedAddress Address, - const char *CompDir, + bool Approximate, const char *CompDir, DILineInfoSpecifier::FileLineInfoKind Kind, DILineInfo &Result) const; @@ -301,7 +302,8 @@ class DWARFDebugLine { getSourceByIndex(uint64_t FileIndex, DILineInfoSpecifier::FileLineInfoKind Kind) const; - uint32_t lookupAddressImpl(object::SectionedAddress Address) const; + uint32_t lookupAddressImpl(object::SectionedAddress Address, + bool *IsApproximateLine = nullptr) const; bool lookupAddressRangeImpl(object::SectionedAddress Address, uint64_t Size, std::vector &Result) const; diff --git a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h index 11a169cfc20a69..bd8de070f84c5a 100644 --- a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h +++ b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h @@ -52,6 +52,7 @@ class LLVMSymbolizer { struct Options { FunctionNameKind PrintFunctions = FunctionNameKind::LinkageName; FileLineInfoKind PathStyle = FileLineInfoKind::AbsoluteFilePath; + bool SkipLineZero = false; bool UseSymbolTable = true; bool Demangle = true; bool RelativeAddresses = false; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp index f36399ed00a6e6..03d75021b39685 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -1743,8 +1743,8 @@ DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address, if (Spec.FLIKind != FileLineInfoKind::None) { if (const DWARFLineTable *LineTable = getLineTableForUnit(CU)) { LineTable->getFileLineInfoForAddress( - {Address.Address, Address.SectionIndex}, CU->getCompilationDir(), - Spec.FLIKind, Result); + {Address.Address, Address.SectionIndex}, Spec.ApproximateLine, + CU->getCompilationDir(), Spec.FLIKind, Result); } } @@ -1838,9 +1838,10 @@ DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address, if (Spec.FLIKind != FileLineInfoKind::None) { DILineInfo Frame; LineTable = getLineTableForUnit(CU); - if (LineTable && LineTable->getFileLineInfoForAddress( - {Address.Address, Address.SectionIndex}, - CU->getCompilationDir(), Spec.FLIKind, Frame)) + if (LineTable && + LineTable->getFileLineInfoForAddress( + {Address.Address, Address.SectionIndex}, Spec.ApproximateLine, + CU->getCompilationDir(), Spec.FLIKind, Frame)) InliningInfo.addFrame(Frame); } return InliningInfo; @@ -1866,8 +1867,8 @@ DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address, // For the topmost routine, get file/line info from line table. if (LineTable) LineTable->getFileLineInfoForAddress( - {Address.Address, Address.SectionIndex}, CU->getCompilationDir(), - Spec.FLIKind, Frame); + {Address.Address, Address.SectionIndex}, Spec.ApproximateLine, + CU->getCompilationDir(), Spec.FLIKind, Frame); } else { // Otherwise, use call file, call line and call column from // previous DIE in inlined chain. diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp index 572628f45fc23a..44e1789a6c5d64 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -158,13 +158,12 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS, uint32_t FileBase = getVersion() >= 5 ? 0 : 1; for (uint32_t I = 0; I != FileNames.size(); ++I) { const FileNameEntry &FileEntry = FileNames[I]; - OS << format("file_names[%3u]:\n", I + FileBase); - OS << " name: "; + OS << format("file_names[%3u]:\n", I + FileBase); + OS << " name: "; FileEntry.Name.dump(OS, DumpOptions); - OS << '\n' - << format(" dir_index: %" PRIu64 "\n", FileEntry.DirIdx); + OS << '\n' << format(" dir_index: %" PRIu64 "\n", FileEntry.DirIdx); if (ContentTypes.HasMD5) - OS << " md5_checksum: " << FileEntry.Checksum.digest() << '\n'; + OS << " md5_checksum: " << FileEntry.Checksum.digest() << '\n'; if (ContentTypes.HasModTime) OS << format(" mod_time: 0x%8.8" PRIx64 "\n", FileEntry.ModTime); if (ContentTypes.HasLength) @@ -604,9 +603,10 @@ Expected DWARFDebugLine::getOrParseLineTable( DWARFDataExtractor &DebugLineData, uint64_t Offset, const DWARFContext &Ctx, const DWARFUnit *U, function_ref RecoverableErrorHandler) { if (!DebugLineData.isValidOffset(Offset)) - return createStringError(errc::invalid_argument, "offset 0x%8.8" PRIx64 - " is not a valid debug line section offset", - Offset); + return createStringError(errc::invalid_argument, + "offset 0x%8.8" PRIx64 + " is not a valid debug line section offset", + Offset); std::pair Pos = LineTableMap.insert(LineTableMapTy::value_type(Offset, LineTable())); @@ -966,7 +966,8 @@ Error DWARFDebugLine::LineTable::parse( if (Cursor && Verbose) { *OS << " ("; - DWARFFormValue::dumpAddress(*OS, OpcodeAddressSize, State.Row.Address.Address); + DWARFFormValue::dumpAddress(*OS, OpcodeAddressSize, + State.Row.Address.Address); *OS << ')'; } } @@ -1159,8 +1160,7 @@ Error DWARFDebugLine::LineTable::parse( // DW_LNS_advance_pc. Such assemblers, however, can use // DW_LNS_fixed_advance_pc instead, sacrificing compression. { - uint16_t PCOffset = - TableData.getRelocatedValue(Cursor, 2); + uint16_t PCOffset = TableData.getRelocatedValue(Cursor, 2); if (Cursor) { State.Row.Address.Address += PCOffset; State.Row.OpIndex = 0; @@ -1312,11 +1312,12 @@ uint32_t DWARFDebugLine::LineTable::findRowInSeq( return RowPos - Rows.begin(); } -uint32_t DWARFDebugLine::LineTable::lookupAddress( - object::SectionedAddress Address) const { +uint32_t +DWARFDebugLine::LineTable::lookupAddress(object::SectionedAddress Address, + bool *IsApproximateLine) const { // Search for relocatable addresses - uint32_t Result = lookupAddressImpl(Address); + uint32_t Result = lookupAddressImpl(Address, IsApproximateLine); if (Result != UnknownRowIndex || Address.SectionIndex == object::SectionedAddress::UndefSection) @@ -1324,11 +1325,15 @@ uint32_t DWARFDebugLine::LineTable::lookupAddress( // Search for absolute addresses Address.SectionIndex = object::SectionedAddress::UndefSection; - return lookupAddressImpl(Address); + return lookupAddressImpl(Address, IsApproximateLine); } -uint32_t DWARFDebugLine::LineTable::lookupAddressImpl( - object::SectionedAddress Address) const { +uint32_t +DWARFDebugLine::LineTable::lookupAddressImpl(object::SectionedAddress Address, + bool *IsApproximateLine) const { + assert(!IsApproximateLine || + !*IsApproximateLine && "Make sure IsApproximateLine is appropriately " + "initialized, if provided"); // First, find an instruction sequence containing the given address. DWARFDebugLine::Sequence Sequence; Sequence.SectionIndex = Address.SectionIndex; @@ -1337,7 +1342,24 @@ uint32_t DWARFDebugLine::LineTable::lookupAddressImpl( DWARFDebugLine::Sequence::orderByHighPC); if (It == Sequences.end() || It->SectionIndex != Address.SectionIndex) return UnknownRowIndex; - return findRowInSeq(*It, Address); + + uint32_t RowIndex = findRowInSeq(*It, Address); + if (RowIndex == UnknownRowIndex || !IsApproximateLine) + return RowIndex; + + // Approximation will only be attempted if a valid RowIndex exists. + uint32_t ApproxRowIndex = RowIndex; + // Approximation Loop + for (; ApproxRowIndex >= It->FirstRowIndex; --ApproxRowIndex) { + if (Rows[ApproxRowIndex].Line) + return ApproxRowIndex; + *IsApproximateLine = true; + } + // Approximation Loop fails to find the valid ApproxRowIndex + if (ApproxRowIndex < It->FirstRowIndex) + *IsApproximateLine = false; + + return RowIndex; } bool DWARFDebugLine::LineTable::lookupAddressRange( @@ -1477,10 +1499,11 @@ bool DWARFDebugLine::Prologue::getFileNameByIndex( } bool DWARFDebugLine::LineTable::getFileLineInfoForAddress( - object::SectionedAddress Address, const char *CompDir, + object::SectionedAddress Address, bool Approximate, const char *CompDir, FileLineInfoKind Kind, DILineInfo &Result) const { // Get the index of row we're looking for in the line table. - uint32_t RowIndex = lookupAddress(Address); + uint32_t RowIndex = + lookupAddress(Address, Approximate ? &Result.IsApproximateLine : nullptr); if (RowIndex == -1U) return false; // Take file number and line/column from the row. diff --git a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp index 716312f26e0bac..989fde9749b183 100644 --- a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp +++ b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp @@ -131,7 +131,10 @@ void PlainPrinterBase::printFunctionName(StringRef FunctionName, bool Inlined) { void LLVMPrinter::printSimpleLocation(StringRef Filename, const DILineInfo &Info) { - OS << Filename << ':' << Info.Line << ':' << Info.Column << '\n'; + OS << Filename << ':' << Info.Line << ':' << Info.Column; + if (Info.IsApproximateLine) + OS << " " << Info.ApproxString; + OS << "\n"; printContext( SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source)); } @@ -139,6 +142,8 @@ void LLVMPrinter::printSimpleLocation(StringRef Filename, void GNUPrinter::printSimpleLocation(StringRef Filename, const DILineInfo &Info) { OS << Filename << ':' << Info.Line; + if (Info.IsApproximateLine) + OS << " " << Info.ApproxString; if (Info.Discriminator) OS << " (discriminator " << Info.Discriminator << ')'; OS << '\n'; @@ -158,6 +163,8 @@ void PlainPrinterBase::printVerbose(StringRef Filename, OS << " Column: " << Info.Column << '\n'; if (Info.Discriminator) OS << " Discriminator: " << Info.Discriminator << '\n'; + if (Info.IsApproximateLine) + OS << " Approximate: true" << '\n'; } void LLVMPrinter::printStartAddress(const DILineInfo &Info) { @@ -294,7 +301,7 @@ static json::Object toJSON(const Request &Request, StringRef ErrorMsg = "") { } static json::Object toJSON(const DILineInfo &LineInfo) { - return json::Object( + json::Object Obj = json::Object( {{"FunctionName", LineInfo.FunctionName != DILineInfo::BadString ? LineInfo.FunctionName : ""}, @@ -309,6 +316,9 @@ static json::Object toJSON(const DILineInfo &LineInfo) { {"Line", LineInfo.Line}, {"Column", LineInfo.Column}, {"Discriminator", LineInfo.Discriminator}}); + if (LineInfo.IsApproximateLine) + Obj.insert({"Approximate", LineInfo.IsApproximateLine}); + return Obj; } void JSONPrinter::print(const Request &Request, const DILineInfo &Info) { diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp index 32c5e3251df62f..9a18095edf35a8 100644 --- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp +++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp @@ -71,7 +71,9 @@ LLVMSymbolizer::symbolizeCodeCommon(const T &ModuleSpecifier, ModuleOffset.Address += Info->getModulePreferredBase(); DILineInfo LineInfo = Info->symbolizeCode( - ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions), + ModuleOffset, + DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions, + Opts.SkipLineZero), Opts.UseSymbolTable); if (Opts.Demangle) LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info); @@ -116,7 +118,9 @@ Expected LLVMSymbolizer::symbolizeInlinedCodeCommon( ModuleOffset.Address += Info->getModulePreferredBase(); DIInliningInfo InlinedContext = Info->symbolizeInlinedCode( - ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions), + ModuleOffset, + DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions, + Opts.SkipLineZero), Opts.UseSymbolTable); if (Opts.Demangle) { for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) { diff --git a/llvm/test/tools/llvm-symbolizer/skip-line-zero.s b/llvm/test/tools/llvm-symbolizer/skip-line-zero.s new file mode 100644 index 00000000000000..e194cda8005bf2 --- /dev/null +++ b/llvm/test/tools/llvm-symbolizer/skip-line-zero.s @@ -0,0 +1,143 @@ +## Test the "--skip-line-zero" option. +## +## This test uses handcrafted assembly to produce the following line table: +## Address Line Column File ISA Discriminator OpIndex Flags +## ------------------ ------ ------ ------ --- ------------- ------- ------------- +## 0x0000000000001710 1 0 1 0 0 0 +## 0x0000000000001714 0 0 1 0 0 0 +## 0x0000000000001719 1 2 1 0 0 0 +## 0x000000000000171b 1 2 1 0 0 0 end_sequence +## 0x00000000000016c0 0 0 1 0 0 0 +## 0x00000000000016cf 2 0 1 0 0 0 +## 0x00000000000016d4 0 0 1 0 0 0 +## 0x00000000000016d9 0 0 1 0 0 0 +## 0x00000000000016df 0 0 1 0 0 0 end_sequence + +# REQUIRES: x86-registered-target + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o + +## Check that without '--skip-line-zero', line zero is displayed for a line-table entry which has no source correspondence. +# RUN: llvm-symbolizer --obj=%t.o -f=none 0x16d4 | FileCheck --strict-whitespace --match-full-lines --check-prefix=DISABLE %s + +# DISABLE:main.c:0:0 + +## Check that the '--skip-line-zero' does not cross sequence boundaries. +## If it fails to find in the current sequence then line zero is returned for the queried address. +# RUN: llvm-symbolizer --obj=%t.o -f=none --skip-line-zero 0x16c0 | FileCheck --strict-whitespace --match-full-lines --check-prefix=FAIL-ACROSS-SEQ %s + +# FAIL-ACROSS-SEQ:main.c:0:0 + +## Check that with '--skip-line-zero', the last non-zero line in the current sequence is displayed. +# RUN: llvm-symbolizer --obj=%t.o -f=none --skip-line-zero 0x1717 | FileCheck --strict-whitespace --match-full-lines --check-prefix=WITHIN-SEQ %s + +# WITHIN-SEQ:main.c:1:0 (approximate) + +## Check that with '--skip-line-zero', multiple line zero rows are skipped within the current sequence. +# RUN: llvm-symbolizer --obj=%t.o -f=none --skip-line-zero 0x16d9 | FileCheck --strict-whitespace --match-full-lines --check-prefix=MULTIPLE-ROWS %s + +# MULTIPLE-ROWS:main.c:2:0 (approximate) + +## Check that '--skip-line-zero' only affects the line zero addresses when more than one address is specified. +# RUN: llvm-symbolizer --obj=%t.o -f=none --skip-line-zero 0x16d4 0x1719 | FileCheck --strict-whitespace --match-full-lines --check-prefixes=ENABLE,NO-APPROX %s + +# ENABLE:main.c:2:0 (approximate) +# NO-APPROX:main.c:1:2 + +## Check to ensure that '--skip-line-zero' with '--verbose' enabled displays approximate flag in verbose ouptut. +# RUN: llvm-symbolizer --obj=%t.o -f=none --skip-line-zero --verbose 0x1717 | FileCheck --strict-whitespace --match-full-lines --check-prefix=VERBOSE %s + +# VERBOSE: Filename: main.c +# VERBOSE-NEXT: Line: 1 +# VERBOSE-NEXT: Column: 0 +# VERBOSE-NEXT: Approximate: true + +## Check to ensure that '--skip-line-zero' with '--output-style=JSON' displays approximate flag in JSON output. +# RUN: llvm-symbolizer --obj=%t.o -f=none --skip-line-zero --output-style=JSON 0x1717 | FileCheck --strict-whitespace --match-full-lines --check-prefix=JSON %s + +# JSON:[{"Address":"0x1717","ModuleName":"{{.*}}{{[/|\]+}}test{{[/|\]+}}tools{{[/|\]+}}llvm-symbolizer{{[/|\]+}}Output{{[/|\]+}}skip-line-zero.s.tmp.o","Symbol":[{"Approximate":true,"Column":0,"Discriminator":0,"FileName":"main.c","FunctionName":"","Line":1,"StartAddress":"","StartFileName":"","StartLine":0}]}] + +## main.c +## __attribute__((section("def"))) int foo() { return 1234; } +## int main(void) { return foo()+5678; } +## +## Generated using +## clang -S -gdwarf-4 --target=x86_64-pc-linux -fdebug-prefix-map=/tmp="" main.c -o main.s +## +## Sections belonging to code segment(.text) are removed. Sections related to debug information(other than .debug_line) are modified. Section .debug_line is handwritten. Section .debug_str is deleted. + + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x55 DW_TAG_compile_unit + .long .Lline_table_start0 # DW_AT_stmt_list + .quad 0 # DW_AT_low_pc + .long .Ldebug_ranges0 # DW_AT_ranges + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + .section .debug_ranges,"",@progbits +.Ldebug_ranges0: + .quad 0x1710 #.Lfunc_begin0 + .quad 0x171b #.Lfunc_end0 + .quad 0x16c0 #.Lfunc_begin1 + .quad 0x16df #.Lfunc_end1 + .quad 0 + .quad 0 + .section .debug_line,"",@progbits +.Lline_table_start0: + .long .Lunit_end - .Lunit_start # unit length +.Lunit_start: + .short 4 # version + .long .Lprologue_end - .Lprologue_start # header length +.Lprologue_start: + .byte 1 # minimum_instruction_length + .byte 1 # maximum_operations_per_instruction + .byte 0 # default_is_stmt + .byte -5 # line_base + .byte 14 # line_range + .byte 13 # opcode_base + .byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # arguments in standard opcodes + .byte 0 # end of include directories + .asciz "main.c" # filename + .byte 0 # directory index + .byte 0 # modification time + .byte 0 # length of file (unavailable) + .byte 0 # end of filenames +.Lprologue_end: + .byte 0x00, 9, 2 # DW_LNE_set_address + .quad 0x1710 # Address Value + .byte 0x01 # DW_LNS_copy + .byte 0x49 # (address += 4, line += -1, op-index += 0) + .byte 0x05, 2 # DW_LNS_set_column (2) + .byte 0x59 # (address += 5, line += 1, op-index += 0) + .byte 0x02 # DW_LNS_advance_pc + .uleb128 0x02 # (addr += 2, op-index += 0) + .byte 0x00, 1, 1 # DW_LNE_end_sequence + .byte 0x00, 9, 2 # DW_LNE_set_address + .quad 0x16c0 # Address Value + .byte 0x11 # (address += 0, line += -1, op-index += 0) + .byte 0xe6 # (address += 15, line += 2, op-index += 0) + .byte 0x56 # (address += 5, line += -2, op-index += 0) + .byte 0x58 # (address += 5, line += 0, op-index += 0) + .byte 0x02 # DW_LNS_advance_pc + .uleb128 0x06 # (addr += 6, op-index += 0) + .byte 0x00, 1, 1 # DW_LNE_end_sequence +.Lunit_end: + diff --git a/llvm/tools/llvm-symbolizer/Opts.td b/llvm/tools/llvm-symbolizer/Opts.td index edc80bfe59673b..d0b227af9db464 100644 --- a/llvm/tools/llvm-symbolizer/Opts.td +++ b/llvm/tools/llvm-symbolizer/Opts.td @@ -55,6 +55,7 @@ def pretty_print : F<"pretty-print", "Make the output more human friendly">; defm print_source_context_lines : Eq<"print-source-context-lines", "Print N lines of source file context">; def relative_address : F<"relative-address", "Interpret addresses as addresses relative to the image base">; def relativenames : F<"relativenames", "Strip the compilation directory from paths">; +def skip_line_zero : F<"skip-line-zero","If an address does not have an associated line number, use the last line number from the current sequence in the line-table">; defm untag_addresses : B<"untag-addresses", "", "Remove memory tags from addresses before symbolization">; def use_dia: F<"dia", "Use the DIA library to access symbols (Windows only)">; def verbose : F<"verbose", "Print verbose line info">; diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp index 6d7953f3109a57..3e41a85d646956 100644 --- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp +++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -490,6 +490,7 @@ int llvm_symbolizer_main(int argc, char **argv, const llvm::ToolContext &) { } else { Opts.PathStyle = DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath; } + Opts.SkipLineZero = Args.hasArg(OPT_skip_line_zero); Opts.DebugFileDirectory = Args.getAllArgValues(OPT_debug_file_directory_EQ); Opts.DefaultArch = Args.getLastArgValue(OPT_default_arch_EQ).str(); Opts.Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, !IsAddr2Line);