Index: llvm/test/tools/llvm-objdump/X86/source-interleave-invalid-source.test =================================================================== --- llvm/test/tools/llvm-objdump/X86/source-interleave-invalid-source.test +++ llvm/test/tools/llvm-objdump/X86/source-interleave-invalid-source.test @@ -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,10 @@ # 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>&1 | FileCheck %s --check-prefixes=CHECK,WARN --implicit-check-not="int *b = &a;" # CHECK: main: # CHECK-NEXT: ; int main() { +# WARN: warning: debug info line number 9999 exceeds the number of lines in # GOOD: ; int *b = &a; # CHECK: ; return *b + foo(); Index: llvm/test/tools/llvm-objdump/X86/source-interleave-missing-source.test =================================================================== --- llvm/test/tools/llvm-objdump/X86/source-interleave-missing-source.test +++ llvm/test/tools/llvm-objdump/X86/source-interleave-missing-source.test @@ -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,10 @@ # 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>&1 | FileCheck %s --check-prefixes=WARN,CHECK --implicit-check-not='main()' # RUN: llvm-objdump --source %t2.o | FileCheck %s --check-prefixes=CHECK,SOURCE +# WARN: warning: failed to find source # CHECK: 0000000000000010 main: # SOURCE-NEXT: ; int main() { # CHECK-NEXT: 10: 55 pushq %rbp Index: llvm/test/tools/llvm-objdump/X86/source-interleave-no-debug-info.test =================================================================== --- llvm/test/tools/llvm-objdump/X86/source-interleave-no-debug-info.test +++ llvm/test/tools/llvm-objdump/X86/source-interleave-no-debug-info.test @@ -1,13 +1,14 @@ ## 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>&1 | FileCheck %s --check-prefixes=WARN,CHECK --implicit-check-not='main()' +# WARN: warning: failed to parse debug info which may be missing # CHECK: 0000000000000010 main: # SOURCE-NEXT: ; int main() { # CHECK-NEXT: 10: 55 pushq %rbp Index: llvm/tools/llvm-objdump/llvm-objdump.cpp =================================================================== --- llvm/tools/llvm-objdump/llvm-objdump.cpp +++ llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -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" @@ -522,13 +523,18 @@ std::unordered_map> SourceCache; // Mark the line endings of the cached source std::unordered_map> 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( DILineInfoSpecifier::FunctionNameKind::None, true, false, false, DefaultArch); @@ -546,8 +552,13 @@ Buffer = MemoryBuffer::getMemBuffer(*LineInfo.Source); } else { auto BufferOrError = MemoryBuffer::getFile(LineInfo.FileName); - if (!BufferOrError) + if (!BufferOrError) { + bool NewMissingSource = + std::get<1>(MissingSources.insert(LineInfo.FileName)); + if (NewMissingSource) + warn(Twine("failed to find source " + LineInfo.FileName)); return false; + } Buffer = std::move(*BufferOrError); } // Chomp the file to get lines @@ -579,7 +590,16 @@ else LineInfo = *ExpectedLineInfo; - if ((LineInfo.FileName == "") || LineInfo.Line == 0 || + + if (LineInfo.FileName == "") { + if(!WarnedNoDebugInfo) { + warn(Twine("failed to parse debug info which may be missing")); + WarnedNoDebugInfo = true; + } + return; + } + + if (LineInfo.Line == 0 || ((OldLineInfo.Line == LineInfo.Line) && (OldLineInfo.FileName == LineInfo.FileName))) return; @@ -592,8 +612,12 @@ 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'; }