[llvm-objdump] Add warning messages if disassembly + source for problematic inputs

Summary: Addresses https://bugs.llvm.org/show_bug.cgi?id=41905

Reviewers: jhenderson, rupprecht, grimar

Reviewed By: jhenderson, grimar

Subscribers: RKSimon, MaskRay, hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D62462

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@368963 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Michael Pozulp 2019-08-15 05:15:22 +00:00
parent 808e1a5000
commit 23c8a3ba6c
10 changed files with 81 additions and 50 deletions

View File

@ -28,6 +28,10 @@ namespace llvm {
/// A format-neutral container for source line information.
struct DILineInfo {
// 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.
static constexpr const char *const Addr2LineBadString = "??";
std::string FileName;
std::string FunctionName;
Optional<StringRef> Source;
@ -38,7 +42,7 @@ struct DILineInfo {
// DWARF-specific.
uint32_t Discriminator = 0;
DILineInfo() : FileName("<invalid>"), FunctionName("<invalid>") {}
DILineInfo() : FileName(BadString), FunctionName(BadString) {}
bool operator==(const DILineInfo &RHS) const {
return Line == RHS.Line && Column == RHS.Column &&
@ -61,9 +65,9 @@ struct DILineInfo {
void dump(raw_ostream &OS) {
OS << "Line info: ";
if (FileName != "<invalid>")
if (FileName != BadString)
OS << "file '" << FileName << "', ";
if (FunctionName != "<invalid>")
if (FunctionName != BadString)
OS << "function '" << FunctionName << "', ";
OS << "line " << Line << ", ";
OS << "column " << Column << ", ";
@ -109,7 +113,7 @@ struct DIGlobal {
uint64_t Start = 0;
uint64_t Size = 0;
DIGlobal() : Name("<invalid>") {}
DIGlobal() : Name(DILineInfo::BadString) {}
};
struct DILocal {

View File

@ -1111,8 +1111,8 @@ DILineInfoTable DWARFContext::getLineInfoForAddressRange(
if (!CU)
return Lines;
std::string FunctionName = "<invalid>";
uint32_t StartLine = 0;
std::string FunctionName(DILineInfo::BadString);
getFunctionNameAndStartLineForAddress(CU, Address.Address, Spec.FNKind,
FunctionName, StartLine);

View File

@ -30,11 +30,6 @@
namespace llvm {
namespace symbolize {
// By default, DILineInfo contains "<invalid>" for function/filename it
// cannot fetch. We replace it to "??" to make our output closer to addr2line.
static const char kDILineInfoBadString[] = "<invalid>";
static const char kBadString[] = "??";
// Prints source code around in the FileName the Line.
void DIPrinter::printContext(const std::string &FileName, int64_t Line) {
if (PrintSourceContext <= 0)
@ -68,16 +63,16 @@ void DIPrinter::printContext(const std::string &FileName, int64_t Line) {
void DIPrinter::print(const DILineInfo &Info, bool Inlined) {
if (PrintFunctionNames) {
std::string FunctionName = Info.FunctionName;
if (FunctionName == kDILineInfoBadString)
FunctionName = kBadString;
if (FunctionName == DILineInfo::BadString)
FunctionName = DILineInfo::Addr2LineBadString;
StringRef Delimiter = PrintPretty ? " at " : "\n";
StringRef Prefix = (PrintPretty && Inlined) ? " (inlined by) " : "";
OS << Prefix << FunctionName << Delimiter;
}
std::string Filename = Info.FileName;
if (Filename == kDILineInfoBadString)
Filename = kBadString;
if (Filename == DILineInfo::BadString)
Filename = DILineInfo::Addr2LineBadString;
else if (Basenames)
Filename = llvm::sys::path::filename(Filename);
if (!Verbose) {
@ -115,8 +110,8 @@ DIPrinter &DIPrinter::operator<<(const DIInliningInfo &Info) {
DIPrinter &DIPrinter::operator<<(const DIGlobal &Global) {
std::string Name = Global.Name;
if (Name == kDILineInfoBadString)
Name = kBadString;
if (Name == DILineInfo::BadString)
Name = DILineInfo::Addr2LineBadString;
OS << Name << "\n";
OS << Global.Start << " " << Global.Size << "\n";
return *this;

View File

@ -1,5 +1,5 @@
## Test llvm-objdump's --source behaviour when a line number is greater than the
## file length.
## file length and ensure that we emit a warning.
# RUN: sed -e "s,SRC_COMPDIR,%/p/Inputs,g" %p/Inputs/source-interleave.ll > %t.ll
# RUN: sed -e "s,line: 7,line: 9999,g" %t.ll > %t2.ll
@ -8,9 +8,11 @@
# RUN: llc -o %t2.o -filetype=obj -mtriple=x86_64-pc-linux %t2.ll
# RUN: llvm-objdump --source %t.o | FileCheck %s --check-prefixes=CHECK,GOOD
# RUN: llvm-objdump --source %t2.o | FileCheck %s --implicit-check-not="int *b = &a;"
# RUN: llvm-objdump --source %t2.o 2> %t2.e | FileCheck %s --check-prefixes=CHECK --implicit-check-not="int *b = &a;"
# RUN: FileCheck %s --input-file %t2.e --check-prefixes=WARN
# CHECK: main:
# CHECK-NEXT: ; int main() {
# WARN: warning: debug info line number 9999 exceeds the number of lines in {{.*}}source-interleave-x86_64.c
# GOOD: ; int *b = &a;
# CHECK: ; return *b + foo();

View File

@ -1,5 +1,5 @@
## Test that if the source cannot be found that disassembly is still printed,
## and that no source is printed.
## that no source is printed, and that we emit a warning.
# RUN: sed -e "s,SRC_COMPDIR,%/t,g" %p/Inputs/source-interleave.ll > %t.ll
# RUN: sed -e "s,SRC_COMPDIR,%/p/Inputs,g" %p/Inputs/source-interleave.ll > %t2.ll
@ -7,9 +7,11 @@
# RUN: llc -o %t.o -filetype=obj -mtriple=x86_64-pc-linux %t.ll
# RUN: llc -o %t2.o -filetype=obj -mtriple=x86_64-pc-linux %t2.ll
# RUN: llvm-objdump --source %t.o | FileCheck %s --implicit-check-not='main()'
# RUN: llvm-objdump --source %t.o 2> %t.e | FileCheck %s --check-prefixes=CHECK --implicit-check-not='main()'
# RUN: llvm-objdump --source %t2.o | FileCheck %s --check-prefixes=CHECK,SOURCE
# RUN: FileCheck %s --input-file %t.e --check-prefixes=WARN
# WARN: warning: failed to find source {{.*}}source-interleave-x86_64.c
# CHECK: 0000000000000010 main:
# SOURCE-NEXT: ; int main() {
# CHECK-NEXT: 10: 55 pushq %rbp

View File

@ -1,13 +1,15 @@
## Test that if an object has no debug information, only the disassembly is
## printed when --source is specified.
## printed when --source is specified, and that we emit a warning.
# RUN: sed -e "s,SRC_COMPDIR,%/p/Inputs,g" %p/Inputs/source-interleave.ll > %t.ll
# RUN: llc -o %t.o -filetype=obj -mtriple=x86_64-pc-linux %t.ll
# RUN: llvm-objcopy --strip-debug %t.o %t2.o
# RUN: llvm-objdump --source %t.o | FileCheck %s --check-prefixes=CHECK,SOURCE
# RUN: llvm-objdump --source %t2.o | FileCheck %s --implicit-check-not='main()'
# RUN: llvm-objdump --source %t2.o 2> %t2.e | FileCheck %s --check-prefixes=CHECK --implicit-check-not='main()'
# RUN: FileCheck %s --input-file %t2.e --check-prefixes=WARN
# WARN: warning: failed to parse debug information for {{.*}}2.o
# CHECK: 0000000000000010 main:
# SOURCE-NEXT: ; int main() {
# CHECK-NEXT: 10: 55 pushq %rbp

View File

@ -521,7 +521,7 @@ void FileAnalysis::parseSectionContents(ArrayRef<uint8_t> SectionBytes,
continue;
}
if (LineInfo->FileName == "<invalid>")
if (LineInfo->FileName == DILineInfo::BadString)
continue;
}

View File

@ -51,6 +51,7 @@
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/InitLLVM.h"
@ -385,12 +386,7 @@ LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
exit(1);
}
void warn(StringRef Message) {
WithColor::warning(errs(), ToolName) << Message << ".\n";
errs().flush();
}
static void warn(Twine Message) {
void warn(Twine Message) {
// Output order between errs() and outs() matters especially for archive
// files where the output is per member object.
outs().flush();
@ -552,17 +548,22 @@ protected:
DILineInfo OldLineInfo;
const ObjectFile *Obj = nullptr;
std::unique_ptr<symbolize::LLVMSymbolizer> Symbolizer;
// File name to file contents of source
// File name to file contents of source.
std::unordered_map<std::string, std::unique_ptr<MemoryBuffer>> SourceCache;
// Mark the line endings of the cached source
// Mark the line endings of the cached source.
std::unordered_map<std::string, std::vector<StringRef>> LineCache;
// Keep track of missing sources.
StringSet<> MissingSources;
// Only emit 'no debug info' warning once.
bool WarnedNoDebugInfo;
private:
bool cacheSource(const DILineInfo& LineInfoFile);
public:
SourcePrinter() = default;
SourcePrinter(const ObjectFile *Obj, StringRef DefaultArch) : Obj(Obj) {
SourcePrinter(const ObjectFile *Obj, StringRef DefaultArch)
: Obj(Obj), WarnedNoDebugInfo(false) {
symbolize::LLVMSymbolizer::Options SymbolizerOpts;
SymbolizerOpts.PrintFunctions = DILineInfoSpecifier::FunctionNameKind::None;
SymbolizerOpts.Demangle = false;
@ -572,6 +573,7 @@ public:
virtual ~SourcePrinter() = default;
virtual void printSourceLine(raw_ostream &OS,
object::SectionedAddress Address,
StringRef ObjectFilename,
StringRef Delimiter = "; ");
};
@ -581,8 +583,12 @@ bool SourcePrinter::cacheSource(const DILineInfo &LineInfo) {
Buffer = MemoryBuffer::getMemBuffer(*LineInfo.Source);
} else {
auto BufferOrError = MemoryBuffer::getFile(LineInfo.FileName);
if (!BufferOrError)
if (!BufferOrError) {
if (MissingSources.insert(LineInfo.FileName).second)
warn("failed to find source " + LineInfo.FileName);
return false;
}
Buffer = std::move(*BufferOrError);
}
// Chomp the file to get lines
@ -603,20 +609,33 @@ bool SourcePrinter::cacheSource(const DILineInfo &LineInfo) {
void SourcePrinter::printSourceLine(raw_ostream &OS,
object::SectionedAddress Address,
StringRef ObjectFilename,
StringRef Delimiter) {
if (!Symbolizer)
return;
DILineInfo LineInfo = DILineInfo();
auto ExpectedLineInfo = Symbolizer->symbolizeCode(*Obj, Address);
std::string ErrorMessage;
if (!ExpectedLineInfo)
consumeError(ExpectedLineInfo.takeError());
ErrorMessage = toString(ExpectedLineInfo.takeError());
else
LineInfo = *ExpectedLineInfo;
if ((LineInfo.FileName == "<invalid>") || LineInfo.Line == 0 ||
((OldLineInfo.Line == LineInfo.Line) &&
(OldLineInfo.FileName == LineInfo.FileName)))
if (LineInfo.FileName == DILineInfo::BadString) {
if (!WarnedNoDebugInfo) {
std::string Warning =
"failed to parse debug information for " + ObjectFilename.str();
if (!ErrorMessage.empty())
Warning += ": " + ErrorMessage;
warn(Warning);
WarnedNoDebugInfo = true;
}
return;
}
if (LineInfo.Line == 0 || ((OldLineInfo.Line == LineInfo.Line) &&
(OldLineInfo.FileName == LineInfo.FileName)))
return;
if (PrintLines)
@ -627,8 +646,12 @@ void SourcePrinter::printSourceLine(raw_ostream &OS,
return;
auto LineBuffer = LineCache.find(LineInfo.FileName);
if (LineBuffer != LineCache.end()) {
if (LineInfo.Line > LineBuffer->second.size())
if (LineInfo.Line > LineBuffer->second.size()) {
warn(formatv(
"debug info line number {0} exceeds the number of lines in {1}",
LineInfo.Line, LineInfo.FileName));
return;
}
// Vector begins at 0, line numbers are non-zero
OS << Delimiter << LineBuffer->second[LineInfo.Line - 1] << '\n';
}
@ -667,10 +690,10 @@ public:
ArrayRef<uint8_t> Bytes,
object::SectionedAddress Address, raw_ostream &OS,
StringRef Annot, MCSubtargetInfo const &STI,
SourcePrinter *SP,
SourcePrinter *SP, StringRef ObjectFilename,
std::vector<RelocationRef> *Rels = nullptr) {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address);
SP->printSourceLine(OS, Address, ObjectFilename);
size_t Start = OS.tell();
if (!NoLeadingAddr)
@ -711,9 +734,10 @@ public:
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
object::SectionedAddress Address, raw_ostream &OS,
StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
StringRef ObjectFilename,
std::vector<RelocationRef> *Rels) override {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address, "");
SP->printSourceLine(OS, Address, ObjectFilename, "");
if (!MI) {
printLead(Bytes, Address.Address, OS);
OS << " <unknown>";
@ -750,7 +774,7 @@ public:
OS << Separator;
Separator = "\n";
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address, "");
SP->printSourceLine(OS, Address, ObjectFilename, "");
printLead(Bytes, Address.Address, OS);
OS << Preamble;
Preamble = " ";
@ -780,9 +804,10 @@ public:
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
object::SectionedAddress Address, raw_ostream &OS,
StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
StringRef ObjectFilename,
std::vector<RelocationRef> *Rels) override {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address);
SP->printSourceLine(OS, Address, ObjectFilename);
if (MI) {
SmallString<40> InstStr;
@ -831,9 +856,10 @@ public:
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
object::SectionedAddress Address, raw_ostream &OS,
StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
StringRef ObjectFilename,
std::vector<RelocationRef> *Rels) override {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address);
SP->printSourceLine(OS, Address, ObjectFilename);
if (!NoLeadingAddr)
OS << format("%8" PRId64 ":", Address.Address / 8);
if (!NoShowRawInsn) {
@ -1382,10 +1408,10 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
if (Size == 0)
Size = 1;
PIP.printInst(
*IP, Disassembled ? &Inst : nullptr, Bytes.slice(Index, Size),
{SectionAddr + Index + VMAAdjustment, Section.getIndex()}, outs(),
"", *STI, &SP, &Rels);
PIP.printInst(*IP, Disassembled ? &Inst : nullptr,
Bytes.slice(Index, Size),
{SectionAddr + Index + VMAAdjustment, Section.getIndex()},
outs(), "", *STI, &SP, Obj->getFileName(), &Rels);
outs() << CommentStream.str();
Comments.clear();

View File

@ -129,7 +129,7 @@ void printSectionHeaders(const object::ObjectFile *O);
void printSectionContents(const object::ObjectFile *O);
void printSymbolTable(const object::ObjectFile *O, StringRef ArchiveName,
StringRef ArchitectureName = StringRef());
void warn(StringRef Message);
void warn(Twine Message);
LLVM_ATTRIBUTE_NORETURN void error(Twine Message);
LLVM_ATTRIBUTE_NORETURN void report_error(StringRef File, Twine Message);
LLVM_ATTRIBUTE_NORETURN void report_error(Error E, StringRef File);

View File

@ -36,7 +36,7 @@ std::string FuncIdConversionHelper::SymbolOrNumber(int32_t FuncId) const {
ModuleAddress.SectionIndex = object::SectionedAddress::UndefSection;
if (auto ResOrErr = Symbolizer.symbolizeCode(BinaryInstrMap, ModuleAddress)) {
auto &DI = *ResOrErr;
if (DI.FunctionName == "<invalid>")
if (DI.FunctionName == DILineInfo::BadString)
F << "@(" << std::hex << It->second << ")";
else
F << DI.FunctionName;