llvm.org GIT mirror llvm / 23c8a3b
[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 Michael Pozulp a month ago
10 changed file(s) with 81 addition(s) and 50 deletion(s). Raw diff Collapse all Expand all
2727
2828 /// A format-neutral container for source line information.
2929 struct DILineInfo {
30 // DILineInfo contains "" for function/filename it cannot fetch.
31 static constexpr const char *const BadString = "";
32 // Use "??" instead of "" to make our output closer to addr2line.
33 static constexpr const char *const Addr2LineBadString = "??";
3034 std::string FileName;
3135 std::string FunctionName;
3236 Optional Source;
3741 // DWARF-specific.
3842 uint32_t Discriminator = 0;
3943
40 DILineInfo() : FileName(""), FunctionName("") {}
44 DILineInfo() : FileName(BadString), FunctionName(BadString) {}
4145
4246 bool operator==(const DILineInfo &RHS) const {
4347 return Line == RHS.Line && Column == RHS.Column &&
6064
6165 void dump(raw_ostream &OS) {
6266 OS << "Line info: ";
63 if (FileName != "")
67 if (FileName != BadString)
6468 OS << "file '" << FileName << "', ";
65 if (FunctionName != "")
69 if (FunctionName != BadString)
6670 OS << "function '" << FunctionName << "', ";
6771 OS << "line " << Line << ", ";
6872 OS << "column " << Column << ", ";
108112 uint64_t Start = 0;
109113 uint64_t Size = 0;
110114
111 DIGlobal() : Name("") {}
115 DIGlobal() : Name(DILineInfo::BadString) {}
112116 };
113117
114118 struct DILocal {
11101110 if (!CU)
11111111 return Lines;
11121112
1113 std::string FunctionName = "";
11141113 uint32_t StartLine = 0;
1114 std::string FunctionName(DILineInfo::BadString);
11151115 getFunctionNameAndStartLineForAddress(CU, Address.Address, Spec.FNKind,
11161116 FunctionName, StartLine);
11171117
2828
2929 namespace llvm {
3030 namespace symbolize {
31
32 // By default, DILineInfo contains "" for function/filename it
33 // cannot fetch. We replace it to "??" to make our output closer to addr2line.
34 static const char kDILineInfoBadString[] = "";
35 static const char kBadString[] = "??";
3631
3732 // Prints source code around in the FileName the Line.
3833 void DIPrinter::printContext(const std::string &FileName, int64_t Line) {
6762 void DIPrinter::print(const DILineInfo &Info, bool Inlined) {
6863 if (PrintFunctionNames) {
6964 std::string FunctionName = Info.FunctionName;
70 if (FunctionName == kDILineInfoBadString)
71 FunctionName = kBadString;
65 if (FunctionName == DILineInfo::BadString)
66 FunctionName = DILineInfo::Addr2LineBadString;
7267
7368 StringRef Delimiter = PrintPretty ? " at " : "\n";
7469 StringRef Prefix = (PrintPretty && Inlined) ? " (inlined by) " : "";
7570 OS << Prefix << FunctionName << Delimiter;
7671 }
7772 std::string Filename = Info.FileName;
78 if (Filename == kDILineInfoBadString)
79 Filename = kBadString;
73 if (Filename == DILineInfo::BadString)
74 Filename = DILineInfo::Addr2LineBadString;
8075 else if (Basenames)
8176 Filename = llvm::sys::path::filename(Filename);
8277 if (!Verbose) {
114109
115110 DIPrinter &DIPrinter::operator<<(const DIGlobal &Global) {
116111 std::string Name = Global.Name;
117 if (Name == kDILineInfoBadString)
118 Name = kBadString;
112 if (Name == DILineInfo::BadString)
113 Name = DILineInfo::Addr2LineBadString;
119114 OS << Name << "\n";
120115 OS << Global.Start << " " << Global.Size << "\n";
121116 return *this;
0 ## Test llvm-objdump's --source behaviour when a line number is greater than the
1 ## file length.
1 ## file length and ensure that we emit a warning.
22
33 # RUN: sed -e "s,SRC_COMPDIR,%/p/Inputs,g" %p/Inputs/source-interleave.ll > %t.ll
44 # RUN: sed -e "s,line: 7,line: 9999,g" %t.ll > %t2.ll
77 # RUN: llc -o %t2.o -filetype=obj -mtriple=x86_64-pc-linux %t2.ll
88
99 # RUN: llvm-objdump --source %t.o | FileCheck %s --check-prefixes=CHECK,GOOD
10 # RUN: llvm-objdump --source %t2.o | FileCheck %s --implicit-check-not="int *b = &a;"
10 # RUN: llvm-objdump --source %t2.o 2> %t2.e | FileCheck %s --check-prefixes=CHECK --implicit-check-not="int *b = &a;"
11 # RUN: FileCheck %s --input-file %t2.e --check-prefixes=WARN
1112
1213 # CHECK: main:
1314 # CHECK-NEXT: ; int main() {
15 # WARN: warning: debug info line number 9999 exceeds the number of lines in {{.*}}source-interleave-x86_64.c
1416 # GOOD: ; int *b = &a;
1517 # CHECK: ; return *b + foo();
0 ## Test that if the source cannot be found that disassembly is still printed,
1 ## and that no source is printed.
1 ## that no source is printed, and that we emit a warning.
22
33 # RUN: sed -e "s,SRC_COMPDIR,%/t,g" %p/Inputs/source-interleave.ll > %t.ll
44 # RUN: sed -e "s,SRC_COMPDIR,%/p/Inputs,g" %p/Inputs/source-interleave.ll > %t2.ll
66 # RUN: llc -o %t.o -filetype=obj -mtriple=x86_64-pc-linux %t.ll
77 # RUN: llc -o %t2.o -filetype=obj -mtriple=x86_64-pc-linux %t2.ll
88
9 # RUN: llvm-objdump --source %t.o | FileCheck %s --implicit-check-not='main()'
9 # RUN: llvm-objdump --source %t.o 2> %t.e | FileCheck %s --check-prefixes=CHECK --implicit-check-not='main()'
1010 # RUN: llvm-objdump --source %t2.o | FileCheck %s --check-prefixes=CHECK,SOURCE
11 # RUN: FileCheck %s --input-file %t.e --check-prefixes=WARN
1112
13 # WARN: warning: failed to find source {{.*}}source-interleave-x86_64.c
1214 # CHECK: 0000000000000010 main:
1315 # SOURCE-NEXT: ; int main() {
1416 # CHECK-NEXT: 10: 55 pushq %rbp
0 ## Test that if an object has no debug information, only the disassembly is
1 ## printed when --source is specified.
1 ## printed when --source is specified, and that we emit a warning.
22
33 # RUN: sed -e "s,SRC_COMPDIR,%/p/Inputs,g" %p/Inputs/source-interleave.ll > %t.ll
44 # RUN: llc -o %t.o -filetype=obj -mtriple=x86_64-pc-linux %t.ll
55 # RUN: llvm-objcopy --strip-debug %t.o %t2.o
66
77 # RUN: llvm-objdump --source %t.o | FileCheck %s --check-prefixes=CHECK,SOURCE
8 # RUN: llvm-objdump --source %t2.o | FileCheck %s --implicit-check-not='main()'
8 # RUN: llvm-objdump --source %t2.o 2> %t2.e | FileCheck %s --check-prefixes=CHECK --implicit-check-not='main()'
9 # RUN: FileCheck %s --input-file %t2.e --check-prefixes=WARN
910
11 # WARN: warning: failed to parse debug information for {{.*}}2.o
1012 # CHECK: 0000000000000010 main:
1113 # SOURCE-NEXT: ; int main() {
1214 # CHECK-NEXT: 10: 55 pushq %rbp
520520 continue;
521521 }
522522
523 if (LineInfo->FileName == "")
523 if (LineInfo->FileName == DILineInfo::BadString)
524524 continue;
525525 }
526526
5050 #include "llvm/Support/Errc.h"
5151 #include "llvm/Support/FileSystem.h"
5252 #include "llvm/Support/Format.h"
53 #include "llvm/Support/FormatVariadic.h"
5354 #include "llvm/Support/GraphWriter.h"
5455 #include "llvm/Support/Host.h"
5556 #include "llvm/Support/InitLLVM.h"
384385 exit(1);
385386 }
386387
387 void warn(StringRef Message) {
388 WithColor::warning(errs(), ToolName) << Message << ".\n";
389 errs().flush();
390 }
391
392 static void warn(Twine Message) {
388 void warn(Twine Message) {
393389 // Output order between errs() and outs() matters especially for archive
394390 // files where the output is per member object.
395391 outs().flush();
551547 DILineInfo OldLineInfo;
552548 const ObjectFile *Obj = nullptr;
553549 std::unique_ptr Symbolizer;
554 // File name to file contents of source
550 // File name to file contents of source.
555551 std::unordered_map> SourceCache;
556 // Mark the line endings of the cached source
552 // Mark the line endings of the cached source.
557553 std::unordered_map> LineCache;
554 // Keep track of missing sources.
555 StringSet<> MissingSources;
556 // Only emit 'no debug info' warning once.
557 bool WarnedNoDebugInfo;
558558
559559 private:
560560 bool cacheSource(const DILineInfo& LineInfoFile);
561561
562562 public:
563563 SourcePrinter() = default;
564 SourcePrinter(const ObjectFile *Obj, StringRef DefaultArch) : Obj(Obj) {
564 SourcePrinter(const ObjectFile *Obj, StringRef DefaultArch)
565 : Obj(Obj), WarnedNoDebugInfo(false) {
565566 symbolize::LLVMSymbolizer::Options SymbolizerOpts;
566567 SymbolizerOpts.PrintFunctions = DILineInfoSpecifier::FunctionNameKind::None;
567568 SymbolizerOpts.Demangle = false;
571572 virtual ~SourcePrinter() = default;
572573 virtual void printSourceLine(raw_ostream &OS,
573574 object::SectionedAddress Address,
575 StringRef ObjectFilename,
574576 StringRef Delimiter = "; ");
575577 };
576578
580582 Buffer = MemoryBuffer::getMemBuffer(*LineInfo.Source);
581583 } else {
582584 auto BufferOrError = MemoryBuffer::getFile(LineInfo.FileName);
583 if (!BufferOrError)
585 if (!BufferOrError) {
586 if (MissingSources.insert(LineInfo.FileName).second)
587 warn("failed to find source " + LineInfo.FileName);
588
584589 return false;
590 }
585591 Buffer = std::move(*BufferOrError);
586592 }
587593 // Chomp the file to get lines
602608
603609 void SourcePrinter::printSourceLine(raw_ostream &OS,
604610 object::SectionedAddress Address,
611 StringRef ObjectFilename,
605612 StringRef Delimiter) {
606613 if (!Symbolizer)
607614 return;
608615
609616 DILineInfo LineInfo = DILineInfo();
610617 auto ExpectedLineInfo = Symbolizer->symbolizeCode(*Obj, Address);
618 std::string ErrorMessage;
611619 if (!ExpectedLineInfo)
612 consumeError(ExpectedLineInfo.takeError());
620 ErrorMessage = toString(ExpectedLineInfo.takeError());
613621 else
614622 LineInfo = *ExpectedLineInfo;
615623
616 if ((LineInfo.FileName == "") || LineInfo.Line == 0 ||
617 ((OldLineInfo.Line == LineInfo.Line) &&
618 (OldLineInfo.FileName == LineInfo.FileName)))
624 if (LineInfo.FileName == DILineInfo::BadString) {
625 if (!WarnedNoDebugInfo) {
626 std::string Warning =
627 "failed to parse debug information for " + ObjectFilename.str();
628 if (!ErrorMessage.empty())
629 Warning += ": " + ErrorMessage;
630 warn(Warning);
631 WarnedNoDebugInfo = true;
632 }
633 return;
634 }
635
636 if (LineInfo.Line == 0 || ((OldLineInfo.Line == LineInfo.Line) &&
637 (OldLineInfo.FileName == LineInfo.FileName)))
619638 return;
620639
621640 if (PrintLines)
626645 return;
627646 auto LineBuffer = LineCache.find(LineInfo.FileName);
628647 if (LineBuffer != LineCache.end()) {
629 if (LineInfo.Line > LineBuffer->second.size())
648 if (LineInfo.Line > LineBuffer->second.size()) {
649 warn(formatv(
650 "debug info line number {0} exceeds the number of lines in {1}",
651 LineInfo.Line, LineInfo.FileName));
630652 return;
653 }
631654 // Vector begins at 0, line numbers are non-zero
632655 OS << Delimiter << LineBuffer->second[LineInfo.Line - 1] << '\n';
633656 }
666689 ArrayRef Bytes,
667690 object::SectionedAddress Address, raw_ostream &OS,
668691 StringRef Annot, MCSubtargetInfo const &STI,
669 SourcePrinter *SP,
692 SourcePrinter *SP, StringRef ObjectFilename,
670693 std::vector *Rels = nullptr) {
671694 if (SP && (PrintSource || PrintLines))
672 SP->printSourceLine(OS, Address);
695 SP->printSourceLine(OS, Address, ObjectFilename);
673696
674697 size_t Start = OS.tell();
675698 if (!NoLeadingAddr)
710733 void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef Bytes,
711734 object::SectionedAddress Address, raw_ostream &OS,
712735 StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
736 StringRef ObjectFilename,
713737 std::vector *Rels) override {
714738 if (SP && (PrintSource || PrintLines))
715 SP->printSourceLine(OS, Address, "");
739 SP->printSourceLine(OS, Address, ObjectFilename, "");
716740 if (!MI) {
717741 printLead(Bytes, Address.Address, OS);
718742 OS << " ";
749773 OS << Separator;
750774 Separator = "\n";
751775 if (SP && (PrintSource || PrintLines))
752 SP->printSourceLine(OS, Address, "");
776 SP->printSourceLine(OS, Address, ObjectFilename, "");
753777 printLead(Bytes, Address.Address, OS);
754778 OS << Preamble;
755779 Preamble = " ";
779803 void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef Bytes,
780804 object::SectionedAddress Address, raw_ostream &OS,
781805 StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
806 StringRef ObjectFilename,
782807 std::vector *Rels) override {
783808 if (SP && (PrintSource || PrintLines))
784 SP->printSourceLine(OS, Address);
809 SP->printSourceLine(OS, Address, ObjectFilename);
785810
786811 if (MI) {
787812 SmallString<40> InstStr;
830855 void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef Bytes,
831856 object::SectionedAddress Address, raw_ostream &OS,
832857 StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
858 StringRef ObjectFilename,
833859 std::vector *Rels) override {
834860 if (SP && (PrintSource || PrintLines))
835 SP->printSourceLine(OS, Address);
861 SP->printSourceLine(OS, Address, ObjectFilename);
836862 if (!NoLeadingAddr)
837863 OS << format("%8" PRId64 ":", Address.Address / 8);
838864 if (!NoShowRawInsn) {
13811407 if (Size == 0)
13821408 Size = 1;
13831409
1384 PIP.printInst(
1385 *IP, Disassembled ? &Inst : nullptr, Bytes.slice(Index, Size),
1386 {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, outs(),
1387 "", *STI, &SP, &Rels);
1410 PIP.printInst(*IP, Disassembled ? &Inst : nullptr,
1411 Bytes.slice(Index, Size),
1412 {SectionAddr + Index + VMAAdjustment, Section.getIndex()},
1413 outs(), "", *STI, &SP, Obj->getFileName(), &Rels);
13881414 outs() << CommentStream.str();
13891415 Comments.clear();
13901416
128128 void printSectionContents(const object::ObjectFile *O);
129129 void printSymbolTable(const object::ObjectFile *O, StringRef ArchiveName,
130130 StringRef ArchitectureName = StringRef());
131 void warn(StringRef Message);
131 void warn(Twine Message);
132132 LLVM_ATTRIBUTE_NORETURN void error(Twine Message);
133133 LLVM_ATTRIBUTE_NORETURN void report_error(StringRef File, Twine Message);
134134 LLVM_ATTRIBUTE_NORETURN void report_error(Error E, StringRef File);
3535 ModuleAddress.SectionIndex = object::SectionedAddress::UndefSection;
3636 if (auto ResOrErr = Symbolizer.symbolizeCode(BinaryInstrMap, ModuleAddress)) {
3737 auto &DI = *ResOrErr;
38 if (DI.FunctionName == "")
38 if (DI.FunctionName == DILineInfo::BadString)
3939 F << "@(" << std::hex << It->second << ")";
4040 else
4141 F << DI.FunctionName;