[llvm-branch-commits] [llvm] [llvm-readobj][ELF] Use WrappedError to filter duplicates (PR #191708)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Apr 16 23:27:41 PDT 2026


https://github.com/aokblast updated https://github.com/llvm/llvm-project/pull/191708

>From 148e771dec99a2abb3e9e08a45d8b13626123b8a Mon Sep 17 00:00:00 2001
From: ShengYi Hung <aokblast at FreeBSD.org>
Date: Sun, 12 Apr 2026 20:13:20 +0800
Subject: [PATCH 1/5] [Support] Add WrappedError class

The error consumer filters duplicate errors based on a portion of the
error message. Introduce a new Error kind that carries a prefix string
to support this use case.
---
 llvm/include/llvm/Support/Error.h    | 47 ++++++++++++++++++++++++++++
 llvm/lib/Support/Error.cpp           |  6 ++++
 llvm/unittests/Support/ErrorTest.cpp | 29 +++++++++++++++++
 3 files changed, 82 insertions(+)

diff --git a/llvm/include/llvm/Support/Error.h b/llvm/include/llvm/Support/Error.h
index c9fd16fdb7c2b..8e414428c8286 100644
--- a/llvm/include/llvm/Support/Error.h
+++ b/llvm/include/llvm/Support/Error.h
@@ -1497,6 +1497,53 @@ inline Error unwrap(LLVMErrorRef ErrRef) {
       reinterpret_cast<ErrorInfoBase *>(ErrRef)));
 }
 
+class LLVM_ABI ContextualizedError : public ErrorInfo<ContextualizedError> {
+public:
+  ContextualizedError(std::unique_ptr<ErrorInfoBase> E,
+                      const Twine &Prefix = "")
+      : Err(std::move(E)), Context(Prefix.str()) {}
+
+  void log(raw_ostream &OS) const override {
+    assert(Err && "Trying to log after takeError().");
+    if (Context.size())
+      OS << Context << ": ";
+    Err->log(OS);
+  }
+
+  Error takeError() { return Error(std::move(Err)); }
+
+  const std::string &getContext() const { return Context; }
+
+  std::string getMessageWithoutContext() const {
+    std::string Msg;
+    raw_string_ostream OS(Msg);
+    Err->log(OS);
+    return Msg;
+  }
+
+  std::error_code convertToErrorCode() const override;
+
+  static Error build(Error E, const Twine &Prefix) {
+    std::unique_ptr<ErrorInfoBase> Payload;
+    handleAllErrors(std::move(E),
+                    [&](std::unique_ptr<ErrorInfoBase> EIB) -> Error {
+                      Payload = std::move(EIB);
+                      return Error::success();
+                    });
+    return Error(std::unique_ptr<ContextualizedError>(
+        new ContextualizedError(std::move(Payload), Prefix)));
+  }
+
+  static char ID;
+
+private:
+  std::unique_ptr<ErrorInfoBase> Err;
+  std::string Context;
+};
+
+inline Error createContextualizedError(Error E, const Twine &Prefix = "") {
+  return ContextualizedError::build(std::move(E), Prefix);
+}
 } // end namespace llvm
 
 #endif // LLVM_SUPPORT_ERROR_H
diff --git a/llvm/lib/Support/Error.cpp b/llvm/lib/Support/Error.cpp
index c6743155ced85..aabb701b9b999 100644
--- a/llvm/lib/Support/Error.cpp
+++ b/llvm/lib/Support/Error.cpp
@@ -205,3 +205,9 @@ LLVMErrorTypeId LLVMGetStringErrorTypeId() {
 LLVMErrorRef LLVMCreateStringError(const char *ErrMsg) {
   return wrap(make_error<StringError>(ErrMsg, inconvertibleErrorCode()));
 }
+
+char ContextualizedError::ID = 0;
+
+std::error_code ContextualizedError::convertToErrorCode() const {
+  return Err->convertToErrorCode();
+}
diff --git a/llvm/unittests/Support/ErrorTest.cpp b/llvm/unittests/Support/ErrorTest.cpp
index 45c0a4f450b51..4ce269d6b71b0 100644
--- a/llvm/unittests/Support/ErrorTest.cpp
+++ b/llvm/unittests/Support/ErrorTest.cpp
@@ -18,6 +18,8 @@
 #include "gtest/gtest-spi.h"
 #include "gtest/gtest.h"
 #include <memory>
+#include <string>
+#include <unordered_set>
 
 using namespace llvm;
 
@@ -1219,4 +1221,31 @@ TEST(Error, ForwardToExpected) {
   EXPECT_THAT_ERROR(ExpectedReturningFct(false).moveInto(MaybeV), Succeeded());
   EXPECT_EQ(*MaybeV, 42);
 }
+
+TEST(Error, DeduplicateByContextualized) {
+  std::unordered_set<std::string> Visit;
+
+  auto InsertError = [&](Error E) {
+    std::string InnerErrorStr;
+    EXPECT_THAT_ERROR(handleErrors(std::move(E),
+                                   [&](const ContextualizedError &E) {
+                                     InnerErrorStr =
+                                         E.getMessageWithoutContext();
+                                   }),
+                      Succeeded());
+    return Visit.insert(InnerErrorStr).second;
+  };
+  EXPECT_EQ(
+      InsertError(createContextualizedError(
+          createStringError("failed to execute operation A"), "Context A")),
+      true);
+  EXPECT_EQ(
+      InsertError(createContextualizedError(
+          createStringError("failed to execute operation B"), "Context A")),
+      true);
+  EXPECT_EQ(
+      InsertError(createContextualizedError(
+          createStringError("failed to execute operation A"), "Context B")),
+      false);
+}
 } // namespace

>From 307007483421f839568c53c4a804ef21a600d753 Mon Sep 17 00:00:00 2001
From: ShengYi Hung <aokblast at FreeBSD.org>
Date: Sun, 12 Apr 2026 20:23:18 +0800
Subject: [PATCH 2/5] [Object][ELF] Pass Error to WarningHandler

Warning consumers may need to handle errors based on their type. Pass
the Error object instead of a string representation to enable this. This
also brings WarningHandler in line with Support/WithColor.h.
---
 llvm/include/llvm/Object/ELF.h              | 54 +++++++++++----------
 llvm/lib/Object/ELF.cpp                     |  4 +-
 llvm/tools/llvm-objdump/llvm-objdump.cpp    |  9 ++--
 llvm/tools/llvm-objdump/llvm-objdump.h      |  2 +-
 llvm/tools/llvm-readobj/ELFDumper.cpp       |  4 +-
 llvm/tools/llvm-readobj/ObjDumper.cpp       |  7 +--
 llvm/tools/llvm-readobj/ObjDumper.h         |  2 +-
 llvm/unittests/Object/ELFObjectFileTest.cpp |  4 +-
 8 files changed, 46 insertions(+), 40 deletions(-)

diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h
index e052519e27e8f..8f1d23b54622e 100644
--- a/llvm/include/llvm/Object/ELF.h
+++ b/llvm/include/llvm/Object/ELF.h
@@ -18,6 +18,7 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/Object/ELFTypes.h"
 #include "llvm/Object/Error.h"
