mirror of
https://github.com/RPCS3/llvm.git
synced 2024-11-23 19:59:48 +00:00
[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:
parent
808e1a5000
commit
23c8a3ba6c
@ -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 {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -521,7 +521,7 @@ void FileAnalysis::parseSectionContents(ArrayRef<uint8_t> SectionBytes,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (LineInfo->FileName == "<invalid>")
|
||||
if (LineInfo->FileName == DILineInfo::BadString)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user