[lld] 0886440 - [Symbolizer] Support for Missing Line Numbers. (#82240)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 5 01:08:37 PDT 2024
Author: Amit Kumar Pandey
Date: 2024-08-05T13:38:34+05:30
New Revision: 0886440ef0ed0ad553522b731c841b81dc36944c
URL: https://github.com/llvm/llvm-project/commit/0886440ef0ed0ad553522b731c841b81dc36944c
DIFF: https://github.com/llvm/llvm-project/commit/0886440ef0ed0ad553522b731c841b81dc36944c.diff
LOG: [Symbolizer] Support for Missing Line Numbers. (#82240)
LLVM Symbolizer attempt to symbolize addresses of optimized binaries
reports missing line numbers for some cases. It maybe due to compiler
which sometimes cannot map an instruction to line number due to
optimizations. Symbolizer should handle those cases gracefully.
Adding an option '--skip-line-zero' to symbolizer so as to report the
nearest non-zero line number.
---------
Co-authored-by: Amit Pandey <amit.pandey at amd.com>
Added:
llvm/test/tools/llvm-symbolizer/skip-line-zero.s
Modified:
lld/Common/DWARF.cpp
llvm/docs/CommandGuide/llvm-symbolizer.rst
llvm/include/llvm/DebugInfo/DIContext.h
llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
llvm/tools/llvm-symbolizer/Opts.td
llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
Removed:
################################################################################
diff --git a/lld/Common/DWARF.cpp b/lld/Common/DWARF.cpp
index 2cd8ca4575dee..728021b78c414 100644
--- a/lld/Common/DWARF.cpp
+++ b/lld/Common/DWARF.cpp
@@ -93,7 +93,7 @@ std::optional<DILineInfo> 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 59c0ab6d196ac..2da1b2470a83e 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 b75dc8db54336..71685ba09d8db 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 "<invalid>" for function/filename it cannot fetch.
static constexpr const char *const BadString = "<invalid>";
// Use "??" instead of "<invalid>" 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 ce3bae6a1760c..ff7bf87d8e6b5 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<uint32_t> &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<uint32_t> &Result) const;
diff --git a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
index 11a169cfc20a6..bd8de070f84c5 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 f36399ed00a6e..03d75021b3968 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 572628f45fc23..44e1789a6c5d6 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<const DWARFDebugLine::LineTable *> DWARFDebugLine::getOrParseLineTable(
DWARFDataExtractor &DebugLineData, uint64_t Offset, const DWARFContext &Ctx,
const DWARFUnit *U, function_ref<void(Error)> 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<LineTableIter, bool> 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 716312f26e0ba..989fde9749b18 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 32c5e3251df62..9a18095edf35a 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<DIInliningInfo> 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 0000000000000..e194cda8005bf
--- /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,"", at 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,"", at 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,"", at 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,"", at 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 edc80bfe59673..d0b227af9db46 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 6d7953f3109a5..3e41a85d64695 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);
More information about the llvm-commits
mailing list