diff --git a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h --- a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h +++ b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h @@ -119,6 +119,8 @@ BIDFetcher = std::move(Fetcher); } + Error findBinaryFile(StringRef Name); + private: // Bundles together object file with code/data and object file with // corresponding debug info. These objects can be the same. diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp --- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp +++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp @@ -710,6 +710,15 @@ return Name; } +/// Checks if the given file exists and can be opened as executable/relocatable +/// file. +/// \param BinName Name of the file to search for. +/// \returns Error::success() if the file was successfully opened, . +Error LLVMSymbolizer::findBinaryFile(StringRef BinName) { + Expected BinFile = getOrCreateModuleInfo(BinName.str()); + return BinFile ? Error::success() : BinFile.takeError(); +} + void LLVMSymbolizer::recordAccess(CachedBinary &Bin) { if (Bin->getBinary()) LRUBinaries.splice(LRUBinaries.end(), LRUBinaries, Bin.getIterator()); diff --git a/llvm/test/tools/llvm-symbolizer/errors.test b/llvm/test/tools/llvm-symbolizer/errors.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-symbolizer/errors.test @@ -0,0 +1,7 @@ +RUN: not llvm-addr2line -e %p/Inputs/inexistent 0x12 2>&1 | FileCheck %s --check-prefix=CHECK-INEXISTENT +# Don't check the OS-dependent message "No such file or directory". +CHECK-INEXISTENT: llvm-addr2line: '{{.*}}Inputs/inexistent': + +RUN: not llvm-addr2line 0x12 2>&1 | FileCheck %s --check-prefix=CHECK-DEFAULT +# Don't check the OS-dependent message "No such file or directory". +CHECK-DEFAULT: llvm-addr2line: 'a.out': diff --git a/llvm/test/tools/llvm-symbolizer/input-base.test b/llvm/test/tools/llvm-symbolizer/input-base.test --- a/llvm/test/tools/llvm-symbolizer/input-base.test +++ b/llvm/test/tools/llvm-symbolizer/input-base.test @@ -11,14 +11,14 @@ RUN: llvm-symbolizer -e /dev/null -a 0O1234 | FileCheck %s --check-prefix=INVALID-NOT-OCTAL-UPPER # llvm-addr2line always requires hexadecimal, but accepts an optional 0x prefix. -RUN: llvm-addr2line -e /dev/null -a 0x1234 | FileCheck %s -RUN: llvm-addr2line -e /dev/null -a 0X1234 | FileCheck %s -RUN: llvm-addr2line -e /dev/null -a 1234 | FileCheck %s -RUN: llvm-addr2line -e /dev/null -a 01234 | FileCheck %s -RUN: llvm-addr2line -e /dev/null -a 0b1010 | FileCheck %s --check-prefix=HEXADECIMAL-NOT-BINARY -RUN: llvm-addr2line -e /dev/null -a 0B1010 | FileCheck %s --check-prefix=HEXADECIMAL-NOT-BINARY -RUN: llvm-addr2line -e /dev/null -a 0o1234 | FileCheck %s --check-prefix=INVALID-NOT-OCTAL -RUN: llvm-addr2line -e /dev/null -a 0O1234 | FileCheck %s --check-prefix=INVALID-NOT-OCTAL +RUN: llvm-addr2line -e %p/Inputs/addr.exe -a 0x1234 | FileCheck %s +RUN: llvm-addr2line -e %p/Inputs/addr.exe -a 0X1234 | FileCheck %s +RUN: llvm-addr2line -e %p/Inputs/addr.exe -a 1234 | FileCheck %s +RUN: llvm-addr2line -e %p/Inputs/addr.exe -a 01234 | FileCheck %s +RUN: llvm-addr2line -e %p/Inputs/addr.exe -a 0b1010 | FileCheck %s --check-prefix=HEXADECIMAL-NOT-BINARY +RUN: llvm-addr2line -e %p/Inputs/addr.exe -a 0B1010 | FileCheck %s --check-prefix=HEXADECIMAL-NOT-BINARY +RUN: llvm-addr2line -e %p/Inputs/addr.exe -a 0o1234 | FileCheck %s --check-prefix=INVALID-NOT-OCTAL +RUN: llvm-addr2line -e %p/Inputs/addr.exe -a 0O1234 | FileCheck %s --check-prefix=INVALID-NOT-OCTAL CHECK: 0x1234 CHECK-NEXT: ?? diff --git a/llvm/test/tools/llvm-symbolizer/untag-addresses.test b/llvm/test/tools/llvm-symbolizer/untag-addresses.test --- a/llvm/test/tools/llvm-symbolizer/untag-addresses.test +++ b/llvm/test/tools/llvm-symbolizer/untag-addresses.test @@ -3,12 +3,13 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: echo DATA %t.o 0 | llvm-symbolizer | FileCheck --check-prefix=UNTAG %s # RUN: echo DATA %t.o 0 | llvm-symbolizer --no-untag-addresses | FileCheck --check-prefix=NOUNTAG %s -# RUN: echo DATA %t.o 0 | llvm-addr2line | FileCheck --check-prefix=NOUNTAG %s +# RUN: echo DATA %t.o 0 | llvm-addr2line -e %t.o| FileCheck --check-prefix=NOUNTAG-GNU %s # UNTAG: foo # UNTAG: 0 4 # NOUNTAG: ?? # NOUNTAG: 0 0 +# NOUNTAG-GNU: ??:0 .data .globl foo diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp --- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp +++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -387,7 +387,8 @@ InitLLVM X(argc, argv); sys::InitializeCOMRAII COM(sys::COMThreadingMode::MultiThreaded); - bool IsAddr2Line = sys::path::stem(argv[0]).contains("addr2line"); + StringRef ToolName = sys::path::stem(argv[0]); + bool IsAddr2Line = ToolName.contains("addr2line"); BumpPtrAllocator A; StringSaver Saver(A); SymbolizerOptTable Tbl; @@ -476,6 +477,20 @@ else Printer = std::make_unique(outs(), errs(), Config); + if (IsAddr2Line) { + StringRef InputFile = Args.getLastArgValue(OPT_obj_EQ); + if (InputFile.empty()) + InputFile = "a.out"; + Error Status = Symbolizer.findBinaryFile(InputFile); + if (Status) { + handleAllErrors(std::move(Status), [&](const ErrorInfoBase &EI) { + errs() << ToolName << ": '" << InputFile << "': " << EI.message() + << '\n'; + }); + return EXIT_FAILURE; + } + } + std::vector InputAddresses = Args.getAllArgValues(OPT_INPUT); if (InputAddresses.empty()) { const int kMaxInputStringLength = 1024;