[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
Sun Apr 12 06:06:08 PDT 2026


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

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.

>From 49e88acb7922b9d74949b440abe81c8b8ca689df 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] [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         | 400 +++++++++---------
 llvm/tools/llvm-readobj/ObjDumper.cpp         |  28 +-
 llvm/tools/llvm-readobj/ObjDumper.h           |   3 +-
 17 files changed, 251 insertions(+), 260 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 bcb580119fb85..540d24b34cdfe 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(toString(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(
+        toString(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(toString(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(toString(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(toString(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;
@@ -2028,14 +2032,14 @@ 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 Err) {
+      this->reportUniqueWarning(std::move(Err));
       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(toString(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(toString(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(toString(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(toString(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(toString(C.takeError()),
+                      "failed while reading call graph info function entry PC"),
           FileName);
       return false;
     }
@@ -5330,8 +5338,8 @@ 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())),
+      reportWarning(createError(toString(C.takeError()),
+                                "failed while reading function type ID"),
                     FileName);
       return false;
     }
@@ -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(toString(C.takeError()),
+                        "failed while reading number of direct callees"),
             FileName);
         return false;
       }
@@ -5355,8 +5363,8 @@ 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())),
+          reportWarning(createError(toString(C.takeError()),
+                                    "failed while reading direct callee"),
                         FileName);
           return false;
         }
@@ -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())),
+                toString(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(toString(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(toString(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;
   }
 
@@ -7998,8 +8012,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 +8163,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 +8180,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 +8202,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 +8215,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 +8253,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(toString(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(toString(MapOrErr.takeError()),
+                              "no SHT_LLVM_CALL_GRAPH section found"),
                   this->FileName);
     return;
   }
@@ -8264,9 +8278,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(toString(SymtabOrErr.takeError()),
+                                  "invalid section linked to " +
+                                      this->describe(*CGRelSection)),
                       this->FileName);
         return;
       }
@@ -8359,9 +8373,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 +8392,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 +8709,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 67630b4c41793..2a1829ced3648 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 WrappedError &E) {
+        reportUniqueWarning(E.getMessage(), E.getPrefix());
+      },
+      [this](const llvm::ErrorInfoBase &E) {
+        reportUniqueWarning(E.message());
+      }));
 }
 
-void ObjDumper::reportUniqueWarning(const Twine &Msg) const {
-  cantFail(WarningHandler(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,



More information about the llvm-branch-commits mailing list