[llvm] 1792852 - [symbolizer] Change reaction on invalid input

Serge Pavlov via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 30 03:55:34 PDT 2023


Author: Serge Pavlov
Date: 2023-08-30T17:54:37+07:00
New Revision: 1792852f86dc75efa1f44d46b1a0daf386d64afa

URL: https://github.com/llvm/llvm-project/commit/1792852f86dc75efa1f44d46b1a0daf386d64afa
DIFF: https://github.com/llvm/llvm-project/commit/1792852f86dc75efa1f44d46b1a0daf386d64afa.diff

LOG: [symbolizer] Change reaction on invalid input

If llvm-symbolizer finds a malformed command, it echoes it to the
standard output. New versions of binutils (starting from 2.39) allow to
specify an address by a symbols. Implementation of this feature in
llvm-symbolizer makes the current reaction on invalid input
inappropriate. Almost any invalid command may be treated as a symbol
name, so the right reaction should be "symbol not found" in such case.

The exception are commands that are recognized but have incorrect
syntax, like "FILE:FILE:". The utility must produce descriptive
diagnostic for such input and route it to the stderr.

This change implements the new reaction on invalid input and is a
prerequisite for implementation of symbol lookup in llvm-symbolizer.

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

Added: 
    llvm/test/tools/llvm-symbolizer/get-input-file.test

Modified: 
    llvm/docs/CommandGuide/llvm-symbolizer.rst
    llvm/docs/ReleaseNotes.rst
    llvm/include/llvm/DebugInfo/Symbolize/DIPrinter.h
    llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
    llvm/test/Support/interrupts.test
    llvm/test/tools/llvm-symbolizer/debuginfod.test
    llvm/test/tools/llvm-symbolizer/file-prefix.test
    llvm/test/tools/llvm-symbolizer/flag-grouping.test
    llvm/test/tools/llvm-symbolizer/flush-output.s
    llvm/test/tools/llvm-symbolizer/functions.s
    llvm/test/tools/llvm-symbolizer/input-base.test
    llvm/test/tools/llvm-symbolizer/invalid-input-address.test
    llvm/test/tools/llvm-symbolizer/options-from-env.test
    llvm/test/tools/llvm-symbolizer/output-style-empty-line.test
    llvm/test/tools/llvm-symbolizer/output-style-json-code.test
    llvm/test/tools/llvm-symbolizer/output-style-json-data.test
    llvm/test/tools/llvm-symbolizer/output-style-json-frame.ll
    llvm/test/tools/llvm-symbolizer/sym-verbose.test
    llvm/test/tools/llvm-symbolizer/sym.test
    llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CommandGuide/llvm-symbolizer.rst b/llvm/docs/CommandGuide/llvm-symbolizer.rst
index d058cde98f1b0e..fe5df077b45664 100644
--- a/llvm/docs/CommandGuide/llvm-symbolizer.rst
+++ b/llvm/docs/CommandGuide/llvm-symbolizer.rst
@@ -18,8 +18,8 @@ symbolize logs containing :doc:`Symbolizer Markup </SymbolizerMarkupFormat>` via
 
 If no address is specified on the command-line, it reads the addresses from
 standard input. If no input name is specified on the command-line, but addresses
-are, or if at any time an input value is not recognized, the input is simply
-echoed to the output.
+are, the first address value is treated as an input name. If an input value is not
+recognized, it reports that source information is not found.
 
 Input names can be specified together with the addresses either on standard
 input or as positional arguments on the command-line. By default, input names

diff  --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 5c4b85c3a85aa1..096157b7710a67 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -160,6 +160,9 @@ Changes to the Debug Info
 Changes to the LLVM tools
 ---------------------------------
 
+* llvm-symbolizer now treats invalid input as an address for which source
+  information is not found.
+
 Changes to LLDB
 ---------------------------------
 

