[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@amd.com>
This commit is contained in:
parent
fc83e97f6e
commit
0886440ef0
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -240,7 +240,8 @@ public:
|
||||
|
||||
/// 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 @@ public:
|
||||
/// 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 @@ public:
|
||||
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;
|
||||
|
||||
@ -52,6 +52,7 @@ public:
|
||||
struct Options {
|
||||
FunctionNameKind PrintFunctions = FunctionNameKind::LinkageName;
|
||||
FileLineInfoKind PathStyle = FileLineInfoKind::AbsoluteFilePath;
|
||||
bool SkipLineZero = false;
|
||||
bool UseSymbolTable = true;
|
||||
bool Demangle = true;
|
||||
bool RelativeAddresses = false;
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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++) {
|
||||
|
||||
143
llvm/test/tools/llvm-symbolizer/skip-line-zero.s
Normal file
143
llvm/test/tools/llvm-symbolizer/skip-line-zero.s
Normal file
@ -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:
|
||||
|
||||
@ -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">;
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user