@@ -77,6 +78,10 @@ LLVM_ABI StringRef getRISCVVendorRelocationTypeName(uint32_t Type,
 LLVM_ABI uint32_t getELFRelativeRelocationType(uint32_t Machine);
 LLVM_ABI StringRef getELFSectionTypeName(uint32_t Machine, uint32_t Type);
 
+static inline Error createError(Error E, const Twine &Context) {
+  return createContextualizedError(std::move(E), Context);
+}
+
 // Subclasses of ELFFile may need this for template instantiation
 inline std::pair<unsigned char, unsigned char>
 getElfArchType(StringRef Object) {
@@ -164,9 +169,7 @@ static std::string getPhdrIndexForError(const ELFFile<ELFT> &Obj,
   return "[unknown index]";
 }
 
-static inline Error defaultWarningHandler(const Twine &Msg) {
-  return createError(Msg);
-}
+static inline Error defaultWarningHandler(Error Err) { return Err; }
 
 template <class ELFT>
 static bool checkSectionOffsets(const typename ELFT::Phdr &Phdr,
@@ -268,9 +271,9 @@ class ELFFile {
   // This is a callback that can be passed to a number of functions.
   // It can be used to ignore non-critical errors (warnings), which is
   // useful for dumpers, like llvm-readobj.
-  // It accepts a warning message string and returns a success
+  // It accepts an error and returns a success
   // when the warning should be ignored or an error otherwise.
-  using WarningHandler = llvm::function_ref<Error(const Twine &Msg)>;
+  using WarningHandler = llvm::function_ref<Error(Error)>;
 
   const uint8_t *base() const { return Buf.bytes_begin(); }
   const uint8_t *end() const { return base() + getBufSize(); }
@@ -623,9 +626,9 @@ getExtendedSymbolTableIndex(const typename ELFT::Sym &Sym, unsigned SymIndex,
 
   Expected<typename ELFT::Word> TableOrErr = ShndxTable[SymIndex];
   if (!TableOrErr)
-    return createError("unable to read an extended symbol table at index " +
-                       Twine(SymIndex) + ": " +
-                       toString(TableOrErr.takeError()));
+    return createError(TableOrErr.takeError(),
+                       "unable to read an extended symbol table at index " +
+                           Twine(SymIndex));
   return *TableOrErr;
 }
 
@@ -842,8 +845,8 @@ ELFFile<ELFT>::getSectionStringTable(Elf_Shdr_Range Sections,
   Expected<uint32_t> ShStrNdxOrErr = getShStrNdx();
   if (!ShStrNdxOrErr)
     return createError(
-        "e_shstrndx == SHN_XINDEX, but cannot read section header 0: " +
-        toString(ShStrNdxOrErr.takeError()));
+        ShStrNdxOrErr.takeError(),
+        "e_shstrndx == SHN_XINDEX, but cannot read section header 0");
 
   uint32_t Index = *ShStrNdxOrErr;
   // There is no section name string table. Return FakeSectionStrings which
@@ -1153,8 +1156,8 @@ ELFFile<ELFT>::getVersionDefinitions(const Elf_Shdr &Sec) const {
 
   Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec);
   if (!ContentsOrErr)
-    return createError("cannot read content of " + describe(*this, Sec) + ": " +
-                       toString(ContentsOrErr.takeError()));
+    return createError(ContentsOrErr.takeError(),
+                       "cannot read content of " + describe(*this, Sec));
 
   const uint8_t *Start = ContentsOrErr->data();
   const uint8_t *End = Start + ContentsOrErr->size();
@@ -1238,7 +1241,7 @@ ELFFile<ELFT>::getVersionDependencies(const Elf_Shdr &Sec,
   StringRef StrTab;
   Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Sec);
   if (!StrTabOrErr) {
-    if (Error E = WarnHandler(toString(StrTabOrErr.takeError())))
+    if (Error E = WarnHandler(StrTabOrErr.takeError()))
       return std::move(E);
   } else {
     StrTab = *StrTabOrErr;
@@ -1246,8 +1249,8 @@ ELFFile<ELFT>::getVersionDependencies(const Elf_Shdr &Sec,
 
   Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec);
   if (!ContentsOrErr)
-    return createError("cannot read content of " + describe(*this, Sec) + ": " +
-                       toString(ContentsOrErr.takeError()));
+    return createError(ContentsOrErr.takeError(),
+                       "cannot read content of " + describe(*this, Sec));
 
   const uint8_t *Start = ContentsOrErr->data();
   const uint8_t *End = Start + ContentsOrErr->size();
@@ -1333,11 +1336,12 @@ Expected<StringRef>
 ELFFile<ELFT>::getStringTable(const Elf_Shdr &Section,
                               WarningHandler WarnHandler) const {
   if (Section.sh_type != ELF::SHT_STRTAB)
-    if (Error E = WarnHandler("invalid sh_type for string table section " +
-                              getSecIndexForError(*this, Section) +
-                              ": expected SHT_STRTAB, but got " +
-                              object::getELFSectionTypeName(
-                                  getHeader().e_machine, Section.sh_type)))
+    if (Error E = WarnHandler(
+            createError("invalid sh_type for string table section " +
+                        getSecIndexForError(*this, Section) +
+                        ": expected SHT_STRTAB, but got " +
+                        object::getELFSectionTypeName(getHeader().e_machine,
+                                                      Section.sh_type))))
       return std::move(E);
 
   auto V = getSectionContentsAsArray<char>(Section);
@@ -1422,14 +1426,14 @@ ELFFile<ELFT>::getLinkAsStrtab(const typename ELFT::Shdr &Sec) const {
   Expected<const typename ELFT::Shdr *> StrTabSecOrErr =
       getSection(Sec.sh_link);
   if (!StrTabSecOrErr)
-    return createError("invalid section linked to " + describe(*this, Sec) +
-                       ": " + toString(StrTabSecOrErr.takeError()));
+    return createError(StrTabSecOrErr.takeError(),
+                       "invalid section linked to " + describe(*this, Sec));
 
   Expected<StringRef> StrTabOrErr = getStringTable(**StrTabSecOrErr);
   if (!StrTabOrErr)
-    return createError("invalid string table linked to " +
-                       describe(*this, Sec) + ": " +
-                       toString(StrTabOrErr.takeError()));
+    return createError(StrTabOrErr.takeError(),
+                       "invalid string table linked to " +
+                           describe(*this, Sec));
   return *StrTabOrErr;
 }
 
diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index 660331d5da96d..3a73cd405aabe 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -690,8 +690,8 @@ ELFFile<ELFT>::toMappedAddr(uint64_t VAddr, WarningHandler WarnHandler) const {
     return A->p_vaddr < B->p_vaddr;
   };
   if (!llvm::is_sorted(LoadSegments, SortPred)) {
-    if (Error E =
-            WarnHandler("loadable segments are unsorted by virtual address"))
+    if (Error E = WarnHandler(
+            createError("loadable segments are unsorted by virtual address")))
       return std::move(E);
     llvm::stable_sort(LoadSegments, SortPred);
   }
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 776e9c6e2f89f..410e9c26bd243 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -355,19 +355,20 @@ static StringRef ToolName;
 std::unique_ptr<BuildIDFetcher> BIDFetcher;
 
 Dumper::Dumper(const object::ObjectFile &O) : O(O), OS(outs()) {
-  WarningHandler = [this](const Twine &Msg) {
-    if (Warnings.insert(Msg.str()).second)
+  WarningHandler = [this](Error Err) {
+    std::string Msg = toString(std::move(Err));
+    if (Warnings.insert(Msg).second)
       reportWarning(Msg, this->O.getFileName());
     return Error::success();
   };
 }
 
 void Dumper::reportUniqueWarning(Error Err) {
-  reportUniqueWarning(toString(std::move(Err)));
+  cantFail(WarningHandler(std::move(Err)));
 }
 
 void Dumper::reportUniqueWarning(const Twine &Msg) {
-  cantFail(WarningHandler(Msg));
+  cantFail(WarningHandler(createError(Msg)));
 }
 
 static Expected<std::unique_ptr<Dumper>> createDumper(const ObjectFile &Obj) {
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h
index 185908b6856c4..33c6f06b048a1 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.h
+++ b/llvm/tools/llvm-objdump/llvm-objdump.h
@@ -88,7 +88,7 @@ class Dumper {
 
 protected:
   llvm::raw_ostream &OS;
-  std::function<Error(const Twine &Msg)> WarningHandler;
+  std::function<Error(Error E)> WarningHandler;
 
 public:
   Dumper(const object::ObjectFile &O);
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index bcb580119fb85..d722102a114e6 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -2028,8 +2028,8 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> &O,
 
 template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() {
   auto toMappedAddr = [&](uint64_t Tag, uint64_t VAddr) -> const uint8_t * {
-    auto MappedAddrOrError = Obj.toMappedAddr(VAddr, [&](const Twine &Msg) {
-      this->reportUniqueWarning(Msg);
+    auto MappedAddrOrError = Obj.toMappedAddr(VAddr, [&](Error E) {
+      this->reportUniqueWarning(std::move(E));
       return Error::success();
     });
     if (!MappedAddrOrError) {
diff --git a/llvm/tools/llvm-readobj/ObjDumper.cpp b/llvm/tools/llvm-readobj/ObjDumper.cpp
index 1d193573b4776..4b178b47e25bb 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.cpp
+++ b/llvm/tools/llvm-readobj/ObjDumper.cpp
@@ -33,8 +33,9 @@ static inline Error createError(const Twine &Msg) {
 ObjDumper::ObjDumper(ScopedPrinter &Writer, StringRef ObjName) : W(Writer) {
   // Dumper reports all non-critical errors as warnings.
   // It does not print the same warning more than once.
-  WarningHandler = [=](const Twine &Msg) {
-    if (Warnings.insert(Msg.str()).second)
+  WarningHandler = [=](Error E) {
+    std::string Msg = toString(std::move(E));
+    if (Warnings.insert(Msg).second)
       reportWarning(createError(Msg), ObjName);
     return Error::success();
   };
@@ -47,7 +48,7 @@ void ObjDumper::reportUniqueWarning(Error Err) const {
 }
 
 void ObjDumper::reportUniqueWarning(const Twine &Msg) const {
-  cantFail(WarningHandler(Msg),
+  cantFail(WarningHandler(createError(Msg)),
            "WarningHandler should always return ErrorSuccess");
 }
 
diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
index 0dba8252fd466..a99e3c5bf307a 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -187,7 +187,7 @@ class ObjDumper {
   void printSectionsAsHex(const object::ObjectFile &Obj,
                           ArrayRef<std::string> Sections, bool Decompress);
 
-  std::function<Error(const Twine &Msg)> WarningHandler;
+  std::function<Error(Error)> WarningHandler;
   void reportUniqueWarning(Error Err) const;
   void reportUniqueWarning(const Twine &Msg) const;
   void printOffloading(const object::ObjectFile &Obj);
diff --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp
index 1e2955ae40a66..1407493c9145f 100644
--- a/llvm/unittests/Object/ELFObjectFileTest.cpp
+++ b/llvm/unittests/Object/ELFObjectFileTest.cpp
@@ -389,9 +389,9 @@ TEST(ELFObjectFileTest, InvalidLoadSegmentsOrderTest) {
   std::string WarnString;
   auto ToMappedAddr = [&](uint64_t Addr) -> const uint8_t * {
     Expected<const uint8_t *> DataOrErr =
-        ExpectedFile->getELFFile().toMappedAddr(Addr, [&](const Twine &Msg) {
+        ExpectedFile->getELFFile().toMappedAddr(Addr, [&](Error E) {
           EXPECT_TRUE(WarnString.empty());
-          WarnString = Msg.str();
+          WarnString = toString(std::move(E));
           return Error::success();
         });
 

>From 610b4df4d9c5d7f815d6ceb48333f9146963cdf8 Mon Sep 17 00:00:00 2001
From: ShengYi Hung <aokblast at FreeBSD.org>
Date: Sun, 12 Apr 2026 20:28:32 +0800
Subject: [PATCH 3/5] [llvm-readobj][ELF] Use WrappedError to filter duplicates

Switch from StringError to WrappedError. Errors of the form "Prefix:
Error" can now be filtered out based on the underlying error while
preserving distinct prefixes, resulting in clearer llvm-readobj output.
---
 llvm/test/Object/invalid.test                 |   2 +-
 .../ELF/broken-dynamic-reloc.test             |   2 -
 .../tools/llvm-readobj/ELF/dynamic-tags.test  |  11 -
 .../tools/llvm-readobj/ELF/gnu-notes.test     |   3 +-
 .../llvm-readobj/ELF/gnu-section-mapping.test |   2 +-
 .../llvm-readobj/ELF/invalid-shstrndx.test    |   2 -
 .../llvm-readobj/ELF/packed-relocs-errors.s   |  29 +-
 .../tools/llvm-readobj/ELF/packed-relocs.test |   2 -
 .../llvm-readobj/ELF/program-headers.test     |  11 +-
 .../llvm-readobj/ELF/relocation-errors.test   |   3 -
 .../tools/llvm-readobj/ELF/relocations.test   |   3 -
 .../tools/llvm-readobj/ELF/relr-relocs.test   |   1 -
 .../tools/llvm-readobj/ELF/stack-sizes.test   |   7 -
 .../llvm-readobj/ELF/versym-invalid.test      |   2 -
 llvm/tools/llvm-readobj/ELFDumper.cpp         | 409 +++++++++---------
 llvm/tools/llvm-readobj/ObjDumper.cpp         |  28 +-
 llvm/tools/llvm-readobj/ObjDumper.h           |   3 +-
 17 files changed, 256 insertions(+), 264 deletions(-)

diff --git a/llvm/test/Object/invalid.test b/llvm/test/Object/invalid.test
index 58ec3cbeadd19..43f3b8fc7473b 100644
--- a/llvm/test/Object/invalid.test
+++ b/llvm/test/Object/invalid.test
@@ -236,7 +236,7 @@ Symbols: []
 # RUN: llvm-readobj --program-headers %p/Inputs/invalid-e_shnum.elf 2>&1 | \
 # RUN:  FileCheck -DFILE=%p/Inputs/invalid-e_shnum.elf --check-prefix=INVALID-PH-ENTSIZE %s
 
-# INVALID-PH-ENTSIZE: warning: '[[FILE]]': unable to dump program headers: invalid e_phentsize: 12336
+# INVALID-PH-ENTSIZE: warning: '[[FILE]]': unable to read program headers to locate the PT_DYNAMIC segment: invalid e_phentsize: 12336
 
 ## Check that llvm-readobj reports a warning when we have no SHT_SYMTAB_SHNDX section,
 ## but have a symbol referencing it.
diff --git a/llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test b/llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test
index 9f18248e7921d..dfdb76a68b6dd 100644
--- a/llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test
+++ b/llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test
@@ -217,7 +217,6 @@ ProgramHeaders:
 # LLVM-NO-DYNSYM:      Dynamic Relocations {
 # LLVM-NO-DYNSYM-NEXT: warning: '[[FILE]]': unable to get name of the dynamic symbol with index 0: no dynamic symbol table found
 # LLVM-NO-DYNSYM-NEXT:   0x0 R_X86_64_NONE <corrupt> 0x0
-# LLVM-NO-DYNSYM-NEXT: warning: '[[FILE]]': unable to get name of the dynamic symbol with index 1: no dynamic symbol table found
 # LLVM-NO-DYNSYM-NEXT:   0x0 R_X86_64_NONE <corrupt> 0x0
 # LLVM-NO-DYNSYM-NEXT: }
 
@@ -225,7 +224,6 @@ ProgramHeaders:
 # GNU-NO-DYNSYM-NEXT: Offset            Info             Type             Symbol's Value   Symbol's Name + Addend
 # GNU-NO-DYNSYM-NEXT: warning: '[[FILE]]': unable to get name of the dynamic symbol with index 0: no dynamic symbol table found
 # GNU-NO-DYNSYM-NEXT: 0000000000000000  0000000000000000 R_X86_64_NONE                     <corrupt> + 0
-# GNU-NO-DYNSYM-NEXT: warning: '[[FILE]]': unable to get name of the dynamic symbol with index 1: no dynamic symbol table found
 # GNU-NO-DYNSYM-NEXT: 0000000000000000  0000000100000000 R_X86_64_NONE                     <corrupt> + 0
 
 --- !ELF
diff --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test
index dec2353fa74dd..e63719c014c02 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test
+++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test
@@ -848,18 +848,7 @@ Sections:
 # RUN:     --check-prefixes=PHENTSIZE-WARN,PHENTSIZE-GNU
 
 # PHENTSIZE-WARN:      warning: '[[FILE]]': unable to read program headers to locate the PT_DYNAMIC segment: invalid e_phentsize: 1
-# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_HASH: invalid e_phentsize: 1
-# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_STRTAB: invalid e_phentsize: 1
-# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_SYMTAB: invalid e_phentsize: 1
-# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_RELA: invalid e_phentsize: 1
 # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': DT_SYMENT value of 0x987 is not the size of a symbol (0x18)
-# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_REL: invalid e_phentsize: 1
-# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_JMPREL: invalid e_phentsize: 1
-# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_SYMTAB_SHNDX: invalid e_phentsize: 1
-# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_RELR: invalid e_phentsize: 1
-# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_CREL: invalid e_phentsize: 1
-# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_ANDROID_RELR: invalid e_phentsize: 1
-# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_GNU_HASH: invalid e_phentsize: 1
 
 # PHENTSIZE-LLVM:      warning: '[[FILE]]': string table was not found
 # PHENTSIZE-LLVM-NEXT: LoadName: <?>
diff --git a/llvm/test/tools/llvm-readobj/ELF/gnu-notes.test b/llvm/test/tools/llvm-readobj/ELF/gnu-notes.test
index 49b8f0dd2c5d8..5e4b4b0852202 100644
--- a/llvm/test/tools/llvm-readobj/ELF/gnu-notes.test
+++ b/llvm/test/tools/llvm-readobj/ELF/gnu-notes.test
@@ -263,8 +263,7 @@ ProgramHeaders:
 # RUN: llvm-readobj --notes %t6.so 2>&1 | FileCheck %s -DFILE=%t6.so --check-prefix=PHENTSIZE-WARN-LLVM
 
 # PHENTSIZE-WARN-GNU: warning: '[[FILE]]': unable to read program headers to locate the PT_DYNAMIC segment: invalid e_phentsize: 1
-# PHENTSIZE-WARN-GNU: warning: '[[FILE]]': unable to read program headers to locate the PT_NOTE segment: invalid e_phentsize: 1
 
+# PHENTSIZE-WARN-LLVM: warning: '[[FILE]]': unable to read program headers to locate the PT_DYNAMIC segment: invalid e_phentsize: 1
 # PHENTSIZE-WARN-LLVM:      NoteSections [
-# PHENTSIZE-WARN-LLVM-NEXT: warning: '[[FILE]]': unable to read program headers to locate the PT_NOTE segment: invalid e_phentsize: 1
 # PHENTSIZE-WARN-LLVM-NEXT: ]
diff --git a/llvm/test/tools/llvm-readobj/ELF/gnu-section-mapping.test b/llvm/test/tools/llvm-readobj/ELF/gnu-section-mapping.test
index 24eb004a8a476..a83469e49042e 100644
--- a/llvm/test/tools/llvm-readobj/ELF/gnu-section-mapping.test
+++ b/llvm/test/tools/llvm-readobj/ELF/gnu-section-mapping.test
@@ -77,6 +77,6 @@ ProgramHeaders:
 # RUN: llvm-readelf --section-mapping %t64-err1.elf 2>&1 | \
 # RUN:   FileCheck %s -DFILE=%t64-err1.elf --check-prefix=PHENTSIZE
 
+# PHENTSIZE: warning: '[[FILE]]': unable to read program headers to locate the PT_DYNAMIC segment: invalid e_phentsize: 1
 # PHENTSIZE:      Section to Segment mapping:
 # PHENTSIZE-NEXT:  Segment Sections...
-# PHENTSIZE-NEXT: warning: '[[FILE]]': can't read program headers to build section to segment mapping: invalid e_phentsize: 1
diff --git a/llvm/test/tools/llvm-readobj/ELF/invalid-shstrndx.test b/llvm/test/tools/llvm-readobj/ELF/invalid-shstrndx.test
index 7d424ec6db0ff..9a8ae131504d0 100644
--- a/llvm/test/tools/llvm-readobj/ELF/invalid-shstrndx.test
+++ b/llvm/test/tools/llvm-readobj/ELF/invalid-shstrndx.test
@@ -36,10 +36,8 @@
 # LLVM-NEXT:   EntrySize: 0
 # LLVM-NEXT: }
 # LLVM:      Index: 1
-# LLVM-NEXT: warning: '[[FILE]]': unable to get the name of SHT_STRTAB section with index 1: section header string table index 255 does not exist
 # LLVM-NEXT: Name: <?> (11)
 # LLVM:      Index: 2
-# LLVM-NEXT: warning: '[[FILE]]': unable to get the name of SHT_STRTAB section with index 2: section header string table index 255 does not exist
 # LLVM-NEXT: Name: <?> (1)
 
 --- !ELF
diff --git a/llvm/test/tools/llvm-readobj/ELF/packed-relocs-errors.s b/llvm/test/tools/llvm-readobj/ELF/packed-relocs-errors.s
index 32e96d716ca44..51b6a2ef25799 100644
--- a/llvm/test/tools/llvm-readobj/ELF/packed-relocs-errors.s
+++ b/llvm/test/tools/llvm-readobj/ELF/packed-relocs-errors.s
@@ -6,28 +6,30 @@
 # RUN: split-file %s %t
 
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t/asm1.s -o %t1.o
-# RUN: llvm-readobj --relocations %t1.o 2>&1 | FileCheck %s -DFILE=%t1.o --check-prefix=ERR-HEADER
-# RUN: llvm-readelf --relocations %t1.o 2>&1 | FileCheck %s -DFILE=%t1.o --check-prefix=ERR-HEADER
+# RUN: llvm-readobj --relocations %t1.o 2>&1 | FileCheck %s -DFILE=%t1.o --check-prefix=ERR-HEADER-LLVM
+# RUN: llvm-readelf --relocations %t1.o 2>&1 | FileCheck %s -DFILE=%t1.o --check-prefix=ERR-HEADER-GNU
 
 #--- asm1.s
 .section .rela.dyn, "a", @0x60000001
 .ascii "APS9"
 
-# ERR-HEADER: warning: '[[FILE]]': unable to read relocations from SHT_ANDROID_REL section with index 3: invalid packed relocation header
+# ERR-HEADER-LLVM: warning: '[[FILE]]': unable to read relocations from SHT_ANDROID_REL section with index 3: invalid packed relocation header
+# ERR-HEADER-GNU: warning: '[[FILE]]': unable to get the number of relocations in SHT_ANDROID_REL section with index 3: invalid packed relocation header
 
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t/asm2.s -o %t2.o
-# RUN: llvm-readobj --relocations %t2.o 2>&1 | FileCheck %s -DFILE=%t2.o --check-prefix=ERR-PAST-END
-# RUN: llvm-readelf --relocations %t2.o 2>&1 | FileCheck %s -DFILE=%t2.o --check-prefix=ERR-PAST-END
+# RUN: llvm-readobj --relocations %t2.o 2>&1 | FileCheck %s -DFILE=%t2.o --check-prefix=ERR-PAST-END-LLVM
+# RUN: llvm-readelf --relocations %t2.o 2>&1 | FileCheck %s -DFILE=%t2.o --check-prefix=ERR-PAST-END-GNU
 
 #--- asm2.s
 .section .rela.dyn, "a", @0x60000001
 .ascii "APS2"
 
-# ERR-PAST-END: warning: '[[FILE]]': unable to read relocations from SHT_ANDROID_REL section with index 3: unable to decode LEB128 at offset 0x{{([[:xdigit:]]{8})}}: malformed sleb128, extends past end
+# ERR-PAST-END-LLVM: warning: '[[FILE]]': unable to read relocations from SHT_ANDROID_REL section with index 3: unable to decode LEB128 at offset 0x{{([[:xdigit:]]{8})}}: malformed sleb128, extends past end
+# ERR-PAST-END-GNU: warning: '[[FILE]]': unable to get the number of relocations in SHT_ANDROID_REL section with index 3: unable to decode LEB128 at offset 0x{{([[:xdigit:]]{8})}}: malformed sleb128, extends past end
 
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t/asm3.s -o %t3.o
-# RUN: llvm-readobj --relocations %t3.o 2>&1 | FileCheck %s -DFILE=%t3.o --check-prefix=ERR-PAST-END
-# RUN: llvm-readelf --relocations %t3.o 2>&1 | FileCheck %s -DFILE=%t3.o --check-prefix=ERR-PAST-END
+# RUN: llvm-readobj --relocations %t3.o 2>&1 | FileCheck %s -DFILE=%t3.o --check-prefix=ERR-PAST-END-LLVM
+# RUN: llvm-readelf --relocations %t3.o 2>&1 | FileCheck %s -DFILE=%t3.o --check-prefix=ERR-PAST-END-GNU
 
 #--- asm3.s
 .section .rela.dyn, "a", @0x60000001
@@ -36,8 +38,8 @@
 .sleb128 0 ## Initial offset
 
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t/asm4.s -o %t4.o
-# RUN: llvm-readobj --relocations %t4.o 2>&1 | FileCheck %s -DFILE=%t4.o --check-prefix=ERR-PAST-END
-# RUN: llvm-readelf --relocations %t4.o 2>&1 | FileCheck %s -DFILE=%t4.o --check-prefix=ERR-PAST-END
+# RUN: llvm-readobj --relocations %t4.o 2>&1 | FileCheck %s -DFILE=%t4.o --check-prefix=ERR-PAST-END-LLVM
+# RUN: llvm-readelf --relocations %t4.o 2>&1 | FileCheck %s -DFILE=%t4.o --check-prefix=ERR-PAST-END-GNU
 
 #--- asm4.s
 .section .rela.dyn, "a", @0x60000001
@@ -50,10 +52,11 @@
 .sleb128 8 ## offset delta
 
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t/asm5.s -o %t5.o
-# RUN: llvm-readobj --relocations %t5.o 2>&1 | FileCheck %s -DFILE=%t5.o --check-prefix=ERR-LARGE
-# RUN: llvm-readelf --relocations %t5.o 2>&1 | FileCheck %s -DFILE=%t5.o --check-prefix=ERR-LARGE
+# RUN: llvm-readobj --relocations %t5.o 2>&1 | FileCheck %s -DFILE=%t5.o --check-prefix=ERR-LARGE-LLVM
+# RUN: llvm-readelf --relocations %t5.o 2>&1 | FileCheck %s -DFILE=%t5.o --check-prefix=ERR-LARGE-GNU
 
-# ERR-LARGE: warning: '[[FILE]]': unable to read relocations from SHT_ANDROID_REL section with index 3: relocation group unexpectedly large
+# ERR-LARGE-LLVM: warning: '[[FILE]]': unable to read relocations from SHT_ANDROID_REL section with index 3: relocation group unexpectedly large
+# ERR-LARGE-GNU: warning: '[[FILE]]': unable to get the number of relocations in SHT_ANDROID_REL section with index 3: relocation group unexpectedly large
 
 #--- asm5.s
 .section .rela.dyn, "a", @0x60000001
diff --git a/llvm/test/tools/llvm-readobj/ELF/packed-relocs.test b/llvm/test/tools/llvm-readobj/ELF/packed-relocs.test
index d209a00fdd560..1bc2110b3e285 100644
--- a/llvm/test/tools/llvm-readobj/ELF/packed-relocs.test
+++ b/llvm/test/tools/llvm-readobj/ELF/packed-relocs.test
@@ -60,7 +60,6 @@ Symbols:
 # BROKEN-RELA-GNU:      warning: '[[FILE]]': unable to get the number of relocations in SHT_ANDROID_RELA section with index 1: section [index 1] has a sh_offset (0xffffffff) + sh_size (0x3a) that is greater than the file size (0x238)
 # BROKEN-RELA-GNU:      Relocation section '.rela.dyn' at offset 0xffffffff contains <?> entries:
 # BROKEN-RELA-GNU-NEXT:     Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
-# BROKEN-RELA-GNU-NEXT: warning: '[[FILE]]': unable to read relocations from SHT_ANDROID_RELA section with index 1: section [index 1] has a sh_offset (0xffffffff) + sh_size (0x3a) that is greater than the file size (0x238)
 
 ## Check we report a warning when the sh_link field of the SHT_ANDROID_RELA section is broken.
 
@@ -143,7 +142,6 @@ Symbols:
 # BROKEN-REL-GNU:      warning: '[[FILE]]': unable to get the number of relocations in SHT_ANDROID_REL section with index 1: section [index 1] has a sh_offset (0xffffffff) + sh_size (0x12) that cannot be represented
 # BROKEN-REL-GNU:      Relocation section '.rel.dyn' at offset 0xffffffff contains <?> entries:
 # BROKEN-REL-GNU-NEXT:  Offset     Info    Type                Sym. Value  Symbol's Name
-# BROKEN-REL-GNU-NEXT: warning: '[[FILE]]': unable to read relocations from SHT_ANDROID_REL section with index 1: section [index 1] has a sh_offset (0xffffffff) + sh_size (0x12) that cannot be represented
 
 ## Check we report a warning when the sh_link field of the SHT_ANDROID_REL section is broken.
 
diff --git a/llvm/test/tools/llvm-readobj/ELF/program-headers.test b/llvm/test/tools/llvm-readobj/ELF/program-headers.test
index 856cf378ddad9..88c615b455489 100644
--- a/llvm/test/tools/llvm-readobj/ELF/program-headers.test
+++ b/llvm/test/tools/llvm-readobj/ELF/program-headers.test
@@ -694,7 +694,6 @@ ProgramHeaders:
 # ERROR-INTERP-NEXT: INTERP         0x000[[#OFFSET + 3]]
 # ERROR-INTERP-NEXT: warning: '[[FILE]]': unable to read program interpreter name at offset 0x[[#OFFSET+3]]: it goes past the end of the file (0x[[#OFFSET + 3]])
 # ERROR-INTERP-NEXT: INTERP         0xaabbccddeeff1122
-# ERROR-INTERP-NEXT: warning: '[[FILE]]': unable to read program interpreter name at offset 0xaabbccddeeff1122: it goes past the end of the file (0x[[#OFFSET + 3]])
 # ERROR-INTERP-NEXT: INTERP         0xaabbccddeeff1122
 
 --- !ELF
@@ -733,15 +732,14 @@ ProgramHeaders:
 # RUN: llvm-readobj --program-headers %t.phdr.err 2>&1 | \
 # RUN:   FileCheck %s -DFILE=%t.phdr.err --check-prefix=WARN-PHENTSIZE-LLVM
 
+# WARN-PHENTSIZE-GNU: warning: '[[FILE]]': unable to read program headers to locate the PT_DYNAMIC segment: invalid e_phentsize: 1
 # WARN-PHENTSIZE-GNU:      Program Headers:
 # WARN-PHENTSIZE-GNU-NEXT:   Type Offset VirtAddr PhysAddr FileSiz  MemSiz Flg Align
-# WARN-PHENTSIZE-GNU-NEXT: warning: '[[FILE]]': unable to dump program headers: invalid e_phentsize: 1
 # WARN-PHENTSIZE-GNU:      Section to Segment mapping:
 # WARN-PHENTSIZE-GNU-NEXT:   Segment Sections...
-# WARN-PHENTSIZE-GNU-NEXT: warning: '[[FILE]]': can't read program headers to build section to segment mapping: invalid e_phentsize: 1
 
+# WARN-PHENTSIZE-LLVM: warning: '[[FILE]]': unable to read program headers to locate the PT_DYNAMIC segment: invalid e_phentsize: 1
 # WARN-PHENTSIZE-LLVM:      ProgramHeaders [
-# WARN-PHENTSIZE-LLVM-NEXT: warning: '[[FILE]]': unable to dump program headers: invalid e_phentsize: 1
 # WARN-PHENTSIZE-LLVM-NEXT: ]
 
 --- !ELF
@@ -774,15 +772,14 @@ ProgramHeaders:
 # RUN: llvm-readobj --program-headers %t.phdr.err2 2>&1 | \
 # RUN:   FileCheck %s -DFILE=%t.phdr.err2 --check-prefix=WARN-PHOFF-LLVM -DOFF=0x161
 
+# WARN-PHOFF-GNU: warning: '[[FILE]]': unable to read program headers to locate the PT_DYNAMIC segment: program headers are longer than binary of size 408: e_phoff = [[OFF]], e_phnum = 1, e_phentsize = 56
 # WARN-PHOFF-GNU:      Program Headers:
 # WARN-PHOFF-GNU-NEXT:   Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
-# WARN-PHOFF-GNU-NEXT: warning: '[[FILE]]': unable to dump program headers: program headers are longer than binary of size 408: e_phoff = [[OFF]], e_phnum = 1, e_phentsize = 56
 # WARN-PHOFF-GNU:      Section to Segment mapping:
 # WARN-PHOFF-GNU-NEXT:   Segment Sections...
-# WARN-PHOFF-GNU-NEXT: warning: '[[FILE]]': can't read program headers to build section to segment mapping: program headers are longer than binary of size 408: e_phoff = [[OFF]], e_phnum = 1, e_phentsize = 56
 
+# WARN-PHOFF-LLVM: warning: '[[FILE]]': unable to read program headers to locate the PT_DYNAMIC segment: program headers are longer than binary of size 408: e_phoff = [[OFF]], e_phnum = 1, e_phentsize = 56
 # WARN-PHOFF-LLVM:      ProgramHeaders [
-# WARN-PHOFF-LLVM-NEXT: warning: '[[FILE]]': unable to dump program headers: program headers are longer than binary of size 408: e_phoff = [[OFF]], e_phnum = 1, e_phentsize = 56
 # WARN-PHOFF-LLVM-NEXT: ]
 
 ## Check we report a warning when the value of e_phoff is so large that
diff --git a/llvm/test/tools/llvm-readobj/ELF/relocation-errors.test b/llvm/test/tools/llvm-readobj/ELF/relocation-errors.test
index 87aab76de4c29..1bd607abb49a5 100644
--- a/llvm/test/tools/llvm-readobj/ELF/relocation-errors.test
+++ b/llvm/test/tools/llvm-readobj/ELF/relocation-errors.test
@@ -7,7 +7,6 @@
 # LLVM:      Relocations [
 # LLVM-NEXT:   Section (3) .rel.text {
 # LLVM-NEXT: warning: '[[FILE]]': unable to print relocation 0 in SHT_REL section with index 3: unable to read an entry with index 4278124286 from SHT_SYMTAB section with index 6: can't read an entry at 0x17e7e7e7d0: it goes past the end of the section (0x90)
-# LLVM-NEXT: warning: '[[FILE]]': unable to print relocation 1 in SHT_REL section with index 3: unable to read an entry with index 4278124286 from SHT_SYMTAB section with index 6: can't read an entry at 0x17e7e7e7d0: it goes past the end of the section (0x90)
 # LLVM-NEXT:     0x2 R_X86_64_NONE -{{$}}
 # LLVM-NEXT:     0x3 R_X86_64_NONE .sec.symbol1{{$}}
 # LLVM-NEXT: warning: '[[FILE]]': invalid section index: 255
@@ -24,7 +23,6 @@
 # GNU:       Relocation section '.rel.text' at offset 0x41 contains 7 entries:
 # GNU-NEXT:      Offset             Info             Type               Symbol's Value  Symbol's Name
 # GNU-NEXT:  warning: '[[FILE]]': unable to print relocation 0 in SHT_REL section with index 3: unable to read an entry with index 4278124286 from SHT_SYMTAB section with index 6: can't read an entry at 0x17e7e7e7d0: it goes past the end of the section (0x90)
-# GNU-NEXT:  warning: '[[FILE]]': unable to print relocation 1 in SHT_REL section with index 3: unable to read an entry with index 4278124286 from SHT_SYMTAB section with index 6: can't read an entry at 0x17e7e7e7d0: it goes past the end of the section (0x90)
 # GNU-NEXT:  0000000000000002  0000000000000000 R_X86_64_NONE
 # GNU-NEXT:  0000000000000003  0000000200000000 R_X86_64_NONE 0000000000000000 .sec.symbol1
 # GNU-NEXT:  warning: '[[FILE]]': invalid section index: 255
@@ -43,7 +41,6 @@
 # CREL-GNU:       Relocation section '.rel.text' at offset 0x41 contains 7 entries:
 # CREL-GNU-NEXT:      Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
 # CREL-GNU-NEXT:  warning: '[[FILE]]': unable to print relocation 0 in SHT_CREL section with index 3: unable to read an entry with index 4278124286 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0
-# CREL-GNU-NEXT:  warning: '[[FILE]]': unable to print relocation 1 in SHT_CREL section with index 3: unable to read an entry with index 4278124286 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0
 # CREL-GNU-NEXT:  0000000000000002  0000000000000000 R_X86_64_NONE                     0
 # CREL-GNU-NEXT:  warning: '[[FILE]]': unable to print relocation 3 in SHT_CREL section with index 3: unable to read an entry with index 2 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0
 # CREL-GNU-NEXT:  warning: '[[FILE]]': unable to print relocation 4 in SHT_CREL section with index 3: unable to read an entry with index 4 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0
diff --git a/llvm/test/tools/llvm-readobj/ELF/relocations.test b/llvm/test/tools/llvm-readobj/ELF/relocations.test
index 34cff4098514d..ef832f79b8990 100644
--- a/llvm/test/tools/llvm-readobj/ELF/relocations.test
+++ b/llvm/test/tools/llvm-readobj/ELF/relocations.test
@@ -360,7 +360,6 @@ Symbols:
 
 # BROKEN-REL-GNU:      Relocation section '.rel.text' at offset 0x51 contains 64 entries:
 # BROKEN-REL-GNU-NEXT:     Offset             Info             Type       Symbol's Value  Symbol's Name
-# BROKEN-REL-GNU-NEXT: warning: '[[FILE]]': unable to read relocations from SHT_REL section with index 2: section [index 2] has invalid sh_entsize: expected 16, but got 1
 # BROKEN-REL-GNU:      Relocation section '.rela.text' at offset 0x91 contains 5 entries:
 # BROKEN-REL-GNU-NEXT:     Offset             Info             Type       Symbol's Value  Symbol's Name
 # BROKEN-REL-GNU-NEXT: 0000000000000000  0000000500000000 R_X86_64_NONE  0000000000000000 rela_0 + 0
@@ -413,7 +412,6 @@ Symbols:
 # BROKEN-LINK-LLVM-NEXT: warning: '[[FILE]]': unable to locate a symbol table for SHT_REL section with index 2: invalid section index: 65535
 # BROKEN-LINK-LLVM-NEXT:   }
 # BROKEN-LINK-LLVM-NEXT:   Section (3) .rela.text {
-# BROKEN-LINK-LLVM-NEXT: warning: '[[FILE]]': unable to locate a symbol table for SHT_RELA section with index 3: invalid section index: 65535
 # BROKEN-LINK-LLVM-NEXT:   }
 # BROKEN-LINK-LLVM-NEXT: ]
 
@@ -423,7 +421,6 @@ Symbols:
 # BROKEN-LINK-GNU-EMPTY:
 # BROKEN-LINK-GNU-NEXT: Relocation section '.rela.text' at offset 0x91 contains 5 entries:
 # BROKEN-LINK-GNU-NEXT:     Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
-# BROKEN-LINK-GNU-NEXT: warning: '[[FILE]]': unable to locate a symbol table for SHT_RELA section with index 3: invalid section index: 65535
 
 ## Show that ELF32 is dumped correctly.
 # RUN: yaml2obj %s --docnum=2 -o %t32
diff --git a/llvm/test/tools/llvm-readobj/ELF/relr-relocs.test b/llvm/test/tools/llvm-readobj/ELF/relr-relocs.test
index c22239900bcf2..b2c63ffc704a6 100644
--- a/llvm/test/tools/llvm-readobj/ELF/relr-relocs.test
+++ b/llvm/test/tools/llvm-readobj/ELF/relr-relocs.test
@@ -166,7 +166,6 @@ Symbols:
 
 # BROKEN-GNU:      warning: '[[FILE]]': unable to get the number of relocations in [[SECNAME]] section with index 1: section [index 1] has invalid sh_entsize: expected 4, but got 1
 # BROKEN-GNU:      Relocation section '.relr.dyn' at offset 0x34 contains <?> entries:
-# BROKEN-GNU-NEXT: warning: '[[FILE]]': unable to read relocations from [[SECNAME]] section with index 1: section [index 1] has invalid sh_entsize: expected 4, but got 1
 
 ## Case B: check the case when relocations can't be read from an SHT_ANDROID_RELR section.
 ##         SHT_ANDROID_RELR = 0x6fffff00.
diff --git a/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test b/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
index c2f25f0d1800c..b147a0970ff8d 100644
--- a/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
+++ b/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
@@ -152,7 +152,6 @@ Symbols:
 # SYM-GNU-NEXT: warning: '[[FILE]]': could not identify function symbol for stack size entry in SHT_PROGBITS section with index 3
 # SYM-GNU-NEXT:            16     ?
 # SYM-GNU-NEXT:            32     ?
-# SYM-GNU-NEXT: warning: '[[FILE]]': cannot identify the section for relocation symbol 'separate_text_section_baz': invalid section index: 255
 # SYM-GNU-NEXT: warning: '[[FILE]]': could not identify function symbol for stack size entry in SHT_PROGBITS section with index 4
 # SYM-GNU-NEXT:             8     ?
 
@@ -167,7 +166,6 @@ Symbols:
 # SYM-LLVM-NEXT:     Functions: [?]
 # SYM-LLVM-NEXT:     Size: 0x20
 # SYM-LLVM-NEXT:   }
-# SYM-LLVM-NEXT: warning: '[[FILE]]': cannot identify the section for relocation symbol 'separate_text_section_baz': invalid section index: 255
 # SYM-LLVM-NEXT: warning: '[[FILE]]': could not identify function symbol for stack size entry in SHT_PROGBITS section with index 4
 # SYM-LLVM-NEXT:   Entry {
 # SYM-LLVM-NEXT:     Functions: [?]
@@ -441,7 +439,6 @@ Symbols:
 # RUN:   FileCheck %s --check-prefix=BADSIZE -DFILE=%t06 --implicit-check-not=warning:
 
 # BADSIZE: warning: '[[FILE]]': could not extract a valid stack size from SHT_PROGBITS section with index 2: unable to decode LEB128 at offset 0x00000008: malformed uleb128, extends past end
-# BADSIZE: warning: '[[FILE]]': could not extract a valid stack size from SHT_PROGBITS section with index 3: unable to decode LEB128 at offset 0x00000008: malformed uleb128, extends past end
 
 --- !ELF
 FileHeader:
@@ -481,17 +478,14 @@ Symbols:
 # BADSECTION-OUT-GNU:      Stack Sizes:
 # BADSECTION-OUT-GNU-NEXT:          Size     Functions
 # BADSECTION-OUT-GNU-NEXT: warning: '[[FILE]]': cannot identify the section for relocation symbol '_Z3foof': invalid section index: 10
-# BADSECTION-OUT-GNU-NEXT: warning: '[[FILE]]': unable to get address of symbol '_Z3foof': invalid section index: 10
 # BADSECTION-OUT-GNU-NEXT: warning: '[[FILE]]': could not identify function symbol for stack size entry in SHT_PROGBITS section with index 2
 # BADSECTION-OUT-GNU-NEXT:             8     ?
 # BADSECTION-OUT-GNU-NEXT: warning: '[[FILE]]': unable to get the target of relocation with index 1 in SHT_RELA section with index 3: unable to read an entry with index 255 from SHT_SYMTAB section with index 4: can't read an entry at 0x17e8: it goes past the end of the section (0x30)
 # BADSECTION-OUT-GNU-NEXT:            22     ?
-# BADSECTION-OUT-GNU-NEXT: warning: '[[FILE]]': unable to get the target of relocation with index 2 in SHT_RELA section with index 3: unable to read an entry with index 255 from SHT_SYMTAB section with index 4: can't read an entry at 0x17e8: it goes past the end of the section (0x30)
 # BADSECTION-OUT-GNU-NEXT:            36     ?
 
 # BADSECTION-OUT-LLVM:      StackSizes [
 # BADSECTION-OUT-LLVM-NEXT: warning: '[[FILE]]': cannot identify the section for relocation symbol '_Z3foof': invalid section index: 10
-# BADSECTION-OUT-LLVM-NEXT: warning: '[[FILE]]': unable to get address of symbol '_Z3foof': invalid section index: 10
 # BADSECTION-OUT-LLVM-NEXT: warning: '[[FILE]]': could not identify function symbol for stack size entry in SHT_PROGBITS section with index 2
 # BADSECTION-OUT-LLVM-NEXT:   Entry {
 # BADSECTION-OUT-LLVM-NEXT:     Functions: [?]
@@ -502,7 +496,6 @@ Symbols:
 # BADSECTION-OUT-LLVM-NEXT:     Functions: [?]
 # BADSECTION-OUT-LLVM-NEXT:     Size: 0x16
 # BADSECTION-OUT-LLVM-NEXT:   }
-# BADSECTION-OUT-LLVM-NEXT: warning: '[[FILE]]': unable to get the target of relocation with index 2 in SHT_RELA section with index 3: unable to read an entry with index 255 from SHT_SYMTAB section with index 4: can't read an entry at 0x17e8: it goes past the end of the section (0x30)
 # BADSECTION-OUT-LLVM-NEXT:   Entry {
 # BADSECTION-OUT-LLVM-NEXT:     Functions: [?]
 # BADSECTION-OUT-LLVM-NEXT:     Size: 0x24
diff --git a/llvm/test/tools/llvm-readobj/ELF/versym-invalid.test b/llvm/test/tools/llvm-readobj/ELF/versym-invalid.test
index 0c4ce6b98816e..6fe1e44b5fb02 100644
--- a/llvm/test/tools/llvm-readobj/ELF/versym-invalid.test
+++ b/llvm/test/tools/llvm-readobj/ELF/versym-invalid.test
@@ -148,7 +148,6 @@ DynamicSymbols: []
 # INVALID-ENT-SIZE-GNU-NEXT:      1: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   UND foo@<corrupt>
 # INVALID-ENT-SIZE-GNU:      Version symbols section '.gnu.version' contains 1 entries:
 # INVALID-ENT-SIZE-GNU-NEXT:  Addr: 0000000000000000  Offset: 0x000040  Link: 2 (.dynsym)
-# INVALID-ENT-SIZE-GNU-NEXT: warning: '[[FILE]]': cannot read content of SHT_GNU_versym section with index 1: section [index 1] has invalid sh_entsize: expected 2, but got 3
 
 # INVALID-ENT-SIZE-LLVM:      DynamicSymbols [
 # INVALID-ENT-SIZE-LLVM-NEXT: warning: '[[FILE]]': section [index 1] has invalid sh_entsize: expected 2, but got 3
@@ -172,7 +171,6 @@ DynamicSymbols: []
 # INVALID-ENT-SIZE-LLVM-NEXT:   }
 # INVALID-ENT-SIZE-LLVM-NEXT: ]
 # INVALID-ENT-SIZE-LLVM:      VersionSymbols [
-# INVALID-ENT-SIZE-LLVM-NEXT: warning: '[[FILE]]': cannot read content of SHT_GNU_versym section with index 1: section [index 1] has invalid sh_entsize: expected 2, but got 3
 # INVALID-ENT-SIZE-LLVM-NEXT: ]
 
 --- !ELF
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index d722102a114e6..7a7e6f8dbb09c 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -49,6 +49,7 @@
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/FormatVariadic.h"
@@ -488,8 +489,8 @@ Expected<SymtabLink<ELFT>> getLinkAsSymtab(const ELFFile<ELFT> &Obj,
   Expected<const typename ELFT::Shdr *> SymtabOrErr =
       Obj.getSection(Sec.sh_link);
   if (!SymtabOrErr)
-    return createError("invalid section linked to " + describe(Obj, Sec) +
-                       ": " + toString(SymtabOrErr.takeError()));
+    return createError(SymtabOrErr.takeError(),
+                       "invalid section linked to " + describe(Obj, Sec));
 
   if ((*SymtabOrErr)->sh_type != ExpectedType)
     return createError(
@@ -502,13 +503,14 @@ Expected<SymtabLink<ELFT>> getLinkAsSymtab(const ELFFile<ELFT> &Obj,
   Expected<StringRef> StrTabOrErr = Obj.getLinkAsStrtab(**SymtabOrErr);
   if (!StrTabOrErr)
     return createError(
+        StrTabOrErr.takeError(),
         "can't get a string table for the symbol table linked to " +
-        describe(Obj, Sec) + ": " + toString(StrTabOrErr.takeError()));
+            describe(Obj, Sec));
 
   Expected<typename ELFT::SymRange> SymsOrErr = Obj.symbols(*SymtabOrErr);
   if (!SymsOrErr)
-    return createError("unable to read symbols from the " + describe(Obj, Sec) +
-                       ": " + toString(SymsOrErr.takeError()));
+    return createError(SymsOrErr.takeError(),
+                       "unable to read symbols from the " + describe(Obj, Sec));
 
   return SymtabLink<ELFT>{*SymsOrErr, *StrTabOrErr, *SymtabOrErr};
 }
@@ -529,8 +531,8 @@ ELFDumper<ELFT>::getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab,
   Expected<ArrayRef<Elf_Versym>> VersionsOrErr =
       Obj.template getSectionContentsAsArray<Elf_Versym>(Sec);
   if (!VersionsOrErr)
-    return createError("cannot read content of " + describe(Sec) + ": " +
-                       toString(VersionsOrErr.takeError()));
+    return createError(VersionsOrErr.takeError(),
+                       "cannot read content of " + describe(Sec));
 
   Expected<SymtabLink<ELFT>> SymTabOrErr =
       getLinkAsSymtab(Obj, Sec, SHT_DYNSYM);
@@ -566,14 +568,14 @@ ELFDumper<ELFT>::getSymtabAndStrtab() const {
     StrTable = *StrTableOrErr;
   else
     reportUniqueWarning(
-        "unable to get the string table for the SHT_SYMTAB section: " +
-        toString(StrTableOrErr.takeError()));
+        toString(StrTableOrErr.takeError()),
+        "unable to get the string table for the SHT_SYMTAB section");
 
   if (Expected<Elf_Sym_Range> SymsOrErr = Obj.symbols(DotSymtabSec))
     Syms = *SymsOrErr;
   else
-    reportUniqueWarning("unable to read symbols from the SHT_SYMTAB section: " +
-                        toString(SymsOrErr.takeError()));
+    reportUniqueWarning(toString(SymsOrErr.takeError()),
+                        "unable to read symbols from the SHT_SYMTAB section");
   return {Syms, StrTable};
 }
 
@@ -945,9 +947,9 @@ ELFDumper<ELFT>::getRelocationTarget(const Relocation<ELFT> &R,
   Expected<const Elf_Sym *> SymOrErr =
       Obj.template getEntry<Elf_Sym>(*SymTab, R.Symbol);
   if (!SymOrErr)
-    return createError("unable to read an entry with index " + Twine(R.Symbol) +
-                       " from " + describe(*SymTab) + ": " +
-                       toString(SymOrErr.takeError()));
+    return createError(SymOrErr.takeError(),
+                       "unable to read an entry with index " + Twine(R.Symbol) +
+                           " from " + describe(*SymTab));
   const Elf_Sym *Sym = *SymOrErr;
   if (!Sym)
     return RelSymbol<ELFT>(nullptr, "");
@@ -982,8 +984,9 @@ static std::string maybeDemangle(StringRef Name) {
 template <typename ELFT>
 std::string ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {
   auto Warn = [&](Error E) -> std::string {
-    reportUniqueWarning("unable to read the name of symbol with index " +
-                        Twine(Index) + ": " + toString(std::move(E)));
+    reportUniqueWarning(toString(std::move(E)),
+                        "unable to read the name of symbol with index " +
+                            Twine(Index));
     return "<?>";
   };
 
@@ -1814,8 +1817,8 @@ ELFDumper<ELFT>::findDynamic() {
     }
   } else {
     reportUniqueWarning(
-        "unable to read program headers to locate the PT_DYNAMIC segment: " +
-        toString(PhdrsOrErr.takeError()));
+        toString(PhdrsOrErr.takeError()),
+        "unable to read program headers to locate the PT_DYNAMIC segment");
   }
 
   // Try to locate the .dynamic section in the sections header table.
@@ -1892,9 +1895,9 @@ void ELFDumper<ELFT>::loadDynamicTable() {
       FromSec.EntSizePrintName = "";
       IsSecTableValid = !FromSec.template getAsArrayRef<Elf_Dyn>().empty();
     } else {
-      reportUniqueWarning("unable to read the dynamic table from " +
-                          describe(*DynamicSec) + ": " +
-                          toString(RegOrErr.takeError()));
+      reportUniqueWarning(toString(RegOrErr.takeError()),
+                          "unable to read the dynamic table from " +
+                              describe(*DynamicSec));
     }
   }
 
@@ -1972,12 +1975,13 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> &O,
           if (Expected<StringRef> E = Obj.getStringTableForSymtab(Sec))
             DynamicStringTable = *E;
           else
-            reportUniqueWarning("unable to get the string table for the " +
-                                describe(Sec) + ": " + toString(E.takeError()));
+            reportUniqueWarning(toString(E.takeError()),
+                                "unable to get the string table for the " +
+                                    describe(Sec));
         } else {
-          reportUniqueWarning("unable to read dynamic symbols from " +
-                              describe(Sec) + ": " +
-                              toString(RegOrErr.takeError()));
+          reportUniqueWarning(toString(RegOrErr.takeError()),
+                              "unable to read dynamic symbols from " +
+                                  describe(Sec));
         }
       }
       break;
@@ -2033,9 +2037,9 @@ template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() {
       return Error::success();
     });
     if (!MappedAddrOrError) {
-      this->reportUniqueWarning("unable to parse DT_" +
-                                Obj.getDynamicTagAsString(Tag) + ": " +
-                                llvm::toString(MappedAddrOrError.takeError()));
+      this->reportUniqueWarning(llvm::toString(MappedAddrOrError.takeError()),
+                                "unable to parse DT_" +
+                                    Obj.getDynamicTagAsString(Tag));
       return nullptr;
     }
     return MappedAddrOrError.get();
@@ -2331,8 +2335,8 @@ ELFDumper<ELFT>::findSectionByName(StringRef Name) const {
       if (*NameOrErr == Name)
         return &Shdr;
     } else {
-      reportUniqueWarning("unable to read the name of " + describe(Shdr) +
-                          ": " + toString(NameOrErr.takeError()));
+      reportUniqueWarning(toString(NameOrErr.takeError()),
+                          "unable to read the name of " + describe(Shdr));
     }
   }
   return nullptr;
@@ -2756,9 +2760,9 @@ void ELFDumper<ELFT>::printGnuHashTable() {
   Expected<ArrayRef<Elf_Word>> Chains =
       getGnuHashTableChains<ELFT>(DynSymRegion, GnuHashTable);
   if (!Chains) {
-    reportUniqueWarning("unable to dump 'Values' for the SHT_GNU_HASH "
-                        "section: " +
-                        toString(Chains.takeError()));
+    reportUniqueWarning(toString(Chains.takeError()),
+                        "unable to dump 'Values' for the SHT_GNU_HASH "
+                        "section");
     return;
   }
 
@@ -2805,10 +2809,10 @@ void ELFDumper<ELFT>::printHashHistogram(const Elf_Hash &HashTable) const {
       if (C == ELF::STN_UNDEF)
           break;
       if (Visited[C]) {
-          this->reportUniqueWarning(
-              ".hash section is invalid: bucket " + Twine(C) +
-              ": a cycle was detected in the linked chain");
-          break;
+        this->reportUniqueWarning("a cycle was detected in the linked chain",
+                                  ".hash section is invalid: bucket " +
+                                      Twine(C));
+        break;
       }
       Visited[C] = true;
       if (MaxChain <= ++ChainLen[B])
@@ -2835,8 +2839,8 @@ void ELFDumper<ELFT>::printGnuHashHistogram(
   Expected<ArrayRef<Elf_Word>> ChainsOrErr =
       getGnuHashTableChains<ELFT>(this->DynSymRegion, &GnuHashTable);
   if (!ChainsOrErr) {
-    this->reportUniqueWarning("unable to print the GNU hash table histogram: " +
-                              toString(ChainsOrErr.takeError()));
+    this->reportUniqueWarning(toString(ChainsOrErr.takeError()),
+                              "unable to print the GNU hash table histogram");
     return;
   }
 
@@ -2955,16 +2959,17 @@ void ELFDumper<ELFT>::printAttributes(
         continue;
       }
     } else {
-      reportUniqueWarning("unable to read the content of the " + describe(Sec) +
-                          ": " + toString(ContentOrErr.takeError()));
+      reportUniqueWarning(toString(ContentOrErr.takeError()),
+                          "unable to read the content of the " + describe(Sec));
       continue;
     }
 
     W.printHex("FormatVersion", Contents[0]);
 
     if (Error E = AttrParser->parse(Contents, Endianness))
-      reportUniqueWarning("unable to dump attributes from the " +
-                          describe(Sec) + ": " + toString(std::move(E)));
+      reportUniqueWarning(toString(std::move(E)),
+                          "unable to dump attributes from the " +
+                              describe(Sec));
   }
 }
 
@@ -3148,24 +3153,24 @@ Error MipsGOTParser<ELFT>::findPLT(Elf_Dyn_Range DynTable) {
         Entries(reinterpret_cast<const Entry *>(PltContentOrErr->data()),
                 PltContentOrErr->size() / sizeof(Entry));
   else
-    return createError("unable to read PLTGOT section content: " +
-                       toString(PltContentOrErr.takeError()));
+    return createError(PltContentOrErr.takeError(),
+                       "unable to read PLTGOT section content");
 
   if (Expected<const Elf_Shdr *> PltSymTableOrErr =
           Obj.getSection(PltRelSec->sh_link))
     PltSymTable = *PltSymTableOrErr;
   else
-    return createError("unable to get a symbol table linked to the " +
-                       describe(Obj, *PltRelSec) + ": " +
-                       toString(PltSymTableOrErr.takeError()));
+    return createError(PltSymTableOrErr.takeError(),
+                       "unable to get a symbol table linked to the " +
+                           describe(Obj, *PltRelSec));
 
   if (Expected<StringRef> StrTabOrErr =
           Obj.getStringTableForSymtab(*PltSymTable))
     PltStrTable = *StrTabOrErr;
   else
-    return createError("unable to get a string table for the " +
-                       describe(Obj, *PltSymTable) + ": " +
-                       toString(StrTabOrErr.takeError()));
+    return createError(StrTabOrErr.takeError(),
+                       "unable to get a string table for the " +
+                           describe(Obj, *PltSymTable));
 
   return Error::success();
 }
@@ -3374,8 +3379,9 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsReginfo() {
       Obj.getSectionContents(*RegInfoSec);
   if (!ContentsOrErr) {
     this->reportUniqueWarning(
+        toString(ContentsOrErr.takeError()),
         "unable to read the content of the .reginfo section (" +
-        describe(*RegInfoSec) + "): " + toString(ContentsOrErr.takeError()));
+            describe(*RegInfoSec) + ")");
     return;
   }
 
@@ -3470,9 +3476,9 @@ template <class ELFT> void ELFDumper<ELFT>::printStackMap() const {
     return;
 
   auto Warn = [&](Error &&E) {
-    this->reportUniqueWarning("unable to read the stack map from " +
-                              describe(*StackMapSection) + ": " +
-                              toString(std::move(E)));
+    this->reportUniqueWarning(toString(std::move(E)),
+                              "unable to read the stack map from " +
+                                  describe(*StackMapSection));
   };
 
   Expected<ArrayRef<uint8_t>> ContentOrErr =
@@ -3496,9 +3502,9 @@ void ELFDumper<ELFT>::printReloc(const Relocation<ELFT> &R, unsigned RelIndex,
                                  const Elf_Shdr &Sec, const Elf_Shdr *SymTab) {
   Expected<RelSymbol<ELFT>> Target = getRelocationTarget(R, SymTab);
   if (!Target) {
-    reportUniqueWarning("unable to print relocation " + Twine(RelIndex) +
-                        " in " + describe(Sec) + ": " +
-                        toString(Target.takeError()));
+    reportUniqueWarning(toString(Target.takeError()),
+                        "unable to print relocation " + Twine(RelIndex) +
+                            " in " + describe(Sec));
     return;
   }
 
@@ -3788,9 +3794,9 @@ template <class ELFT> std::vector<GroupSection> ELFDumper<ELFT>::getGroups() {
                           const Elf_Shdr &Symtab) -> StringRef {
     Expected<StringRef> StrTableOrErr = Obj.getStringTableForSymtab(Symtab);
     if (!StrTableOrErr) {
-      reportUniqueWarning("unable to get the string table for " +
-                          describe(Symtab) + ": " +
-                          toString(StrTableOrErr.takeError()));
+      reportUniqueWarning(toString(StrTableOrErr.takeError()),
+                          "unable to get the string table for " +
+                              describe(Symtab));
       return "<?>";
     }
 
@@ -3820,26 +3826,27 @@ template <class ELFT> std::vector<GroupSection> ELFDumper<ELFT>::getGroups() {
               Obj.template getEntry<Elf_Sym>(**SymtabOrErr, Sec.sh_info))
         Signature = GetSignature(**SymOrErr, Sec.sh_info, **SymtabOrErr);
       else
-        reportUniqueWarning("unable to get the signature symbol for " +
-                            describe(Sec) + ": " +
-                            toString(SymOrErr.takeError()));
+        reportUniqueWarning(toString(SymOrErr.takeError()),
+                            "unable to get the signature symbol for " +
+                                describe(Sec));
     } else {
-      reportUniqueWarning("unable to get the symbol table for " +
-                          describe(Sec) + ": " +
-                          toString(SymtabOrErr.takeError()));
+      reportUniqueWarning(toString(SymtabOrErr.takeError()),
+                          "unable to get the symbol table for " +
+                              describe(Sec));
     }
 
     ArrayRef<Elf_Word> Data;
     if (Expected<ArrayRef<Elf_Word>> ContentsOrErr =
             Obj.template getSectionContentsAsArray<Elf_Word>(Sec)) {
       if (ContentsOrErr->empty())
-        reportUniqueWarning("unable to read the section group flag from the " +
-                            describe(Sec) + ": the section is empty");
+        reportUniqueWarning("the section is empty",
+                            "unable to read the section group flag from the " +
+                                describe(Sec));
       else
         Data = *ContentsOrErr;
     } else {
-      reportUniqueWarning("unable to get the content of the " + describe(Sec) +
-                          ": " + toString(ContentsOrErr.takeError()));
+      reportUniqueWarning(toString(ContentsOrErr.takeError()),
+                          "unable to get the content of the " + describe(Sec));
     }
 
     Ret.push_back({getPrintableSectionName(Sec),
@@ -3859,9 +3866,10 @@ template <class ELFT> std::vector<GroupSection> ELFDumper<ELFT>::getGroups() {
       if (Expected<const Elf_Shdr *> SecOrErr = Obj.getSection(Ndx)) {
         GM.push_back({getPrintableSectionName(**SecOrErr), Ndx});
       } else {
-        reportUniqueWarning("unable to get the section with index " +
-                            Twine(Ndx) + " when dumping the " + describe(Sec) +
-                            ": " + toString(SecOrErr.takeError()));
+        reportUniqueWarning(toString(SecOrErr.takeError()),
+                            "unable to get the section with index " +
+                                Twine(Ndx) + " when dumping the " +
+                                describe(Sec));
         GM.push_back({"<?>", Ndx});
       }
     }
@@ -4031,12 +4039,14 @@ template <class ELFT> void GNUELFDumper<ELFT>::printRelocations() {
     HasRelocSections = true;
 
     std::string EntriesNum = "<?>";
+    // Defer error reporting to sync the error output between LLVM and GNU
+    // implementation
     if (Expected<size_t> NumOrErr = GetEntriesNum(Sec))
       EntriesNum = std::to_string(*NumOrErr);
     else
-      this->reportUniqueWarning("unable to get the number of relocations in " +
-                                this->describe(Sec) + ": " +
-                                toString(NumOrErr.takeError()));
+      this->reportUniqueWarning(toString(NumOrErr.takeError()),
+                                "unable to get the number of relocations in " +
+                                    this->describe(Sec));
 
     uintX_t Offset = Sec.sh_offset;
     StringRef Name = this->getPrintableSectionName(Sec);
@@ -4067,9 +4077,9 @@ template <class ELFT> void GNUELFDumper<ELFT>::printRelocations() {
 template <class ELFT> void GNUELFDumper<ELFT>::printRelr(const Elf_Shdr &Sec) {
   Expected<Elf_Relr_Range> RangeOrErr = this->Obj.relrs(Sec);
   if (!RangeOrErr) {
-    this->reportUniqueWarning("unable to read relocations from " +
-                              this->describe(Sec) + ": " +
-                              toString(RangeOrErr.takeError()));
+    this->reportUniqueWarning(toString(RangeOrErr.takeError()),
+                              "unable to read relocations from " +
+                                  this->describe(Sec));
     return;
   }
   if (ELFT::Is64Bits)
@@ -4491,9 +4501,9 @@ void GNUELFDumper<ELFT>::printHashTableSymbols(const Elf_Hash &SysVHash) {
         break;
 
       if (Visited[Ch]) {
-        this->reportUniqueWarning(".hash section is invalid: bucket " +
-                                  Twine(Ch) +
-                                  ": a cycle was detected in the linked chain");
+        this->reportUniqueWarning("a cycle was detected in the linked chain",
+                                  ".hash section is invalid: bucket " +
+                                      Twine(Ch));
         break;
       }
 
@@ -4536,9 +4546,9 @@ void GNUELFDumper<ELFT>::printGnuHashTableSymbols(const Elf_GnuHash &GnuHash) {
       getGnuHashTableChains<ELFT>(this->DynSymRegion, &GnuHash);
   ArrayRef<Elf_Word> Values;
   if (!ValuesOrErr)
-    this->reportUniqueWarning("unable to get hash values for the SHT_GNU_HASH "
-                              "section: " +
-                              toString(ValuesOrErr.takeError()));
+    this->reportUniqueWarning(toString(ValuesOrErr.takeError()),
+                              "unable to get hash values for the SHT_GNU_HASH "
+                              "section");
   else
     Values = *ValuesOrErr;
 
@@ -4820,8 +4830,8 @@ template <class ELFT> void GNUELFDumper<ELFT>::printProgramHeaders() {
 
   Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = this->Obj.program_headers();
   if (!PhdrsOrErr) {
-    this->reportUniqueWarning("unable to dump program headers: " +
-                              toString(PhdrsOrErr.takeError()));
+    this->reportUniqueWarning(toString(PhdrsOrErr.takeError()),
+                              "unable to dump program headers");
     return;
   }
 
@@ -4840,8 +4850,8 @@ template <class ELFT> void GNUELFDumper<ELFT>::printProgramHeaders() {
       OS << "\n";
       auto ReportBadInterp = [&](const Twine &Msg) {
         this->reportUniqueWarning(
-            "unable to read program interpreter name at offset 0x" +
-            Twine::utohexstr(Phdr.p_offset) + ": " + Msg);
+            Msg, "unable to read program interpreter name at offset 0x" +
+                     Twine::utohexstr(Phdr.p_offset));
       };
 
       if (Phdr.p_offset >= this->Obj.getBufSize()) {
@@ -4874,8 +4884,8 @@ template <class ELFT> void GNUELFDumper<ELFT>::printSectionMapping() {
   Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = this->Obj.program_headers();
   if (!PhdrsOrErr) {
     this->reportUniqueWarning(
-        "can't read program headers to build section to segment mapping: " +
-        toString(PhdrsOrErr.takeError()));
+        toString(PhdrsOrErr.takeError()),
+        "can't read program headers to build section to segment mapping");
     return;
   }
 
@@ -4926,8 +4936,8 @@ RelSymbol<ELFT> getSymbolForReloc(const ELFDumper<ELFT> &Dumper,
   auto WarnAndReturn = [&](const Elf_Sym *Sym,
                            const Twine &Reason) -> RelSymbol<ELFT> {
     Dumper.reportUniqueWarning(
-        "unable to get name of the dynamic symbol with index " +
-        Twine(Reloc.Symbol) + ": " + Reason);
+        Reason, "unable to get name of the dynamic symbol with index " +
+                    Twine(Reloc.Symbol));
     return {Sym, "<corrupt>"};
   };
 
@@ -5101,9 +5111,9 @@ void GNUELFDumper<ELFT>::printGNUVersionSectionProlog(
           this->Obj.getSection(Sec.sh_link))
     LinkedSecName = this->getPrintableSectionName(**LinkedSecOrErr);
   else
-    this->reportUniqueWarning("invalid section linked to " +
-                              this->describe(Sec) + ": " +
-                              toString(LinkedSecOrErr.takeError()));
+    this->reportUniqueWarning(toString(LinkedSecOrErr.takeError()),
+                              "invalid section linked to " +
+                                  this->describe(Sec));
 
   OS << " Addr: " << format_hex_no_prefix(Sec.sh_addr, 16)
      << "  Offset: " << format_hex(Sec.sh_offset, 8)
@@ -5150,9 +5160,9 @@ void GNUELFDumper<ELFT>::printVersionSymbolSection(const Elf_Shdr *Sec) {
     Expected<StringRef> NameOrErr = this->Obj.getSymbolVersionByIndex(
         Ndx, IsDefault, *VersionMap, /*IsSymHidden=*/std::nullopt);
     if (!NameOrErr) {
-      this->reportUniqueWarning("unable to get a version for entry " +
-                                Twine(I) + " of " + this->describe(*Sec) +
-                                ": " + toString(NameOrErr.takeError()));
+      this->reportUniqueWarning(toString(NameOrErr.takeError()),
+                                "unable to get a version for entry " +
+                                    Twine(I) + " of " + this->describe(*Sec));
       Versions.emplace_back("<corrupt>");
       continue;
     }
@@ -5290,10 +5300,9 @@ bool ELFDumper<ELFT>::processCallGraphSection(const Elf_Shdr *CGSection) {
 
     uint8_t FlagsVal = Data.getU8(C);
     if (!C) {
-      reportWarning(
-          createError("failed while reading call graph info's Flags: " +
-                      toString(C.takeError())),
-          FileName);
+      reportWarning(createError(C.takeError(),
+                                "failed while reading call graph info's Flags"),
+                    FileName);
       return false;
     }
     callgraph::Flags CGFlags = static_cast<callgraph::Flags>(FlagsVal);
@@ -5313,9 +5322,8 @@ bool ELFDumper<ELFT>::processCallGraphSection(const Elf_Shdr *CGSection) {
         static_cast<uint64_t>(Data.getUnsigned(C, sizeof(typename ELFT::uint)));
     if (!C) {
       reportWarning(
-          createError(
-              "failed while reading call graph info function entry PC: " +
-              toString(C.takeError())),
+          createError(C.takeError(),
+                      "failed while reading call graph info function entry PC"),
           FileName);
       return false;
     }
@@ -5330,9 +5338,9 @@ bool ELFDumper<ELFT>::processCallGraphSection(const Elf_Shdr *CGSection) {
     CGInfo.IsIndirectTarget = IsIndirectTarget;
     uint64_t TypeID = Data.getU64(C);
     if (!C) {
-      reportWarning(createError("failed while reading function type ID: " +
-                                toString(C.takeError())),
-                    FileName);
+      reportWarning(
+          createError(C.takeError(), "failed while reading function type ID"),
+          FileName);
       return false;
     }
     CGInfo.FunctionTypeID = TypeID;
@@ -5344,8 +5352,8 @@ bool ELFDumper<ELFT>::processCallGraphSection(const Elf_Shdr *CGSection) {
       uint64_t NumDirectCallees = Data.getULEB128(C);
       if (!C) {
         reportWarning(
-            createError("failed while reading number of direct callees: " +
-                        toString(C.takeError())),
+            createError(C.takeError(),
+                        "failed while reading number of direct callees"),
             FileName);
         return false;
       }
@@ -5355,9 +5363,9 @@ bool ELFDumper<ELFT>::processCallGraphSection(const Elf_Shdr *CGSection) {
         uint64_t Callee = static_cast<uint64_t>(
             Data.getUnsigned(C, sizeof(typename ELFT::uint)));
         if (!C) {
-          reportWarning(createError("failed while reading direct callee: " +
-                                    toString(C.takeError())),
-                        FileName);
+          reportWarning(
+              createError(C.takeError(), "failed while reading direct callee"),
+              FileName);
           return false;
         }
         CGInfo.DirectCallees.insert((IsETREL ? CalleeOffset : Callee));
@@ -5369,8 +5377,8 @@ bool ELFDumper<ELFT>::processCallGraphSection(const Elf_Shdr *CGSection) {
       if (!C) {
         reportWarning(
             createError(
-                "failed while reading number of indirect target type IDs: " +
-                toString(C.takeError())),
+                C.takeError(),
+                "failed while reading number of indirect target type IDs"),
             FileName);
         return false;
       }
@@ -5379,8 +5387,8 @@ bool ELFDumper<ELFT>::processCallGraphSection(const Elf_Shdr *CGSection) {
         uint64_t TargetType = Data.getU64(C);
         if (!C) {
           reportWarning(
-              createError("failed while reading indirect target type ID: " +
-                          toString(C.takeError())),
+              createError(C.takeError(),
+                          "failed while reading indirect target type ID"),
               FileName);
           return false;
         }
@@ -5428,8 +5436,8 @@ decodeAddrsigSection(const ELFFile<ELFT> &Obj, const typename ELFT::Shdr &Sec) {
           toULEB128Array(*ContentsOrErr))
     return *SymsOrErr;
   else
-    return createError("unable to decode " + describe(Obj, Sec) + ": " +
-                       toString(SymsOrErr.takeError()));
+    return createError(SymsOrErr.takeError(),
+                       "unable to decode " + describe(Obj, Sec));
 }
 
 template <class ELFT> void GNUELFDumper<ELFT>::printAddrsig() {
@@ -6367,15 +6375,16 @@ static void processNotesHelper(
       size_t I = 0;
       for (const typename ELFT::Note Note : Obj.notes(S, Err)) {
         if (Error E = ProcessNoteFn(Note, IsCoreFile))
-          Dumper.reportUniqueWarning(
-              "unable to read note with index " + Twine(I) + " from the " +
-              describe(Obj, S) + ": " + toString(std::move(E)));
+          Dumper.reportUniqueWarning(toString(std::move(E)),
+                                     "unable to read note with index " +
+                                         Twine(I) + " from the " +
+                                         describe(Obj, S));
         ++I;
       }
       if (Err)
-        Dumper.reportUniqueWarning("unable to read notes from the " +
-                                   describe(Obj, S) + ": " +
-                                   toString(std::move(Err)));
+        Dumper.reportUniqueWarning(toString(std::move(Err)),
+                                   "unable to read notes from the " +
+                                       describe(Obj, S));
       FinishNotesFn();
     }
     return;
@@ -6384,8 +6393,8 @@ static void processNotesHelper(
   Expected<ArrayRef<typename ELFT::Phdr>> PhdrsOrErr = Obj.program_headers();
   if (!PhdrsOrErr) {
     Dumper.reportUniqueWarning(
-        "unable to read program headers to locate the PT_NOTE segment: " +
-        toString(PhdrsOrErr.takeError()));
+        toString(PhdrsOrErr.takeError()),
+        "unable to read program headers to locate the PT_NOTE segment");
     return;
   }
 
@@ -6398,16 +6407,17 @@ static void processNotesHelper(
     size_t Index = 0;
     for (const typename ELFT::Note Note : Obj.notes(P, Err)) {
       if (Error E = ProcessNoteFn(Note, IsCoreFile))
-        Dumper.reportUniqueWarning("unable to read note with index " +
-                                   Twine(Index) +
-                                   " from the PT_NOTE segment with index " +
-                                   Twine(I) + ": " + toString(std::move(E)));
+        Dumper.reportUniqueWarning(
+            toString(std::move(E)),
+            "unable to read note with index " + Twine(Index) +
+                " from the PT_NOTE segment with index " + Twine(I));
       ++Index;
     }
     if (Err)
       Dumper.reportUniqueWarning(
+          toString(std::move(Err)),
           "unable to read notes from the PT_NOTE segment with index " +
-          Twine(I) + ": " + toString(std::move(Err)));
+              Twine(I));
     FinishNotesFn();
   }
 }
@@ -6527,8 +6537,8 @@ ELFDumper<ELFT>::getMemtagGlobalsSectionContents(uint64_t ExpectedAddr) {
     Expected<ArrayRef<uint8_t>> Contents = Obj.getSectionContents(Sec);
     if (auto E = Contents.takeError()) {
       reportUniqueWarning(
-          "couldn't get SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC section contents: " +
-          toString(std::move(E)));
+          toString(std::move(E)),
+          "couldn't get SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC section contents");
       return ArrayRef<uint8_t>();
     }
     return Contents.get();
@@ -6606,8 +6616,8 @@ template <typename ELFT> void ELFDumper<ELFT>::printMemtag() {
     I += DecodedBytes;
     if (Error) {
       reportUniqueWarning(
-          "error decoding distance uleb, " + Twine(DecodedBytes) +
-          " byte(s) into SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC: " + Twine(Error));
+          Twine(Error), "error decoding distance uleb, " + Twine(DecodedBytes) +
+                            " byte(s) into SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC");
       GlobalDescriptors.clear();
       break;
     }
@@ -6620,8 +6630,9 @@ template <typename ELFT> void ELFDumper<ELFT>::printMemtag() {
       I += DecodedBytes;
       if (Error) {
         reportUniqueWarning(
+            Twine(Error),
             "error decoding size-only uleb, " + Twine(DecodedBytes) +
-            " byte(s) into SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC: " + Twine(Error));
+                " byte(s) into SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC: ");
         GlobalDescriptors.clear();
         break;
       }
@@ -6805,8 +6816,8 @@ void ELFDumper<ELFT>::printSectionsAsSFrame(ArrayRef<std::string> Sections) {
     Expected<object::SFrameParser<E>> Parser = object::SFrameParser<E>::create(
         arrayRefFromStringRef(SectionContent), Section.getAddress());
     if (!Parser) {
-      reportUniqueWarning("invalid sframe section: " +
-                          toString(Parser.takeError()));
+      reportUniqueWarning(toString(Parser.takeError()),
+                          "invalid sframe section");
       continue;
     }
 
@@ -6846,8 +6857,9 @@ void ELFDumper<ELFT>::printDependentLibsHelper(
     function_ref<void(const Elf_Shdr &)> OnSectionStart,
     function_ref<void(StringRef, uint64_t)> OnLibEntry) {
   auto Warn = [this](unsigned SecNdx, StringRef Msg) {
-    this->reportUniqueWarning("SHT_LLVM_DEPENDENT_LIBRARIES section at index " +
-                              Twine(SecNdx) + " is broken: " + Msg);
+    this->reportUniqueWarning(Msg,
+                              "SHT_LLVM_DEPENDENT_LIBRARIES section at index " +
+                                  Twine(SecNdx) + " is broken");
   };
 
   unsigned I = -1;
@@ -6886,8 +6898,8 @@ void ELFDumper<ELFT>::forEachRelocationDo(
         RelRelaFn) {
   auto Warn = [&](Error &&E,
                   const Twine &Prefix = "unable to read relocations from") {
-    this->reportUniqueWarning(Prefix + " " + describe(Sec) + ": " +
-                              toString(std::move(E)));
+    this->reportUniqueWarning(toString(std::move(E)),
+                              Prefix + " " + describe(Sec));
   };
 
   // SHT_RELR/SHT_ANDROID_RELR/SHT_AARCH64_AUTH_RELR sections do not have an
@@ -6971,8 +6983,8 @@ StringRef ELFDumper<ELFT>::getPrintableSectionName(const Elf_Shdr &Sec) const {
           Obj.getSectionName(Sec, this->WarningHandler))
     Name = *SecNameOrErr;
   else
-    this->reportUniqueWarning("unable to get the name of " + describe(Sec) +
-                              ": " + toString(SecNameOrErr.takeError()));
+    this->reportUniqueWarning(toString(SecNameOrErr.takeError()),
+                              "unable to get the name of " + describe(Sec));
   return Name;
 }
 
@@ -7033,16 +7045,17 @@ SmallVector<uint32_t> ELFDumper<ELFT>::getSymbolIndexesForFunctionAddress(
               ObjF.toSymbolRef(this->DotSymtabSec, Index).getAddress();
           if (!SymAddrOrErr) {
             std::string Name = this->getStaticSymbolName(Index);
-            reportUniqueWarning("unable to get address of symbol '" + Name +
-                                "': " + toString(SymAddrOrErr.takeError()));
+            reportUniqueWarning(toString(SymAddrOrErr.takeError()),
+                                "unable to get address of symbol '" + Name +
+                                    '\'');
             return SymbolIndexes;
           }
 
           (*this->AddressToIndexMap)[*SymAddrOrErr].push_back(Index);
         }
       } else {
-        reportUniqueWarning("unable to read the symbol table: " +
-                            toString(SymsOrError.takeError()));
+        reportUniqueWarning(toString(SymsOrError.takeError()),
+                            "unable to read the symbol table");
       }
     }
   }
@@ -7065,8 +7078,8 @@ SmallVector<uint32_t> ELFDumper<ELFT>::getSymbolIndexesForFunctionAddress(
         std::string Name = this->getStaticSymbolName(Index);
         // Note: it is impossible to trigger this error currently, it is
         // untested.
-        reportUniqueWarning("unable to get section of symbol '" + Name +
-                            "': " + toString(SecOrErr.takeError()));
+        reportUniqueWarning(toString(SecOrErr.takeError()),
+                            "unable to get section of symbol '" + Name);
         return SymbolIndexes;
       }
     }
@@ -7093,9 +7106,9 @@ bool ELFDumper<ELFT>::printFunctionStackSize(
   Error Err = Error::success();
   uint64_t StackSize = Data.getULEB128(Offset, &Err);
   if (Err) {
-    reportUniqueWarning("could not extract a valid stack size from " +
-                        describe(StackSizeSec) + ": " +
-                        toString(std::move(Err)));
+    reportUniqueWarning(toString(std::move(Err)),
+                        "could not extract a valid stack size from " +
+                            describe(StackSizeSec));
     return false;
   }
 
@@ -7134,9 +7147,9 @@ void ELFDumper<ELFT>::printStackSize(const Relocation<ELFT> &R,
   const Elf_Sym *Sym = nullptr;
   Expected<RelSymbol<ELFT>> TargetOrErr = this->getRelocationTarget(R, SymTab);
   if (!TargetOrErr)
-    reportUniqueWarning("unable to get the target of relocation with index " +
-                        Twine(Ndx) + " in " + describe(RelocSec) + ": " +
-                        toString(TargetOrErr.takeError()));
+    reportUniqueWarning(toString(TargetOrErr.takeError()),
+                        "unable to get the target of relocation with index " +
+                            Twine(Ndx) + " in " + describe(RelocSec));
   else
     Sym = TargetOrErr->Sym;
 
@@ -7146,8 +7159,9 @@ void ELFDumper<ELFT>::printStackSize(const Relocation<ELFT> &R,
         this->Obj.getSection(*Sym, SymTab, this->getShndxTable(SymTab));
     if (!SectionOrErr) {
       reportUniqueWarning(
+          toString(SectionOrErr.takeError()),
           "cannot identify the section for relocation symbol '" +
-          (*TargetOrErr).Name + "': " + toString(SectionOrErr.takeError()));
+              (*TargetOrErr).Name + '\'');
     } else if (*SectionOrErr != FunctionSec) {
       reportUniqueWarning("relocation symbol '" + (*TargetOrErr).Name +
                           "' is not in the expected section");
@@ -7222,8 +7236,8 @@ void ELFDumper<ELFT>::printRelocatableStackSizes(
   Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>>
       StackSizeRelocMapOrErr = Obj.getSectionAndRelocations(IsMatch);
   if (!StackSizeRelocMapOrErr) {
-    reportUniqueWarning("unable to get stack size map section(s): " +
-                        toString(StackSizeRelocMapOrErr.takeError()));
+    reportUniqueWarning(toString(StackSizeRelocMapOrErr.takeError()),
+                        "unable to get stack size map section(s)");
     return;
   }
 
@@ -7441,15 +7455,16 @@ getMipsAbiFlagsSection(const ELFDumper<ELFT> &Dumper) {
   if (Sec == nullptr)
     return nullptr;
 
-  constexpr StringRef ErrPrefix = "unable to read the .MIPS.abiflags section: ";
+  constexpr StringRef ErrPrefix = "unable to read the .MIPS.abiflags section";
   Expected<ArrayRef<uint8_t>> DataOrErr =
       Dumper.getElfObject().getELFFile().getSectionContents(*Sec);
   if (!DataOrErr)
-    return createError(ErrPrefix + toString(DataOrErr.takeError()));
+    return createError(DataOrErr.takeError(), ErrPrefix);
 
   if (DataOrErr->size() != sizeof(Elf_Mips_ABIFlags<ELFT>))
-    return createError(ErrPrefix + "it has a wrong size (" +
-        Twine(DataOrErr->size()) + ")");
+    return createError(std::move(createError("it has a wrong size (" +
+                                             Twine(DataOrErr->size()) + ")")),
+                       ErrPrefix);
   return reinterpret_cast<const Elf_Mips_ABIFlags<ELFT> *>(DataOrErr->data());
 }
 
@@ -7998,8 +8013,8 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printProgramHeaders() {
 
   Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = this->Obj.program_headers();
   if (!PhdrsOrErr) {
-    this->reportUniqueWarning("unable to dump program headers: " +
-                              toString(PhdrsOrErr.takeError()));
+    this->reportUniqueWarning(toString(PhdrsOrErr.takeError()),
+                              "unable to dump program headers");
     return;
   }
 
@@ -8149,9 +8164,9 @@ static bool getSymbolIndices(const typename ELFT::Shdr *CGRelSection,
     Expected<typename ELFT::RelRange> CGProfileRelOrError =
         Obj.rels(*CGRelSection);
     if (!CGProfileRelOrError) {
-      Dumper->reportUniqueWarning("unable to load relocations for "
-                                  "SHT_LLVM_CALL_GRAPH_PROFILE section: " +
-                                  toString(CGProfileRelOrError.takeError()));
+      Dumper->reportUniqueWarning(toString(CGProfileRelOrError.takeError()),
+                                  "unable to load relocations for "
+                                  "SHT_LLVM_CALL_GRAPH_PROFILE section");
       return false;
     }
 
@@ -8166,9 +8181,9 @@ static bool getSymbolIndices(const typename ELFT::Shdr *CGRelSection,
     Expected<typename ELFT::RelaRange> CGProfileRelaOrError =
         Obj.relas(*CGRelSection);
     if (!CGProfileRelaOrError) {
-      Dumper->reportUniqueWarning("unable to load relocations for "
-                                  "SHT_LLVM_CALL_GRAPH_PROFILE section: " +
-                                  toString(CGProfileRelaOrError.takeError()));
+      Dumper->reportUniqueWarning(toString(CGProfileRelaOrError.takeError()),
+                                  "unable to load relocations for "
+                                  "SHT_LLVM_CALL_GRAPH_PROFILE section");
       return false;
     }
 
@@ -8188,8 +8203,8 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printCGProfile() {
   Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> SecToRelocMapOrErr =
       this->Obj.getSectionAndRelocations(IsMatch);
   if (!SecToRelocMapOrErr) {
-    this->reportUniqueWarning("unable to get CG Profile section(s): " +
-                              toString(SecToRelocMapOrErr.takeError()));
+    this->reportUniqueWarning(toString(SecToRelocMapOrErr.takeError()),
+                              "unable to get CG Profile section(s)");
     return;
   }
 
@@ -8201,8 +8216,8 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printCGProfile() {
         this->Obj.template getSectionContentsAsArray<Elf_CGProfile>(*CGSection);
     if (!CGProfileOrErr) {
       this->reportUniqueWarning(
-          "unable to load the SHT_LLVM_CALL_GRAPH_PROFILE section: " +
-          toString(CGProfileOrErr.takeError()));
+          toString(CGProfileOrErr.takeError()),
+          "unable to load the SHT_LLVM_CALL_GRAPH_PROFILE section");
       return;
     }
 
@@ -8239,14 +8254,14 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printCallGraphInfo() {
         return Sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH;
       });
   if (!MapOrErr) {
-    reportWarning(createError("unable to read SHT_LLVM_CALL_GRAPH section: " +
-                              toString(MapOrErr.takeError())),
+    reportWarning(createError(MapOrErr.takeError(),
+                              "unable to read SHT_LLVM_CALL_GRAPH section"),
                   this->FileName);
     return;
   }
   if (MapOrErr->empty()) {
-    reportWarning(createError("no SHT_LLVM_CALL_GRAPH section found" +
-                              toString(MapOrErr.takeError())),
+    reportWarning(createError(MapOrErr.takeError(),
+                              "no SHT_LLVM_CALL_GRAPH section found"),
                   this->FileName);
     return;
   }
@@ -8264,9 +8279,9 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printCallGraphInfo() {
       Expected<const typename ELFT::Shdr *> SymtabOrErr =
           this->Obj.getSection(CGRelSection->sh_link);
       if (!SymtabOrErr) {
-        reportWarning(createError("invalid section linked to " +
-                                  this->describe(*CGRelSection) + ": " +
-                                  toString(SymtabOrErr.takeError())),
+        reportWarning(createError(SymtabOrErr.takeError(),
+                                  "invalid section linked to " +
+                                      this->describe(*CGRelSection)),
                       this->FileName);
         return;
       }
@@ -8359,9 +8374,8 @@ void LLVMELFDumper<ELFT>::printBBAddrMaps(bool PrettyPGOAnalysis) {
   Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> SecRelocMapOrErr =
       this->Obj.getSectionAndRelocations(IsMatch);
   if (!SecRelocMapOrErr) {
-    this->reportUniqueWarning(
-        "failed to get SHT_LLVM_BB_ADDR_MAP section(s): " +
-        toString(SecRelocMapOrErr.takeError()));
+    this->reportUniqueWarning(toString(SecRelocMapOrErr.takeError()),
+                              "failed to get SHT_LLVM_BB_ADDR_MAP section(s)");
     return;
   }
   for (auto const &[Sec, RelocSec] : *SecRelocMapOrErr) {
@@ -8379,8 +8393,8 @@ void LLVMELFDumper<ELFT>::printBBAddrMaps(bool PrettyPGOAnalysis) {
     Expected<std::vector<BBAddrMap>> BBAddrMapOrErr =
         this->Obj.decodeBBAddrMap(*Sec, RelocSec, &PGOAnalyses);
     if (!BBAddrMapOrErr) {
-      this->reportUniqueWarning("unable to dump " + this->describe(*Sec) +
-                                ": " + toString(BBAddrMapOrErr.takeError()));
+      this->reportUniqueWarning(toString(BBAddrMapOrErr.takeError()),
+                                "unable to dump " + this->describe(*Sec));
       continue;
     }
     for (const auto &[AM, PAM] : zip_equal(*BBAddrMapOrErr, PGOAnalyses)) {
@@ -8696,19 +8710,18 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printELFLinkerOptions() {
     Expected<ArrayRef<uint8_t>> ContentsOrErr =
         this->Obj.getSectionContents(Shdr);
     if (!ContentsOrErr) {
-      this->reportUniqueWarning("unable to read the content of the "
-                                "SHT_LLVM_LINKER_OPTIONS section: " +
-                                toString(ContentsOrErr.takeError()));
+      this->reportUniqueWarning(toString(ContentsOrErr.takeError()),
+                                "unable to read the content of the "
+                                "SHT_LLVM_LINKER_OPTIONS section");
       continue;
     }
     if (ContentsOrErr->empty())
       continue;
 
     if (ContentsOrErr->back() != 0) {
-      this->reportUniqueWarning("SHT_LLVM_LINKER_OPTIONS section at index " +
-                                Twine(I) +
-                                " is broken: the "
-                                "content is not null-terminated");
+      this->reportUniqueWarning("the content is not null-terminated",
+                                "SHT_LLVM_LINKER_OPTIONS section at index " +
+                                    Twine(I) + " is broken");
       continue;
     }
 
diff --git a/llvm/tools/llvm-readobj/ObjDumper.cpp b/llvm/tools/llvm-readobj/ObjDumper.cpp
index 4b178b47e25bb..9d26a81f4b690 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.cpp
+++ b/llvm/tools/llvm-readobj/ObjDumper.cpp
@@ -30,13 +30,12 @@ static inline Error createError(const Twine &Msg) {
   return createStringError(object::object_error::parse_failed, Msg);
 }
 
-ObjDumper::ObjDumper(ScopedPrinter &Writer, StringRef ObjName) : W(Writer) {
+ObjDumper::ObjDumper(ScopedPrinter &Writer, StringRef ObjName)
+    : W(Writer), ObjName(ObjName) {
   // Dumper reports all non-critical errors as warnings.
   // It does not print the same warning more than once.
   WarningHandler = [=](Error E) {
-    std::string Msg = toString(std::move(E));
-    if (Warnings.insert(Msg).second)
-      reportWarning(createError(Msg), ObjName);
+    reportUniqueWarning(std::move(E));
     return Error::success();
   };
 }
@@ -44,12 +43,25 @@ ObjDumper::ObjDumper(ScopedPrinter &Writer, StringRef ObjName) : W(Writer) {
 ObjDumper::~ObjDumper() = default;
 
 void ObjDumper::reportUniqueWarning(Error Err) const {
-  reportUniqueWarning(toString(std::move(Err)));
+  cantFail(llvm::handleErrors(
+      std::move(Err),
+      [this](const ContextualizedError &E) {
+        reportUniqueWarning(E.getMessageWithoutContext(), E.getContext());
+      },
+      [this](const llvm::ErrorInfoBase &E) {
+        reportUniqueWarning(E.message());
+      }));
 }
 
-void ObjDumper::reportUniqueWarning(const Twine &Msg) const {
-  cantFail(WarningHandler(createError(Msg)),
-           "WarningHandler should always return ErrorSuccess");
+void ObjDumper::reportUniqueWarning(const Twine &Msg,
+                                    const Twine &Prefix) const {
+  std::string MsgStr = Msg.str();
+  std::string PrefixStr = Prefix.str();
+  if (!const_cast<ObjDumper *>(this)->Warnings.insert(MsgStr).second)
+    return;
+  if (PrefixStr.size())
+    MsgStr = std::move(PrefixStr) + ": " + std::move(MsgStr);
+  reportWarning(createError(MsgStr), ObjName);
 }
 
 static void printAsPrintable(raw_ostream &W, const uint8_t *Start, size_t Len) {
diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
index a99e3c5bf307a..443e91920a21e 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -189,7 +189,7 @@ class ObjDumper {
 
   std::function<Error(Error)> WarningHandler;
   void reportUniqueWarning(Error Err) const;
-  void reportUniqueWarning(const Twine &Msg) const;
+  void reportUniqueWarning(const Twine &Msg, const Twine &Prefix = "") const;
   void printOffloading(const object::ObjectFile &Obj);
 
 protected:
@@ -208,6 +208,7 @@ class ObjDumper {
   virtual void printSectionMapping() {}
 
   std::unordered_set<std::string> Warnings;
+  StringRef ObjName;
 };
 
 std::unique_ptr<ObjDumper> createCOFFDumper(const object::COFFObjectFile &Obj,

>From 5d0fc8253599051f690222321a5a26787543ce65 Mon Sep 17 00:00:00 2001
From: ShengYi Hung <aokblast at FreeBSD.org>
Date: Thu, 16 Apr 2026 21:50:34 +0800
Subject: [PATCH 4/5] [llvm-readobj][ELF] Remove redundant error in
 reportWarning

If MapOrError contains no error, calling takeError() results in
undefined behavior and may crash the program.
---
 llvm/tools/llvm-readobj/ELFDumper.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 7a7e6f8dbb09c..f76211e564d1f 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -8260,8 +8260,7 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printCallGraphInfo() {
     return;
   }
   if (MapOrErr->empty()) {
-    reportWarning(createError(MapOrErr.takeError(),
-                              "no SHT_LLVM_CALL_GRAPH section found"),
+    reportWarning(createError("no SHT_LLVM_CALL_GRAPH section found"),
                   this->FileName);
     return;
   }

>From 81af175c5ff2b51c938db7792ffb7acfff43ead3 Mon Sep 17 00:00:00 2001
From: ShengYi Hung <aokblast at FreeBSD.org>
Date: Fri, 17 Apr 2026 14:26:34 +0800
Subject: [PATCH 5/5] fixup! [Object][ELF] Pass Error to WarningHandler

---
 llvm/tools/llvm-readobj/ELFDumper.cpp | 66 +++++++++++++--------------
 1 file changed, 32 insertions(+), 34 deletions(-)

diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index f76211e564d1f..9241af69b9326 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -984,9 +984,9 @@ static std::string maybeDemangle(StringRef Name) {
 template <typename ELFT>
 std::string ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {
   auto Warn = [&](Error E) -> std::string {
-    reportUniqueWarning(toString(std::move(E)),
-                        "unable to read the name of symbol with index " +
-                            Twine(Index));
+    reportUniqueWarning(createError(
+        std::move(E),
+        "unable to read the name of symbol with index " + Twine(Index)));
     return "<?>";
   };
 
@@ -2967,9 +2967,8 @@ void ELFDumper<ELFT>::printAttributes(
     W.printHex("FormatVersion", Contents[0]);
 
     if (Error E = AttrParser->parse(Contents, Endianness))
-      reportUniqueWarning(toString(std::move(E)),
-                          "unable to dump attributes from the " +
-                              describe(Sec));
+      reportUniqueWarning(createError(
+          std::move(E), "unable to dump attributes from the " + describe(Sec)));
   }
 }
 
@@ -3476,9 +3475,9 @@ template <class ELFT> void ELFDumper<ELFT>::printStackMap() const {
     return;
 
   auto Warn = [&](Error &&E) {
-    this->reportUniqueWarning(toString(std::move(E)),
-                              "unable to read the stack map from " +
-                                  describe(*StackMapSection));
+    this->reportUniqueWarning(
+        createError(std::move(E), "unable to read the stack map from " +
+                                      describe(*StackMapSection)));
   };
 
   Expected<ArrayRef<uint8_t>> ContentOrErr =
@@ -6375,16 +6374,15 @@ static void processNotesHelper(
       size_t I = 0;
       for (const typename ELFT::Note Note : Obj.notes(S, Err)) {
         if (Error E = ProcessNoteFn(Note, IsCoreFile))
-          Dumper.reportUniqueWarning(toString(std::move(E)),
-                                     "unable to read note with index " +
-                                         Twine(I) + " from the " +
-                                         describe(Obj, S));
+          Dumper.reportUniqueWarning(createError(
+              std::move(E), "unable to read note with index " + Twine(I) +
+                                " from the " + describe(Obj, S)));
         ++I;
       }
       if (Err)
-        Dumper.reportUniqueWarning(toString(std::move(Err)),
-                                   "unable to read notes from the " +
-                                       describe(Obj, S));
+        Dumper.reportUniqueWarning(
+            createError(std::move(Err),
+                        "unable to read notes from the " + describe(Obj, S)));
       FinishNotesFn();
     }
     return;
@@ -6407,17 +6405,17 @@ static void processNotesHelper(
     size_t Index = 0;
     for (const typename ELFT::Note Note : Obj.notes(P, Err)) {
       if (Error E = ProcessNoteFn(Note, IsCoreFile))
-        Dumper.reportUniqueWarning(
-            toString(std::move(E)),
-            "unable to read note with index " + Twine(Index) +
-                " from the PT_NOTE segment with index " + Twine(I));
+        Dumper.reportUniqueWarning(createError(
+            std::move(E), "unable to read note with index " + Twine(Index) +
+                              " from the PT_NOTE segment with index " +
+                              Twine(I)));
       ++Index;
     }
     if (Err)
-      Dumper.reportUniqueWarning(
-          toString(std::move(Err)),
+      Dumper.reportUniqueWarning(createError(
+          std::move(Err),
           "unable to read notes from the PT_NOTE segment with index " +
-              Twine(I));
+              Twine(I)));
     FinishNotesFn();
   }
 }
@@ -6536,9 +6534,9 @@ ELFDumper<ELFT>::getMemtagGlobalsSectionContents(uint64_t ExpectedAddr) {
     }
     Expected<ArrayRef<uint8_t>> Contents = Obj.getSectionContents(Sec);
     if (auto E = Contents.takeError()) {
-      reportUniqueWarning(
-          toString(std::move(E)),
-          "couldn't get SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC section contents");
+      reportUniqueWarning(createError(
+          std::move(E),
+          "couldn't get SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC section contents"));
       return ArrayRef<uint8_t>();
     }
     return Contents.get();
@@ -6898,8 +6896,8 @@ void ELFDumper<ELFT>::forEachRelocationDo(
         RelRelaFn) {
   auto Warn = [&](Error &&E,
                   const Twine &Prefix = "unable to read relocations from") {
-    this->reportUniqueWarning(toString(std::move(E)),
-                              Prefix + " " + describe(Sec));
+    this->reportUniqueWarning(
+        createError(std::move(E), Prefix + " " + describe(Sec)));
   };
 
   // SHT_RELR/SHT_ANDROID_RELR/SHT_AARCH64_AUTH_RELR sections do not have an
@@ -7106,9 +7104,9 @@ bool ELFDumper<ELFT>::printFunctionStackSize(
   Error Err = Error::success();
   uint64_t StackSize = Data.getULEB128(Offset, &Err);
   if (Err) {
-    reportUniqueWarning(toString(std::move(Err)),
-                        "could not extract a valid stack size from " +
-                            describe(StackSizeSec));
+    reportUniqueWarning(createError(
+        std::move(Err),
+        "could not extract a valid stack size from " + describe(StackSizeSec)));
     return false;
   }
 
@@ -7462,9 +7460,9 @@ getMipsAbiFlagsSection(const ELFDumper<ELFT> &Dumper) {
     return createError(DataOrErr.takeError(), ErrPrefix);
 
   if (DataOrErr->size() != sizeof(Elf_Mips_ABIFlags<ELFT>))
-    return createError(std::move(createError("it has a wrong size (" +
-                                             Twine(DataOrErr->size()) + ")")),
-                       ErrPrefix);
+    return createError(
+        createError("it has a wrong size (" + Twine(DataOrErr->size()) + ")"),
+        ErrPrefix);
   return reinterpret_cast<const Elf_Mips_ABIFlags<ELFT> *>(DataOrErr->data());
 }
 



More information about the llvm-branch-commits mailing list