diff  --git a/llvm/include/llvm/DebugInfo/Symbolize/DIPrinter.h b/llvm/include/llvm/DebugInfo/Symbolize/DIPrinter.h
index b89f1da5857acf..026f917ced5bc1 100644
--- a/llvm/include/llvm/DebugInfo/Symbolize/DIPrinter.h
+++ b/llvm/include/llvm/DebugInfo/Symbolize/DIPrinter.h
@@ -47,9 +47,6 @@ class DIPrinter {
   virtual void print(const Request &Request,
                      const std::vector<DILocal> &Locals) = 0;
 
-  virtual void printInvalidCommand(const Request &Request,
-                                   StringRef Command) = 0;
-
   virtual bool printError(const Request &Request,
                           const ErrorInfoBase &ErrorInfo) = 0;
 
@@ -83,7 +80,7 @@ class PlainPrinterBase : public DIPrinter {
   virtual void printFooter() {}
 
 private:
-  void printHeader(uint64_t Address);
+  void printHeader(std::optional<uint64_t> Address);
 
 public:
   PlainPrinterBase(raw_ostream &OS, ErrorHandler EH, PrinterConfig &Config)
@@ -95,8 +92,6 @@ class PlainPrinterBase : public DIPrinter {
   void print(const Request &Request,
              const std::vector<DILocal> &Locals) override;
 
-  void printInvalidCommand(const Request &Request, StringRef Command) override;
-
   bool printError(const Request &Request,
                   const ErrorInfoBase &ErrorInfo) override;
 
@@ -147,8 +142,6 @@ class JSONPrinter : public DIPrinter {
   void print(const Request &Request,
              const std::vector<DILocal> &Locals) override;
 
-  void printInvalidCommand(const Request &Request, StringRef Command) override;
-
   bool printError(const Request &Request,
                   const ErrorInfoBase &ErrorInfo) override;
 

diff  --git a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
index f9669b554b4708..dcf5eee2bb32b6 100644
--- a/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
@@ -105,10 +105,10 @@ class SourceCode {
   }
 };
 
-void PlainPrinterBase::printHeader(uint64_t Address) {
-  if (Config.PrintAddress) {
+void PlainPrinterBase::printHeader(std::optional<uint64_t> Address) {
+  if (Address.has_value() && Config.PrintAddress) {
     OS << "0x";
-    OS.write_hex(Address);
+    OS.write_hex(*Address);
     StringRef Delimiter = Config.Pretty ? ": " : "\n";
     OS << Delimiter;
   }
@@ -182,7 +182,7 @@ void PlainPrinterBase::print(const DILineInfo &Info, bool Inlined) {
 }
 
 void PlainPrinterBase::print(const Request &Request, const DILineInfo &Info) {
-  printHeader(*Request.Address);
+  printHeader(Request.Address);
   print(Info, false);
   printFooter();
 }
@@ -260,11 +260,6 @@ void PlainPrinterBase::print(const Request &Request,
   printFooter();
 }
 
-void PlainPrinterBase::printInvalidCommand(const Request &Request,
-                                           StringRef Command) {
-  OS << Command << '\n';
-}
-
 bool PlainPrinterBase::printError(const Request &Request,
                                   const ErrorInfoBase &ErrorInfo) {
   ErrHandler(ErrorInfo, Request.ModuleName);
@@ -367,13 +362,6 @@ void JSONPrinter::print(const Request &Request,
     printJSON(std::move(Json));
 }
 
-void JSONPrinter::printInvalidCommand(const Request &Request,
-                                      StringRef Command) {
-  printError(Request,
-             StringError("unable to parse arguments: " + Command,
-                         std::make_error_code(std::errc::invalid_argument)));
-}
-
 bool JSONPrinter::printError(const Request &Request,
                              const ErrorInfoBase &ErrorInfo) {
   json::Object Json = toJSON(Request, ErrorInfo.message());

diff  --git a/llvm/test/Support/interrupts.test b/llvm/test/Support/interrupts.test
index 1201e12829c413..86730f5139c042 100644
--- a/llvm/test/Support/interrupts.test
+++ b/llvm/test/Support/interrupts.test
@@ -12,7 +12,7 @@ import time
 def run_symbolizer():
     proc = subprocess.Popen([sys.argv[2]], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
     # Write then read some output to ensure the process has started fully.
-    proc.stdin.write(b'foo\n')
+    proc.stdin.write(b'foo bar\n')
     proc.stdin.flush()
     proc.stdout.readline()
     # Windows handles signals 
diff erently.

diff  --git a/llvm/test/tools/llvm-symbolizer/debuginfod.test b/llvm/test/tools/llvm-symbolizer/debuginfod.test
index 98559077cfe057..1e2c935ffeb0bc 100644
--- a/llvm/test/tools/llvm-symbolizer/debuginfod.test
+++ b/llvm/test/tools/llvm-symbolizer/debuginfod.test
@@ -39,9 +39,9 @@ RUN:   FileCheck %s --check-prefix=FOUND
 
 # Passing BUILDID twice is a syntax error.
 RUN: env DEBUGINFOD_CACHE_PATH=%t llvm-symbolizer \
-RUN:   "BUILDID:BUILDID:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d" | \
+RUN:   "BUILDID:BUILDID:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d" 2>&1 | \
 RUN:   FileCheck %s --check-prefix=BUILDIDBUILDID
-BUILDIDBUILDID: BUILDID:BUILDID:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d
+BUILDIDBUILDID: error: 'BUILDID:BUILDID:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d': duplicate input file specification prefix
 
 # CODE should work preceding build ID.
 RUN: env DEBUGINFOD_CACHE_PATH=%t llvm-symbolizer \
@@ -63,16 +63,16 @@ NOTHINGFOUND-NEXT: ??:0:0
 # BUILDID shouldn't be parsed if --obj is given, just like regular filenames.
 RUN: env DEBUGINFOD_CACHE_PATH=%t llvm-symbolizer \
 RUN:   --obj=%t/addr.exe \
-RUN:   "BUILDID:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d" | \
+RUN:   "BUILDID:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d" 2>&1 | \
 RUN:   FileCheck %s --check-prefix=BUILDIDIGNORED
-BUILDIDIGNORED: BUILDID:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d
+BUILDIDIGNORED: error: 'BUILDID:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d': input file has already been specified
 
 # Providing both BUILDID and FILE is a syntax error.
 RUN: env DEBUGINFOD_CACHE_PATH=%t llvm-symbolizer \
-RUN:   "BUILDID:FILE:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d" | \
+RUN:   "BUILDID:FILE:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d" 2>&1 | \
 RUN:   FileCheck %s --check-prefix=BUILDIDFILE
-BUILDIDFILE: BUILDID:FILE:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d
+BUILDIDFILE: error: 'BUILDID:FILE:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d': duplicate input file specification prefix
 RUN: env DEBUGINFOD_CACHE_PATH=%t llvm-symbolizer \
-RUN:   "FILE:BUILDID:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d" | \
+RUN:   "FILE:BUILDID:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d" 2>&1 | \
 RUN:   FileCheck %s --check-prefix=FILEBUILDID
-FILEBUILDID: FILE:BUILDID:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d
+FILEBUILDID: error: 'FILE:BUILDID:127da749021c1fc1a58cba734a1f542cbe2b7ce4 0x40054d': duplicate input file specification prefix

diff  --git a/llvm/test/tools/llvm-symbolizer/file-prefix.test b/llvm/test/tools/llvm-symbolizer/file-prefix.test
index a309914118050f..66f645017f1fc9 100644
--- a/llvm/test/tools/llvm-symbolizer/file-prefix.test
+++ b/llvm/test/tools/llvm-symbolizer/file-prefix.test
@@ -4,6 +4,8 @@ RUN:   FileCheck %s --check-prefix=FOUND
 FOUND: {{[/\]+}}tmp{{[/\]+}}x.c:14:0
 
 # Passing FILE twice is a syntax error.
-RUN: llvm-symbolizer "CODE FILE:FILE:%p/Inputs/addr.exe 0x40054d" | \
-RUN:   FileCheck %s --check-prefix=FILEFILE
-FILEFILE: CODE FILE:FILE:{{.*}}/Inputs/addr.exe 0x40054d
+RUN: llvm-symbolizer "CODE FILE:FILE:%p/Inputs/addr.exe 0x40054d" 2>%t.err | FileCheck --check-prefix=NOTFOUND %s
+RUN:   FileCheck %s --check-prefix=FILEFILE --input-file %t.err
+NOTFOUND:      ??
+NOTFOUND-NEXT: ??:0:0
+FILEFILE: error: 'CODE FILE:FILE:{{.*}}/Inputs/addr.exe 0x40054d': duplicate input file specification prefix

diff  --git a/llvm/test/tools/llvm-symbolizer/flag-grouping.test b/llvm/test/tools/llvm-symbolizer/flag-grouping.test
index cc2dbfdc893d93..7bcb68dd470677 100644
--- a/llvm/test/tools/llvm-symbolizer/flag-grouping.test
+++ b/llvm/test/tools/llvm-symbolizer/flag-grouping.test
@@ -3,8 +3,8 @@ RUN: llvm-symbolizer -apCie %p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck
 RUN: llvm-symbolizer -apCie=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck %s
 RUN: llvm-symbolizer -apCie%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck %s
 
-CHECK: some text
+CHECK: ?? at ??:0:0
 CHECK: 0x40054d: inctwo
 CHECK: (inlined by) inc
 CHECK  (inlined by) main
-CHECK: some text2
+CHECK: ?? at ??:0:0

diff  --git a/llvm/test/tools/llvm-symbolizer/flush-output.s b/llvm/test/tools/llvm-symbolizer/flush-output.s
index 840f430feaf810..070bf3fa3c86e3 100644
--- a/llvm/test/tools/llvm-symbolizer/flush-output.s
+++ b/llvm/test/tools/llvm-symbolizer/flush-output.s
@@ -14,4 +14,4 @@ foo:
 # RUN:   | FileCheck %s
 
 # CHECK: flush-output.s:10
-# CHECK: bad
+# CHECK: ??:0

diff  --git a/llvm/test/tools/llvm-symbolizer/functions.s b/llvm/test/tools/llvm-symbolizer/functions.s
index 3093d801d395f9..953760ac24af90 100644
--- a/llvm/test/tools/llvm-symbolizer/functions.s
+++ b/llvm/test/tools/llvm-symbolizer/functions.s
@@ -26,7 +26,8 @@
 # NONE-NOT: foo
 # NONE:     functions.cpp:2:0
 
-# ERR: none
+# ERR: ??
+# ERR-NEXT: ??:0
 
 # The assembly below is a stripped down version of the output of:
 #   clang -S -g --target=x86_64-pc-linux

diff  --git a/llvm/test/tools/llvm-symbolizer/get-input-file.test b/llvm/test/tools/llvm-symbolizer/get-input-file.test
new file mode 100644
index 00000000000000..e98b8ca389697e
--- /dev/null
+++ b/llvm/test/tools/llvm-symbolizer/get-input-file.test
@@ -0,0 +1,47 @@
+# If binary input file is not specified, llvm-symbolizer assumes it is the first
+# item in the command.
+
+# No input items at all, complain about missing input file.
+RUN: echo | llvm-symbolizer 2>%t.1.err | FileCheck %s --check-prefix=NOSOURCE
+RUN: FileCheck --input-file=%t.1.err --check-prefix=NOFILE %s
+
+# Only one input item, complain about missing addresses.
+RUN: llvm-symbolizer "foo" 2>%t.2.err | FileCheck %s --check-prefix=NOSOURCE
+RUN: FileCheck --input-file=%t.2.err --check-prefix=NOADDR %s
+
+# Two items specified, check if the first one is an existing file.
+RUN: llvm-symbolizer "foo 400" 2>%t.3.err | FileCheck %s --check-prefix=NOSOURCE
+RUN: FileCheck --input-file=%t.3.err --check-prefix=NOTFOUND %s
+
+# FILE: must be followed by a file name.
+RUN: llvm-symbolizer "FILE:" 2>%t.4.err | FileCheck %s --check-prefix=NOSOURCE
+RUN: FileCheck --input-file=%t.4.err --check-prefix=MISSING-FILE %s
+
+# BUILDID: must be followed by a hash.
+RUN: llvm-symbolizer "BUILDID:" 2>%t.5.err | FileCheck %s --check-prefix=NOSOURCE
+RUN: FileCheck --input-file=%t.5.err --check-prefix=MISSING-HASH %s
+
+# Wrong build-id.
+RUN: llvm-symbolizer "BUILDID: foo" 2>%t.6.err | FileCheck %s --check-prefix=NOSOURCE
+RUN: FileCheck --input-file=%t.6.err --check-prefix=BAD-HASH %s
+
+# Unbalanced string quotes in the file name.
+RUN: llvm-symbolizer "FILE:\"foo" 2>%t.7.err | FileCheck %s --check-prefix=NOSOURCE
+RUN: FileCheck --input-file=%t.7.err --check-prefix=BAD-QUOTE %s
+
+NOSOURCE:      ??
+NOSOURCE-NEXT: ??:0:0
+
+NOFILE: error: no input filename has been specified
+
+NOADDR: error: 'foo': no module offset has been specified
+
+NOTFOUND:  error: 'foo': {{[nN]}}o such file or directory
+
+MISSING-FILE: error: 'FILE:': must be followed by an input file
+
+MISSING-HASH: error: 'BUILDID:': must be followed by a hash
+
+BAD-HASH:  error: 'BUILDID: foo': wrong format of build-id
+
+BAD-QUOTE: error: 'FILE:"foo': unbalanced quotes in input file name

diff  --git a/llvm/test/tools/llvm-symbolizer/input-base.test b/llvm/test/tools/llvm-symbolizer/input-base.test
index 21b3fc837e16c1..78cf1a38bf4e04 100644
--- a/llvm/test/tools/llvm-symbolizer/input-base.test
+++ b/llvm/test/tools/llvm-symbolizer/input-base.test
@@ -8,7 +8,7 @@ RUN: llvm-symbolizer -e %p/Inputs/addr.exe -a 0B1001000110100 | FileCheck %s
 RUN: llvm-symbolizer -e %p/Inputs/addr.exe -a 0o11064 | FileCheck %s
 
 # llvm-symbolizer / StringRef::getAsInteger only accepts the 0o prefix in lowercase.
-RUN: llvm-symbolizer -e %p/Inputs/addr.exe -a 0O1234 | FileCheck %s --check-prefix=INVALID-NOT-OCTAL-UPPER
+RUN: llvm-symbolizer -e %p/Inputs/addr.exe -a 0O1234 | FileCheck %s --check-prefix=INVALID
 
 # llvm-addr2line always requires hexadecimal, but accepts an optional 0x prefix.
 RUN: llvm-addr2line -e %p/Inputs/addr.exe -a 0x1234 | FileCheck %s
@@ -17,17 +17,16 @@ 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-LOWER
-RUN: llvm-addr2line -e %p/Inputs/addr.exe -a 0O1234 | FileCheck %s --check-prefix=INVALID-NOT-OCTAL-UPPER
+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: ??
 
+INVALID:      ??
+INVALID-NEXT: ??:0
+
 HEXADECIMAL-NOT-BINARY: 0xb1010
 HEXADECIMAL-NOT-BINARY: ??
 
-INVALID-NOT-OCTAL-LOWER: 0o1234
-INVALID-NOT-OCTAL-LOWER-NOT: ??
-
-INVALID-NOT-OCTAL-UPPER: 0O1234
-INVALID-NOT-OCTAL-UPPER-NOT: ??
+INVALID-NOT-OCTAL: ??:0

diff  --git a/llvm/test/tools/llvm-symbolizer/invalid-input-address.test b/llvm/test/tools/llvm-symbolizer/invalid-input-address.test
index 44291186d7fd2d..e9f25c5e299401 100644
--- a/llvm/test/tools/llvm-symbolizer/invalid-input-address.test
+++ b/llvm/test/tools/llvm-symbolizer/invalid-input-address.test
@@ -1,10 +1,12 @@
 # Use address that can't fit in a 64-bit number. Show that llvm-symbolizer
-# simply echoes it as per other malformed input addresses.
+# simply treats it as an unknown symbol.
 RUN: llvm-symbolizer --obj=%p/Inputs/addr.exe 0x10000000000000000 | FileCheck --check-prefix=LARGE-ADDR %s
 
-LARGE-ADDR-NOT: {{.}}
-LARGE-ADDR:     0x10000000000000000
-LARGE-ADDR-NOT: {{.}}
+LARGE-ADDR-NOT:  {{.}}
+LARGE-ADDR:      ??
+LARGE-ADDR-NEXT: ??:0:0
+LARGE-ADDR-EMPTY:
+LARGE-ADDR-NOT:  {{.}}
 
 RUN: echo '"some text"' '"some text2"' > %t.rsp
 RUN: echo -e 'some text\nsome text2\n' > %t.inp
@@ -19,5 +21,5 @@ RUN: llvm-addr2line --obj=%p/Inputs/addr.exe < %t.inp | FileCheck --check-prefix
 RUN: llvm-addr2line --obj=%p/Inputs/addr.exe "some text" "some text2" | FileCheck --check-prefix=BAD-INPUT %s
 RUN: llvm-addr2line --obj=%p/Inputs/addr.exe @%t.rsp | FileCheck --check-prefix=BAD-INPUT %s
 
-BAD-INPUT:      some text
-BAD-INPUT-NEXT: some text2
+BAD-INPUT:      ??
+BAD-INPUT-NEXT: ??:0

diff  --git a/llvm/test/tools/llvm-symbolizer/options-from-env.test b/llvm/test/tools/llvm-symbolizer/options-from-env.test
index 5fb566f56a0253..51e35b284b843f 100644
--- a/llvm/test/tools/llvm-symbolizer/options-from-env.test
+++ b/llvm/test/tools/llvm-symbolizer/options-from-env.test
@@ -1,6 +1,16 @@
-# RUN: env LLVM_SYMBOLIZER_OPTS='0 1 --verbose' llvm-symbolizer 2 | FileCheck %s
-# RUN: env LLVM_ADDR2LINE_OPTS='0 1 --verbose' llvm-addr2line 2 | FileCheck %s
+RUN: env LLVM_SYMBOLIZER_OPTS='-e %p/Inputs/discrim --verbose' llvm-symbolizer 0x400590 | FileCheck --check-prefix=LLVM %s
+RUN: env LLVM_ADDR2LINE_OPTS='-e %p/Inputs/discrim --verbose' llvm-addr2line 0x400590 | FileCheck --check-prefix=GNU %s
 
-# CHECK:      0
-# CHECK-NEXT: 1
-# CHECK-NEXT: 2
+LLVM:      foo
+LLVM-NEXT: Filename: /tmp{{[\\/]}}discrim.c
+LLVM-NEXT: Function start filename: /tmp{{[\\/]}}discrim.c
+LLVM-NEXT: Function start line: 4
+LLVM-NEXT: Function start address: 0x400590
+LLVM-NEXT: Line: 5
+LLVM-NEXT: Column: 7
+
+GNU:      Filename: /tmp{{[\\/]}}discrim.c
+GNU-NEXT: Function start filename: /tmp{{[\\/]}}discrim.c
+GNU-NEXT: Function start line: 4
+GNU-NEXT: Line: 5
+GNU-NEXT: Column: 7

diff  --git a/llvm/test/tools/llvm-symbolizer/output-style-empty-line.test b/llvm/test/tools/llvm-symbolizer/output-style-empty-line.test
index a3797d7b2e94c1..70622ec3ab57d7 100644
--- a/llvm/test/tools/llvm-symbolizer/output-style-empty-line.test
+++ b/llvm/test/tools/llvm-symbolizer/output-style-empty-line.test
@@ -13,7 +13,7 @@ RUN:   | FileCheck %s --check-prefix=LLVM
 
 LLVM: x.c:14:0
 LLVM-EMPTY:
-LLVM-NEXT: some text2
+LLVM-NEXT: ??
 
 RUN: llvm-symbolizer --output-style=GNU -e %p/Inputs/addr.exe < %p/Inputs/addr.inp \
 RUN:   | FileCheck %s --check-prefix=GNU
@@ -25,4 +25,4 @@ RUN: llvm-addr2line --output-style=GNU -i -e %p/Inputs/addr.exe < %p/Inputs/addr
 RUN:   | FileCheck %s --check-prefix=GNU
 
 GNU: x.c:14
-GNU-NEXT: some text2
+GNU-NEXT: ??

diff  --git a/llvm/test/tools/llvm-symbolizer/output-style-json-code.test b/llvm/test/tools/llvm-symbolizer/output-style-json-code.test
index e3977f291d4909..9179b673f39fd0 100644
--- a/llvm/test/tools/llvm-symbolizer/output-style-json-code.test
+++ b/llvm/test/tools/llvm-symbolizer/output-style-json-code.test
@@ -25,39 +25,39 @@
 # RUN: llvm-symbolizer --output-style=JSON --no-inlines -e %p/Inputs/addr.exe < %p/Inputs/addr.inp | \
 # RUN:   FileCheck %s --check-prefix=NO-INLINES --strict-whitespace --match-full-lines --implicit-check-not={{.}}
 ## Invalid first argument before any valid one.
-# NO-INLINES:{"Error":{"Message":"unable to parse arguments: some text"},"ModuleName":"{{.*}}/Inputs/addr.exe"}
+# NO-INLINES:{"ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":0,"Discriminator":0,"FileName":"","FunctionName":"","Line":0,"StartAddress":"","StartFileName":"","StartLine":0}]}
 ## Resolve valid address.
 # NO-INLINES-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"main","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2}]}
 ## Invalid argument after a valid one.
-# NO-INLINES-NEXT:{"Error":{"Message":"unable to parse arguments: some text2"},"ModuleName":"{{.*}}/Inputs/addr.exe"}
+# NO-INLINES-NEXT:{"ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":0,"Discriminator":0,"FileName":"","FunctionName":"","Line":0,"StartAddress":"","StartFileName":"","StartLine":0}]}
 
 ## This test case is testing stdin input, inlines by default.
 # RUN: llvm-symbolizer --output-style=JSON -e %p/Inputs/addr.exe < %p/Inputs/addr.inp | \
 # RUN:   FileCheck %s --check-prefix=INLINE --strict-whitespace --match-full-lines --implicit-check-not={{.}}
 ## Invalid first argument before any valid one.
-# INLINE:{"Error":{"Message":"unable to parse arguments: some text"},"ModuleName":"{{.*}}/Inputs/addr.exe"}
+# INLINE:{"ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":0,"Discriminator":0,"FileName":"","FunctionName":"","Line":0,"StartAddress":"","StartFileName":"","StartLine":0}]}
 ## Resolve valid address.
 # INLINE-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inctwo","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inc","Line":7,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":6},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"main","Line":14,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":12}]}
 ## Invalid argument after a valid one.
-# INLINE-NEXT:{"Error":{"Message":"unable to parse arguments: some text2"},"ModuleName":"{{.*}}/Inputs/addr.exe"}
+# INLINE-NEXT:{"ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":0,"Discriminator":0,"FileName":"","FunctionName":"","Line":0,"StartAddress":"","StartFileName":"","StartLine":0}]}
 
 ## Also check the last test case with llvm-adr2line.
 ## The expected result is the same with -f -i.
 # RUN: llvm-addr2line --output-style=JSON -f -i -e %p/Inputs/addr.exe < %p/Inputs/addr.inp | \
 # RUN:   FileCheck %s --check-prefix=INLINE-A2L --strict-whitespace --match-full-lines --implicit-check-not={{.}}
 ## Invalid first argument before any valid one.
-# INLINE-A2L:{"Error":{"Message":"unable to parse arguments: some text"},"ModuleName":"{{.*}}/Inputs/addr.exe"}
+# INLINE-A2L:{"ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":0,"Discriminator":0,"FileName":"","FunctionName":"","Line":0,"StartAddress":"","StartFileName":"","StartLine":0}]}
 ## Resolve valid address.
 # INLINE-A2L-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inctwo","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"inc","Line":7,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":6},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"main","Line":14,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":12}]}
 ## Invalid argument after a valid one.
-# INLINE-A2L-NEXT:{"Error":{"Message":"unable to parse arguments: some text2"},"ModuleName":"{{.*}}/Inputs/addr.exe"}
+# INLINE-A2L-NEXT:{"ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":0,"Discriminator":0,"FileName":"","FunctionName":"","Line":0,"StartAddress":"","StartFileName":"","StartLine":0}]}
 
 ## Note llvm-addr2line without -f does not print the function name in JSON too.
 # RUN: llvm-addr2line --output-style=JSON -i -e %p/Inputs/addr.exe < %p/Inputs/addr.inp | \
 # RUN:   FileCheck %s --check-prefix=NO-FUNC-A2L --strict-whitespace --match-full-lines --implicit-check-not={{.}}
 ## Invalid first argument before any valid one.
-# NO-FUNC-A2L:{"Error":{"Message":"unable to parse arguments: some text"},"ModuleName":"{{.*}}/Inputs/addr.exe"}
+# NO-FUNC-A2L:{"ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":0,"Discriminator":0,"FileName":"","FunctionName":"","Line":0,"StartAddress":"","StartFileName":"","StartLine":0}]}
 ## Resolve valid address.
 # NO-FUNC-A2L-NEXT:{"Address":"0x40054d","ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":3,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"","Line":3,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":2},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"","Line":7,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":6},{"Column":0,"Discriminator":0,"FileName":"/tmp{{/|\\\\}}x.c","FunctionName":"","Line":14,"StartAddress":"0x400540","StartFileName":"/tmp{{/|\\\\}}x.c","StartLine":12}]}
 ## Invalid argument after a valid one.
-# NO-FUNC-A2L-NEXT:{"Error":{"Message":"unable to parse arguments: some text2"},"ModuleName":"{{.*}}/Inputs/addr.exe"}
+# NO-FUNC-A2L-NEXT:{"ModuleName":"{{.*}}/Inputs/addr.exe","Symbol":[{"Column":0,"Discriminator":0,"FileName":"","FunctionName":"","Line":0,"StartAddress":"","StartFileName":"","StartLine":0}]}

diff  --git a/llvm/test/tools/llvm-symbolizer/output-style-json-data.test b/llvm/test/tools/llvm-symbolizer/output-style-json-data.test
index f77cf40b907418..722ac73d751043 100644
--- a/llvm/test/tools/llvm-symbolizer/output-style-json-data.test
+++ b/llvm/test/tools/llvm-symbolizer/output-style-json-data.test
@@ -10,7 +10,7 @@
 ## Handle invalid argument.
 # RUN: llvm-symbolizer "DATA tmp.o Z" --output-style=JSON | \
 # RUN:   FileCheck %s --check-prefix=INVARG --strict-whitespace --match-full-lines --implicit-check-not={{.}}
-# INVARG:[{"Error":{"Message":"unable to parse arguments: DATA tmp.o Z"},"ModuleName":"tmp.o"}]
+# INVARG:[{"ModuleName":"tmp.o","Symbol":[{"Column":0,"Discriminator":0,"FileName":"","FunctionName":"","Line":0,"StartAddress":"","StartFileName":"","StartLine":0}]}]
 
 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
 

diff  --git a/llvm/test/tools/llvm-symbolizer/output-style-json-frame.ll b/llvm/test/tools/llvm-symbolizer/output-style-json-frame.ll
index d6cb4030c0927e..8a99345420fdeb 100644
--- a/llvm/test/tools/llvm-symbolizer/output-style-json-frame.ll
+++ b/llvm/test/tools/llvm-symbolizer/output-style-json-frame.ll
@@ -10,7 +10,7 @@
 ;; Handle invalid argument.
 ; RUN: llvm-symbolizer "FRAME tmp.o Z" --output-style=JSON | \
 ; RUN:   FileCheck %s --check-prefix=INVARG --strict-whitespace --match-full-lines --implicit-check-not={{.}}
-; INVARG:[{"Error":{"Message":"unable to parse arguments: FRAME tmp.o Z"},"ModuleName":"tmp.o"}]
+; INVARG:[{"ModuleName":"tmp.o","Symbol":[{"Column":0,"Discriminator":0,"FileName":"","FunctionName":"","Line":0,"StartAddress":"","StartFileName":"","StartLine":0}]}]
 
 ; RUN: llc -filetype=obj -o %t.o %s 
 

diff  --git a/llvm/test/tools/llvm-symbolizer/sym-verbose.test b/llvm/test/tools/llvm-symbolizer/sym-verbose.test
index 2c4f4c3621fe54..831fd6c7f05071 100644
--- a/llvm/test/tools/llvm-symbolizer/sym-verbose.test
+++ b/llvm/test/tools/llvm-symbolizer/sym-verbose.test
@@ -13,7 +13,7 @@
 
 RUN: llvm-symbolizer --verbose --print-address --obj=%p/Inputs/discrim < %p/Inputs/discrim.inp | FileCheck %s
 
-CHECK: some text
+CHECK: ??
 
 CHECK: 0x400590
 CHECK-NEXT: foo
@@ -118,4 +118,4 @@ CHECK-NEXT: Line: 10
 CHECK-NEXT: Column: 0
 CHECK-NEXT: Discriminator: 2
 
-CHECK: some more text
+CHECK: ??

diff  --git a/llvm/test/tools/llvm-symbolizer/sym.test b/llvm/test/tools/llvm-symbolizer/sym.test
index a9a1339bd6c48a..a5793efb65029f 100644
--- a/llvm/test/tools/llvm-symbolizer/sym.test
+++ b/llvm/test/tools/llvm-symbolizer/sym.test
@@ -21,7 +21,8 @@ RUN: llvm-symbolizer --print-address --obj=%p/Inputs/addr.exe < %p/Inputs/addr.i
 RUN: llvm-symbolizer --addresses --obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck %s
 RUN: llvm-symbolizer -a --obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck %s
 
-CHECK: some text
+CHECK: ??:0:0
+CHECK-EMPTY:
 CHECK-NEXT: 0x40054d
 CHECK-NEXT: inctwo
 CHECK-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:3:3
@@ -30,7 +31,8 @@ CHECK-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:7:0
 CHECK-NEXT: main
 CHECK-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:14:0
 CHECK-EMPTY:
-CHECK-NEXT: some text2
+CHECK-NEXT: ??
+CHECK-NEXT: ??:0:0
 
 RUN: llvm-symbolizer --inlining --print-address --pretty-print --obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefix="PRETTY" %s 
 RUN: llvm-symbolizer --inlining --print-address -p --obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefix="PRETTY" %s
@@ -43,11 +45,11 @@ RUN: llvm-symbolizer -i --print-address -p --obj=%p/Inputs/addr.exe < %p/Inputs/
 # Support this compatibility alias for a while.
 RUN: llvm-symbolizer --inlining=true --print-address -p --obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefix="PRETTY" %s
 
-PRETTY: some text
+PRETTY: ??:0:0
 PRETTY: {{[0x]+}}40054d: inctwo at {{[/\]+}}tmp{{[/\]+}}x.c:3:3
 PRETTY:  (inlined by) inc at {{[/\]+}}tmp{{[/\]+}}x.c:7:0
 PRETTY:  (inlined by) main at {{[/\]+}}tmp{{[/\]+}}x.c:14:0
-PRETTY: some text2
+PRETTY: ??:0:0
 
 RUN: llvm-addr2line --obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefix=A2L %s
 RUN: llvm-addr2line -a --obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2L,A2L_A %s
@@ -62,7 +64,7 @@ RUN: llvm-addr2line -pai --obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileChe
 RUN: llvm-addr2line -pfi --obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2LP,A2LP_F,A2LP_FI %s
 RUN: llvm-addr2line -pafi --obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2LP,A2LP_AF,A2LP_FI %s
 
-A2L:         some text
+A2L:         ??:0
 A2L_A-NEXT:  0x40054d
 A2L_F-NEXT:  inctwo
 A2L-NEXT:    {{[/\]+}}tmp{{[/\]+}}x.c:3{{$}}
@@ -70,9 +72,10 @@ A2L_FI-NEXT: inc{{$}}
 A2L_I-NEXT:  {{[/\]+}}tmp{{[/\]+}}x.c:7{{$}}
 A2L_FI-NEXT: main
 A2L_I-NEXT:  {{[/\]+}}tmp{{[/\]+}}x.c:14{{$}}
-A2L-NEXT:    some text2
+A2L_F-NEXT:  ??
+A2L-NEXT:    ??:0
 
-A2LP:          some text
+A2LP:          ??:0
 A2LP_A-NEXT:   0x40054d: {{[/\]+}}tmp{{[/\]+}}x.c:3{{$}}
 A2LP_F-NEXT:   inctwo at {{[/\]+}}tmp{{[/\]+}}x.c:3{{$}}
 A2LP_AF-NEXT:  0x40054d: inctwo at {{[/\]+}}tmp{{[/\]+}}x.c:3{{$}}
@@ -80,4 +83,4 @@ A2LP_I-NEXT:   {{[/\]+}}tmp{{[/\]+}}x.c:7{{$}}
 A2LP_I-NEXT:   {{[/\]+}}tmp{{[/\]+}}x.c:14{{$}}
 A2LP_FI-NEXT:   (inlined by) inc at {{[/\]+}}tmp{{[/\]+}}x.c:7{{$}}
 A2LP_FI-NEXT:   (inlined by) main at {{[/\]+}}tmp{{[/\]+}}x.c:14{{$}}
-A2LP-NEXT:     some text2
+A2LP-NEXT:     ??:0

diff  --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 4c1c2f224984c7..78a0e6772f3fb3 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -32,6 +32,7 @@
 #include "llvm/Support/COM.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/InitLLVM.h"
 #include "llvm/Support/LLVMDriver.h"
@@ -80,10 +81,10 @@ class SymbolizerOptTable : public opt::GenericOptTable {
 
 static std::string ToolName;
 
-static void printError(const ErrorInfoBase &EI, StringRef Path) {
+static void printError(const ErrorInfoBase &EI, StringRef AuxInfo) {
   WithColor::error(errs(), ToolName);
-  if (!EI.isA<FileError>())
-    errs() << "'" << Path << "': ";
+  if (!AuxInfo.empty())
+    errs() << "'" << AuxInfo << "': ";
   EI.log(errs());
   errs() << '\n';
 }
@@ -151,10 +152,14 @@ static StringRef getSpaceDelimitedWord(StringRef &Source) {
   return Result;
 }
 
-static bool parseCommand(StringRef BinaryName, bool IsAddr2Line,
-                         StringRef InputString, Command &Cmd,
-                         std::string &ModuleName, object::BuildID &BuildID,
-                         uint64_t &ModuleOffset) {
+static Error makeStringError(StringRef Msg) {
+  return make_error<StringError>(Msg, inconvertibleErrorCode());
+}
+
+static Error parseCommand(StringRef BinaryName, bool IsAddr2Line,
+                          StringRef InputString, Command &Cmd,
+                          std::string &ModuleName, object::BuildID &BuildID,
+                          uint64_t &ModuleOffset) {
   ModuleName = BinaryName;
   if (InputString.consume_front("CODE ")) {
     Cmd = Command::Code;
@@ -174,34 +179,40 @@ static bool parseCommand(StringRef BinaryName, bool IsAddr2Line,
     InputString = InputString.ltrim();
     if (InputString.consume_front("FILE:")) {
       if (HasFilePrefix || HasBuildIDPrefix)
-        // Input file specification prefix has already been seen.
-        return false;
+        return makeStringError("duplicate input file specification prefix");
       HasFilePrefix = true;
       continue;
     }
     if (InputString.consume_front("BUILDID:")) {
       if (HasBuildIDPrefix || HasFilePrefix)
-        // Input file specification prefix has already been seen.
-        return false;
+        return makeStringError("duplicate input file specification prefix");
       HasBuildIDPrefix = true;
       continue;
     }
     break;
   }
 
+  // If an input file is not specified on the command line, try to extract it
+  // from the command.
   if (HasBuildIDPrefix || HasFilePrefix) {
+    InputString = InputString.ltrim();
+    if (InputString.empty()) {
+      if (HasFilePrefix)
+        return makeStringError("must be followed by an input file");
+      else
+        return makeStringError("must be followed by a hash");
+    }
+
     if (!BinaryName.empty() || !BuildID.empty())
-      // Input file has already been specified on the command line.
-      return false;
+      return makeStringError("input file has already been specified");
+
     StringRef Name = getSpaceDelimitedWord(InputString);
     if (Name.empty())
-      // Wrong name for module file.
-      return false;
+      return makeStringError("unbalanced quotes in input file name");
     if (HasBuildIDPrefix) {
       BuildID = parseBuildID(Name);
       if (BuildID.empty())
-        // Wrong format of BuildID hash.
-        return false;
+        return makeStringError("wrong format of build-id");
     } else {
       ModuleName = Name;
     }
@@ -209,20 +220,28 @@ static bool parseCommand(StringRef BinaryName, bool IsAddr2Line,
     // No input file has been specified. If the input string contains at least
     // two items, assume that the first item is a file name.
     ModuleName = getSpaceDelimitedWord(InputString);
-    if (ModuleName.empty() || InputString.empty())
-      // No input filename has been specified.
-      return false;
+    if (ModuleName.empty())
+      return makeStringError("no input filename has been specified");
   }
 
-  // Skip delimiters and parse module offset.
+  // Parse module offset.
   InputString = InputString.ltrim();
+  if (InputString.empty())
+    return makeStringError("no module offset has been specified");
   int OffsetLength = InputString.find_first_of(" \n\r");
   StringRef Offset = InputString.substr(0, OffsetLength);
   // GNU addr2line assumes the offset is hexadecimal and allows a redundant
   // "0x" or "0X" prefix; do the same for compatibility.
   if (IsAddr2Line)
     Offset.consume_front("0x") || Offset.consume_front("0X");
-  return !Offset.getAsInteger(IsAddr2Line ? 16 : 0, ModuleOffset);
+
+  // If the input is not a valid module offset, it is not an error, but its
+  // lookup does not make sense. Return error of 
diff erent kind to distinguish
+  // from error or success.
+  if (Offset.getAsInteger(IsAddr2Line ? 16 : 0, ModuleOffset))
+    return errorCodeToError(errc::invalid_argument);
+
+  return Error::success();
 }
 
 template <typename T>
@@ -268,6 +287,11 @@ void executeCommand(StringRef ModuleName, const T &ModuleSpec, Command Cmd,
   Symbolizer.pruneCache();
 }
 
+static void printUnknownLineInfo(std::string ModuleName, DIPrinter &Printer) {
+  Request SymRequest = {ModuleName, std::nullopt};
+  Printer.print(SymRequest, DILineInfo());
+}
+
 static void symbolizeInput(const opt::InputArgList &Args,
                            object::BuildIDRef IncomingBuildID,
                            uint64_t AdjustVMA, bool IsAddr2Line,
@@ -277,9 +301,16 @@ static void symbolizeInput(const opt::InputArgList &Args,
   std::string ModuleName;
   object::BuildID BuildID(IncomingBuildID.begin(), IncomingBuildID.end());
   uint64_t Offset = 0;
-  if (!parseCommand(Args.getLastArgValue(OPT_obj_EQ), IsAddr2Line,
-                    StringRef(InputString), Cmd, ModuleName, BuildID, Offset)) {
-    Printer.printInvalidCommand({ModuleName, std::nullopt}, InputString);
+  if (Error E = parseCommand(Args.getLastArgValue(OPT_obj_EQ), IsAddr2Line,
+                             StringRef(InputString), Cmd, ModuleName, BuildID,
+                             Offset)) {
+    handleAllErrors(
+        std::move(E),
+        [&](const StringError &EI) {
+          printError(EI, InputString);
+          printUnknownLineInfo(ModuleName, Printer);
+        },
+        [&](const ECError &EI) { printUnknownLineInfo(ModuleName, Printer); });
     return;
   }
   bool ShouldInline = Args.hasFlag(OPT_inlines, OPT_no_inlines, !IsAddr2Line);


        


More information about the llvm-commits mailing list