Skip to content

[Symbolizer] Support for Missing Line Numbers. #82240

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lld/Common/DWARF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
33 changes: 33 additions & 0 deletions llvm/docs/CommandGuide/llvm-symbolizer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
-------

Expand All @@ -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
Expand Down
9 changes: 6 additions & 3 deletions llvm/include/llvm/DebugInfo/DIContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -50,6 +51,7 @@ struct DILineInfo {
// DWARF-specific.
uint32_t Discriminator = 0;

bool IsApproximateLine = false;
DILineInfo()
: FileName(BadString), FunctionName(BadString), StartFileName(BadString) {
}
Expand Down Expand Up @@ -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;
Expand Down
8 changes: 5 additions & 3 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
15 changes: 8 additions & 7 deletions llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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;
Expand All @@ -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.
Expand Down
63 changes: 43 additions & 20 deletions llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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()));
Expand Down Expand Up @@ -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 << ')';
}
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1312,23 +1312,28 @@ 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)
return Result;

// 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;
Expand All @@ -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(
Expand Down Expand Up @@ -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.
Expand Down
14 changes: 12 additions & 2 deletions llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,19 @@ 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));
}

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';
Expand All @@ -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) {
Expand Down Expand Up @@ -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
: ""},
Expand All @@ -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) {
Expand Down
8 changes: 6 additions & 2 deletions llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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++) {
Expand Down
Loading