diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
--- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
+++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
@@ -40,11 +40,14 @@
                  Obj.IsPE ? Obj.PeHeader.SectionAlignment : 1);
 }
 
-static std::vector<uint8_t> createGnuDebugLinkSectionContents(StringRef File) {
+static std::vector<uint8_t>
+createGnuDebugLinkSectionContents(StringRef File,
+                                  const ErrorReporter &Reporter) {
   ErrorOr<std::unique_ptr<MemoryBuffer>> LinkTargetOrErr =
       MemoryBuffer::getFile(File);
   if (!LinkTargetOrErr)
-    error("'" + File + "': " + LinkTargetOrErr.getError().message());
+    Reporter.fatalError(errc::invalid_argument,
+                        LinkTargetOrErr.getError().message(), File);
   auto LinkTarget = std::move(*LinkTargetOrErr);
   uint32_t CRC32 = llvm::crc32(arrayRefFromStringRef(LinkTarget->getBuffer()));
 
@@ -81,9 +84,10 @@
   Obj.addSections(Sec);
 }
 
-static void addGnuDebugLink(Object &Obj, StringRef DebugLinkFile) {
+static void addGnuDebugLink(Object &Obj, StringRef DebugLinkFile,
+                            const ErrorReporter &Reporter) {
   std::vector<uint8_t> Contents =
-      createGnuDebugLinkSectionContents(DebugLinkFile);
+      createGnuDebugLinkSectionContents(DebugLinkFile, Reporter);
   addSection(Obj, ".gnu_debuglink", Contents,
              IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
                  IMAGE_SCN_MEM_DISCARDABLE);
@@ -184,11 +188,12 @@
     if (Config.SymbolsToRemove.matches(Sym.Name)) {
       // Explicitly removing a referenced symbol is an error.
       if (Sym.Referenced)
-        reportError(Config.OutputFilename,
-                    createStringError(llvm::errc::invalid_argument,
-                                      "not stripping symbol '%s' because it is "
-                                      "named in a relocation",
-                                      Sym.Name.str().c_str()));
+        Config.Reporter.get().fatalError(
+            createStringError(llvm::errc::invalid_argument,
+                              "not stripping symbol '%s' because it is "
+                              "named in a relocation",
+                              Sym.Name.str().c_str()),
+            Config.OutputFilename);
       return true;
     }
 
@@ -239,7 +244,7 @@
   }
 
   if (!Config.AddGnuDebugLink.empty())
-    addGnuDebugLink(Obj, Config.AddGnuDebugLink);
+    addGnuDebugLink(Obj, Config.AddGnuDebugLink, Config.Reporter);
 
   if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() ||
       Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
diff --git a/llvm/tools/llvm-objcopy/CopyConfig.h b/llvm/tools/llvm-objcopy/CopyConfig.h
--- a/llvm/tools/llvm-objcopy/CopyConfig.h
+++ b/llvm/tools/llvm-objcopy/CopyConfig.h
@@ -10,6 +10,7 @@
 #define LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H
 
 #include "ELF/ELFConfig.h"
+#include "Error.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/BitmaskEnum.h"
 #include "llvm/ADT/DenseSet.h"
@@ -147,6 +148,8 @@
 
 // Configuration for copying/stripping a single file.
 struct CopyConfig {
+  CopyConfig(const ErrorReporter &Reporter) : Reporter(Reporter) {}
+
   // Format-specific options to be initialized lazily when needed.
   Optional<elf::ELFCopyConfig> ELF;
 
@@ -232,6 +235,8 @@
   bool DecompressDebugSections = false;
   DebugCompressionType CompressionType = DebugCompressionType::None;
 
+  std::reference_wrapper<const ErrorReporter> Reporter;
+
   // parseELFConfig performs ELF-specific command-line parsing. Fills `ELF` on
   // success or returns an Error otherwise.
   Error parseELFConfig() {
@@ -255,30 +260,28 @@
 
 // ParseObjcopyOptions returns the config and sets the input arguments. If a
 // help flag is set then ParseObjcopyOptions will print the help messege and
-// exit. ErrorCallback is used to handle recoverable errors. An Error returned
-// by the callback aborts the parsing and is then returned by this function.
-Expected<DriverConfig>
-parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
-                    llvm::function_ref<Error(Error)> ErrorCallback);
+// exit. ErrorReporter is used to report errors.
+Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
+                                           const ErrorReporter &Reporter);
 
 // ParseInstallNameToolOptions returns the config and sets the input arguments.
 // If a help flag is set then ParseInstallNameToolOptions will print the help
-// messege and exit.
+// messege and exit. ErrorReporter is used to report errors.
 Expected<DriverConfig>
-parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr);
+parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr,
+                            const ErrorReporter &Reporter);
 
 // ParseBitcodeStripOptions returns the config and sets the input arguments.
 // If a help flag is set then ParseBitcodeStripOptions will print the help
-// messege and exit.
-Expected<DriverConfig> parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr);
+// messege and exit. ErrorReporter is used to report errors.
+Expected<DriverConfig> parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr,
+                                                const ErrorReporter &Reporter);
 
 // ParseStripOptions returns the config and sets the input arguments. If a
 // help flag is set then ParseStripOptions will print the help messege and
-// exit. ErrorCallback is used to handle recoverable errors. An Error returned
-// by the callback aborts the parsing and is then returned by this function.
-Expected<DriverConfig>
-parseStripOptions(ArrayRef<const char *> ArgsArr,
-                  llvm::function_ref<Error(Error)> ErrorCallback);
+// exit. ErrorReporter is used to handle errors.
+Expected<DriverConfig> parseStripOptions(ArrayRef<const char *> ArgsArr,
+                                         const ErrorReporter &Reporter);
 } // namespace objcopy
 } // namespace llvm
 
diff --git a/llvm/tools/llvm-objcopy/CopyConfig.cpp b/llvm/tools/llvm-objcopy/CopyConfig.cpp
--- a/llvm/tools/llvm-objcopy/CopyConfig.cpp
+++ b/llvm/tools/llvm-objcopy/CopyConfig.cpp
@@ -468,9 +468,8 @@
 // ParseObjcopyOptions returns the config and sets the input arguments. If a
 // help flag is set then ParseObjcopyOptions will print the help messege and
 // exit.
-Expected<DriverConfig>
-parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
-                    llvm::function_ref<Error(Error)> ErrorCallback) {
+Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
+                                           const ErrorReporter &Reporter) {
   DriverConfig DC;
   ObjcopyOptTable T;
   unsigned MissingArgumentIndex, MissingArgumentCount;
@@ -509,7 +508,7 @@
     return createStringError(errc::invalid_argument,
                              "too many positional arguments");
 
-  CopyConfig Config;
+  CopyConfig Config(Reporter);
   Config.InputFilename = Positional[0];
   Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
   if (InputArgs.hasArg(OBJCOPY_target) &&
@@ -683,6 +682,10 @@
           SR.NewName.str().c_str());
   }
 
+  std::function<Error(Error)> ErrorCallback = [&Reporter](Error Err) {
+    Reporter.warning(std::move(Err));
+    return Error::success();
+  };
   for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
     if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(
             Arg->getValue(), SectionMatchStyle, ErrorCallback)))
@@ -860,9 +863,10 @@
 // If a help flag is set then ParseInstallNameToolOptions will print the help
 // messege and exit.
 Expected<DriverConfig>
-parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {
+parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr,
+                            const ErrorReporter &Reporter) {
   DriverConfig DC;
-  CopyConfig Config;
+  CopyConfig Config(Reporter);
   InstallNameToolOptTable T;
   unsigned MissingArgumentIndex, MissingArgumentCount;
   llvm::opt::InputArgList InputArgs =
@@ -972,10 +976,10 @@
   return std::move(DC);
 }
 
-Expected<DriverConfig>
-parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr) {
+Expected<DriverConfig> parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr,
+                                                const ErrorReporter &Reporter) {
   DriverConfig DC;
-  CopyConfig Config;
+  CopyConfig Config(Reporter);
   BitcodeStripOptTable T;
   unsigned MissingArgumentIndex, MissingArgumentCount;
   opt::InputArgList InputArgs =
@@ -1019,9 +1023,8 @@
 // ParseStripOptions returns the config and sets the input arguments. If a
 // help flag is set then ParseStripOptions will print the help messege and
 // exit.
-Expected<DriverConfig>
-parseStripOptions(ArrayRef<const char *> ArgsArr,
-                  llvm::function_ref<Error(Error)> ErrorCallback) {
+Expected<DriverConfig> parseStripOptions(ArrayRef<const char *> ArgsArr,
+                                         const ErrorReporter &Reporter) {
   StripOptTable T;
   unsigned MissingArgumentIndex, MissingArgumentCount;
   llvm::opt::InputArgList InputArgs =
@@ -1058,7 +1061,7 @@
         errc::invalid_argument,
         "multiple input files cannot be used in combination with -o");
 
-  CopyConfig Config;
+  CopyConfig Config(Reporter);
 
   if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard))
     return createStringError(errc::invalid_argument,
@@ -1087,6 +1090,10 @@
   Config.OnlyKeepDebug = InputArgs.hasArg(STRIP_only_keep_debug);
   Config.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);
 
+  std::function<Error(Error)> ErrorCallback = [&Reporter](Error Err) {
+    Reporter.warning(std::move(Err));
+    return Error::success();
+  };
   for (auto Arg : InputArgs.filtered(STRIP_keep_section))
     if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(
             Arg->getValue(), SectionMatchStyle, ErrorCallback)))
diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
--- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
+++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
@@ -139,17 +139,17 @@
   // Depending on the initial ELFT and OutputFormat we need a different Writer.
   switch (OutputElfType) {
   case ELFT_ELF32LE:
-    return std::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, !Config.StripSections,
-                                                Config.OnlyKeepDebug);
+    return std::make_unique<ELFWriter<ELF32LE>>(
+        Obj, Buf, !Config.StripSections, Config.OnlyKeepDebug, Config.Reporter);
   case ELFT_ELF64LE:
-    return std::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, !Config.StripSections,
-                                                Config.OnlyKeepDebug);
+    return std::make_unique<ELFWriter<ELF64LE>>(
+        Obj, Buf, !Config.StripSections, Config.OnlyKeepDebug, Config.Reporter);
   case ELFT_ELF32BE:
-    return std::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, !Config.StripSections,
-                                                Config.OnlyKeepDebug);
+    return std::make_unique<ELFWriter<ELF32BE>>(
+        Obj, Buf, !Config.StripSections, Config.OnlyKeepDebug, Config.Reporter);
   case ELFT_ELF64BE:
-    return std::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, !Config.StripSections,
-                                                Config.OnlyKeepDebug);
+    return std::make_unique<ELFWriter<ELF64BE>>(
+        Obj, Buf, !Config.StripSections, Config.OnlyKeepDebug, Config.Reporter);
   }
   llvm_unreachable("Invalid output format");
 }
@@ -159,9 +159,9 @@
                                             ElfType OutputElfType) {
   switch (Config.OutputFormat) {
   case FileFormat::Binary:
-    return std::make_unique<BinaryWriter>(Obj, Buf);
+    return std::make_unique<BinaryWriter>(Obj, Buf, Config.Reporter);
   case FileFormat::IHex:
-    return std::make_unique<IHexWriter>(Obj, Buf);
+    return std::make_unique<IHexWriter>(Obj, Buf, Config.Reporter);
   default:
     return createELFWriter(Config, Obj, Buf, OutputElfType);
   }
@@ -581,7 +581,7 @@
     replaceDebugSections(Obj, RemovePred, isCompressable,
                          [&Config, &Obj](const SectionBase *S) {
                            return &Obj.addSection<CompressedSection>(
-                                *S, Config.CompressionType);
+                               *S, Config.CompressionType, Config.Reporter);
                          });
   else if (Config.DecompressDebugSections)
     replaceDebugSections(
@@ -768,7 +768,7 @@
 
 Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
                            Buffer &Out) {
-  IHexReader Reader(&In);
+  IHexReader Reader(&In, Config.Reporter);
   std::unique_ptr<Object> Obj = Reader.create(true);
   const ElfType OutputElfType =
     getOutputElfType(Config.OutputArch.getValueOr(MachineInfo()));
@@ -781,7 +781,7 @@
                                 Buffer &Out) {
   uint8_t NewSymbolVisibility =
       Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT);
-  BinaryReader Reader(&In, NewSymbolVisibility);
+  BinaryReader Reader(&In, NewSymbolVisibility, Config.Reporter);
   std::unique_ptr<Object> Obj = Reader.create(true);
 
   // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch
@@ -795,7 +795,7 @@
 
 Error executeObjcopyOnBinary(const CopyConfig &Config,
                              object::ELFObjectFileBase &In, Buffer &Out) {
-  ELFReader Reader(&In, Config.ExtractPartition);
+  ELFReader Reader(&In, Config.ExtractPartition, Config.Reporter);
   std::unique_ptr<Object> Obj = Reader.create(!Config.SymbolsToAdd.empty());
   // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input.
   const ElfType OutputElfType =
diff --git a/llvm/tools/llvm-objcopy/ELF/Object.h b/llvm/tools/llvm-objcopy/ELF/Object.h
--- a/llvm/tools/llvm-objcopy/ELF/Object.h
+++ b/llvm/tools/llvm-objcopy/ELF/Object.h
@@ -61,16 +61,19 @@
   iterator end() const { return iterator(Sections.data() + Sections.size()); }
   size_t size() const { return Sections.size(); }
 
-  SectionBase *getSection(uint32_t Index, Twine ErrMsg);
+  SectionBase *getSection(uint32_t Index, Twine ErrMsg,
+                          const ErrorReporter &Reporter);
 
   template <class T>
-  T *getSectionOfType(uint32_t Index, Twine IndexErrMsg, Twine TypeErrMsg);
+  T *getSectionOfType(uint32_t Index, Twine IndexErrMsg, Twine TypeErrMsg,
+                      const ErrorReporter &Reporter);
 };
 
 enum ElfType { ELFT_ELF32LE, ELFT_ELF64LE, ELFT_ELF32BE, ELFT_ELF64BE };
 
 class SectionVisitor {
 public:
+  SectionVisitor(const ErrorReporter &Reporter) : Reporter(Reporter) {}
   virtual ~SectionVisitor() = default;
 
   virtual void visit(const Section &Sec) = 0;
@@ -84,6 +87,9 @@
   virtual void visit(const SectionIndexSection &Sec) = 0;
   virtual void visit(const CompressedSection &Sec) = 0;
   virtual void visit(const DecompressedSection &Sec) = 0;
+
+protected:
+  const ErrorReporter &Reporter;
 };
 
 class MutableSectionVisitor {
@@ -122,7 +128,8 @@
   virtual void visit(const CompressedSection &Sec) override = 0;
   virtual void visit(const DecompressedSection &Sec) override = 0;
 
-  explicit SectionWriter(Buffer &Buf) : Out(Buf) {}
+  explicit SectionWriter(Buffer &Buf, const ErrorReporter &Reporter)
+      : SectionVisitor(Reporter), Out(Buf) {}
 };
 
 template <class ELFT> class ELFSectionWriter : public SectionWriter {
@@ -142,7 +149,8 @@
   void visit(const CompressedSection &Sec) override;
   void visit(const DecompressedSection &Sec) override;
 
-  explicit ELFSectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
+  explicit ELFSectionWriter(Buffer &Buf, const ErrorReporter &Reporter)
+      : SectionWriter(Buf, Reporter) {}
 };
 
 template <class ELFT> class ELFSectionSizer : public MutableSectionVisitor {
@@ -186,7 +194,8 @@
   void visit(const CompressedSection &Sec) override;
   void visit(const DecompressedSection &Sec) override;
 
-  explicit BinarySectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
+  explicit BinarySectionWriter(Buffer &Buf, const ErrorReporter &Reporter)
+      : SectionWriter(Buf, Reporter) {}
 };
 
 using IHexLineData = SmallVector<char, 64>;
@@ -282,7 +291,8 @@
   virtual void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data);
 
 public:
-  explicit IHexSectionWriterBase(Buffer &Buf) : BinarySectionWriter(Buf) {}
+  explicit IHexSectionWriterBase(Buffer &Buf, const ErrorReporter &Reporter)
+      : BinarySectionWriter(Buf, Reporter) {}
 
   uint64_t getBufferOffset() const { return Offset; }
   void visit(const Section &Sec) final;
@@ -295,7 +305,8 @@
 // Real IHEX section writer
 class IHexSectionWriter : public IHexSectionWriterBase {
 public:
-  IHexSectionWriter(Buffer &Buf) : IHexSectionWriterBase(Buf) {}
+  IHexSectionWriter(Buffer &Buf, const ErrorReporter &Reporter)
+      : IHexSectionWriterBase(Buf, Reporter) {}
 
   void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data) override;
   void visit(const StringTableSection &Sec) override;
@@ -305,13 +316,15 @@
 protected:
   Object &Obj;
   Buffer &Buf;
+  const ErrorReporter &Reporter;
 
 public:
   virtual ~Writer();
   virtual Error finalize() = 0;
   virtual Error write() = 0;
 
-  Writer(Object &O, Buffer &B) : Obj(O), Buf(B) {}
+  Writer(Object &O, Buffer &B, const ErrorReporter &Reporter)
+      : Obj(O), Buf(B), Reporter(Reporter) {}
 };
 
 template <class ELFT> class ELFWriter : public Writer {
@@ -348,7 +361,8 @@
 
   Error finalize() override;
   Error write() override;
-  ELFWriter(Object &Obj, Buffer &Buf, bool WSH, bool OnlyKeepDebug);
+  ELFWriter(Object &Obj, Buffer &Buf, bool WSH, bool OnlyKeepDebug,
+            const ErrorReporter &Reporter);
 };
 
 class BinaryWriter : public Writer {
@@ -361,7 +375,8 @@
   ~BinaryWriter() {}
   Error finalize() override;
   Error write() override;
-  BinaryWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {}
+  BinaryWriter(Object &Obj, Buffer &Buf, const ErrorReporter &Reporter)
+      : Writer(Obj, Buf, Reporter) {}
 };
 
 class IHexWriter : public Writer {
@@ -380,7 +395,8 @@
   ~IHexWriter() {}
   Error finalize() override;
   Error write() override;
-  IHexWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {}
+  IHexWriter(Object &Obj, Buffer &Buf, const ErrorReporter &Reporter)
+      : Writer(Obj, Buf, Reporter) {}
 };
 
 class SectionBase {
@@ -412,7 +428,8 @@
 
   virtual ~SectionBase() = default;
 
-  virtual void initialize(SectionTableRef SecTable);
+  virtual void initialize(SectionTableRef SecTable,
+                          const ErrorReporter &Reporter);
   virtual void finalize();
   // Remove references to these sections. The list of sections must be sorted.
   virtual Error
@@ -485,7 +502,8 @@
   void accept(MutableSectionVisitor &Visitor) override;
   Error removeSectionReferences(bool AllowBrokenLinks,
       function_ref<bool(const SectionBase *)> ToRemove) override;
-  void initialize(SectionTableRef SecTable) override;
+  void initialize(SectionTableRef SecTable,
+                  const ErrorReporter &Reporter) override;
   void finalize() override;
 };
 
@@ -527,7 +545,8 @@
 
 public:
   CompressedSection(const SectionBase &Sec,
-                    DebugCompressionType CompressionType);
+                    DebugCompressionType CompressionType,
+                    const ErrorReporter &Reporter);
   CompressedSection(ArrayRef<uint8_t> CompressedData, uint64_t DecompressedSize,
                     uint64_t DecompressedAlign);
 
@@ -647,7 +666,8 @@
     Size = NumSymbols * 4;
   }  
   void setSymTab(SymbolTableSection *SymTab) { Symbols = SymTab; }
-  void initialize(SectionTableRef SecTable) override;
+  void initialize(SectionTableRef SecTable,
+                  const ErrorReporter &Reporter) override;
   void finalize() override;
   void accept(SectionVisitor &Visitor) const override;
   void accept(MutableSectionVisitor &Visitor) override;
@@ -688,13 +708,14 @@
   const SectionIndexSection *getShndxTable() const { return SectionIndexTable; }
   void fillShndxTable();
   const SectionBase *getStrTab() const { return SymbolNames; }
-  const Symbol *getSymbolByIndex(uint32_t Index) const;
-  Symbol *getSymbolByIndex(uint32_t Index);
+  const Symbol *getSymbolByIndex(uint32_t Index,
+                                 const ErrorReporter &Reporter) const;
+  Symbol *getSymbolByIndex(uint32_t Index, const ErrorReporter &Reporter);
   void updateSymbols(function_ref<void(Symbol &)> Callable);
 
   Error removeSectionReferences(bool AllowBrokenLinks,
       function_ref<bool(const SectionBase *)> ToRemove) override;
-  void initialize(SectionTableRef SecTable) override;
+  void initialize(SectionTableRef SecTable, const ErrorReporter &) override;
   void finalize() override;
   void accept(SectionVisitor &Visitor) const override;
   void accept(MutableSectionVisitor &Visitor) override;
@@ -748,7 +769,8 @@
   SymTabType *Symbols = nullptr;
 
 public:
-  void initialize(SectionTableRef SecTable) override;
+  void initialize(SectionTableRef SecTable,
+                  const ErrorReporter &Reporter) override;
   void finalize() override;
 };
 
@@ -874,8 +896,12 @@
 
 class Reader {
 public:
+  Reader(const ErrorReporter &Reporter) : Reporter(Reporter) {}
   virtual ~Reader();
   virtual std::unique_ptr<Object> create(bool EnsureSymtab) const = 0;
+
+protected:
+  const ErrorReporter &Reporter;
 };
 
 using object::Binary;
@@ -886,6 +912,7 @@
 class BasicELFBuilder {
 protected:
   std::unique_ptr<Object> Obj;
+  const ErrorReporter &Reporter;
 
   void initFileHeader();
   void initHeaderSegment();
@@ -894,7 +921,8 @@
   void initSections();
 
 public:
-  BasicELFBuilder() : Obj(std::make_unique<Object>()) {}
+  BasicELFBuilder(const ErrorReporter &Reporter)
+      : Obj(std::make_unique<Object>(Reporter)), Reporter(Reporter) {}
 };
 
 class BinaryELFBuilder : public BasicELFBuilder {
@@ -903,8 +931,9 @@
   void addData(SymbolTableSection *SymTab);
 
 public:
-  BinaryELFBuilder(MemoryBuffer *MB, uint8_t NewSymbolVisibility)
-      : BasicELFBuilder(), MemBuf(MB),
+  BinaryELFBuilder(MemoryBuffer *MB, uint8_t NewSymbolVisibility,
+                   const ErrorReporter &Reporter)
+      : BasicELFBuilder(Reporter), MemBuf(MB),
         NewSymbolVisibility(NewSymbolVisibility) {}
 
   std::unique_ptr<Object> build();
@@ -916,8 +945,9 @@
   void addDataSections();
 
 public:
-  IHexELFBuilder(const std::vector<IHexRecord> &Records)
-      : BasicELFBuilder(), Records(Records) {}
+  IHexELFBuilder(const std::vector<IHexRecord> &Records,
+                 const ErrorReporter &Reporter)
+      : BasicELFBuilder(Reporter), Records(Records) {}
 
   std::unique_ptr<Object> build();
 };
@@ -932,6 +962,7 @@
   Object &Obj;
   size_t EhdrOffset = 0;
   Optional<StringRef> ExtractPartition;
+  const ErrorReporter &Reporter;
 
   void setParentSegment(Segment &Child);
   void readProgramHeaders(const ELFFile<ELFT> &HeadersFile);
@@ -944,9 +975,10 @@
 
 public:
   ELFBuilder(const ELFObjectFile<ELFT> &ElfObj, Object &Obj,
-             Optional<StringRef> ExtractPartition)
+             Optional<StringRef> ExtractPartition,
+             const ErrorReporter &Reporter)
       : ElfFile(*ElfObj.getELFFile()), Obj(Obj),
-        ExtractPartition(ExtractPartition) {}
+        ExtractPartition(ExtractPartition), Reporter(Reporter) {}
 
   void build(bool EnsureSymtab);
 };
@@ -956,8 +988,10 @@
   uint8_t NewSymbolVisibility;
 
 public:
-  BinaryReader(MemoryBuffer *MB, const uint8_t NewSymbolVisibility)
-      : MemBuf(MB), NewSymbolVisibility(NewSymbolVisibility) {}
+  BinaryReader(MemoryBuffer *MB, const uint8_t NewSymbolVisibility,
+               const ErrorReporter &Reporter)
+      : Reader(Reporter), MemBuf(MB), NewSymbolVisibility(NewSymbolVisibility) {
+  }
   std::unique_ptr<Object> create(bool EnsureSymtab) const override;
 };
 
@@ -978,7 +1012,8 @@
   }
 
 public:
-  IHexReader(MemoryBuffer *MB) : MemBuf(MB) {}
+  IHexReader(MemoryBuffer *MB, const ErrorReporter &Reporter)
+      : Reader(Reporter), MemBuf(MB) {}
 
   std::unique_ptr<Object> create(bool EnsureSymtab) const override;
 };
@@ -989,8 +1024,9 @@
 
 public:
   std::unique_ptr<Object> create(bool EnsureSymtab) const override;
-  explicit ELFReader(Binary *B, Optional<StringRef> ExtractPartition)
-      : Bin(B), ExtractPartition(ExtractPartition) {}
+  explicit ELFReader(Binary *B, Optional<StringRef> ExtractPartition,
+                     const ErrorReporter &Reporter)
+      : Reader(Reporter), Bin(B), ExtractPartition(ExtractPartition) {}
 };
 
 class Object {
@@ -1002,11 +1038,15 @@
   std::vector<SegPtr> Segments;
   std::vector<SecPtr> RemovedSections;
 
+  const ErrorReporter &Reporter;
+
   static bool sectionIsAlloc(const SectionBase &Sec) {
     return Sec.Flags & ELF::SHF_ALLOC;
   };
 
 public:
+  Object(const ErrorReporter &Reporter) : Reporter(Reporter) {}
+
   template <class T>
   using Range = iterator_range<
       pointee_iterator<typename std::vector<std::unique_ptr<T>>::iterator>>;
diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp
--- a/llvm/tools/llvm-objcopy/ELF/Object.cpp
+++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp
@@ -60,7 +60,8 @@
   return Error::success();
 }
 
-void SectionBase::initialize(SectionTableRef SecTable) {}
+void SectionBase::initialize(SectionTableRef SecTable,
+                             const ErrorReporter &Reporter) {}
 void SectionBase::finalize() {}
 void SectionBase::markSymbols() {}
 void SectionBase::replaceSectionReferences(
@@ -126,23 +127,31 @@
 void ELFSectionSizer<ELFT>::visit(DecompressedSection &Sec) {}
 
 void BinarySectionWriter::visit(const SectionIndexSection &Sec) {
-  error("cannot write symbol section index table '" + Sec.Name + "' ");
+  Reporter.fatalError(errc::operation_not_permitted,
+                      "cannot write symbol section index table '" + Sec.Name +
+                          "' ");
 }
 
 void BinarySectionWriter::visit(const SymbolTableSection &Sec) {
-  error("cannot write symbol table '" + Sec.Name + "' out to binary");
+  Reporter.fatalError(errc::operation_not_permitted,
+                      "cannot write symbol table '" + Sec.Name +
+                          "' out to binary");
 }
 
 void BinarySectionWriter::visit(const RelocationSection &Sec) {
-  error("cannot write relocation section '" + Sec.Name + "' out to binary");
+  Reporter.fatalError(errc::operation_not_permitted,
+                      "cannot write relocation section '" + Sec.Name +
+                          "' out to binary");
 }
 
 void BinarySectionWriter::visit(const GnuDebugLinkSection &Sec) {
-  error("cannot write '" + Sec.Name + "' out to binary");
+  Reporter.fatalError(errc::operation_not_permitted,
+                      "cannot write '" + Sec.Name + "' out to binary");
 }
 
 void BinarySectionWriter::visit(const GroupSection &Sec) {
-  error("cannot write '" + Sec.Name + "' out to binary");
+  Reporter.fatalError(errc::operation_not_permitted,
+                      "cannot write '" + Sec.Name + "' out to binary");
 }
 
 void SectionWriter::visit(const Section &Sec) {
@@ -436,14 +445,15 @@
   SmallVector<char, 128> DecompressedContent;
   if (Error E = zlib::uncompress(CompressedContent, DecompressedContent,
                                  static_cast<size_t>(Sec.Size)))
-    reportError(Sec.Name, std::move(E));
+    Reporter.fatalError(std::move(E), Sec.Name);
 
   uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
   std::copy(DecompressedContent.begin(), DecompressedContent.end(), Buf);
 }
 
 void BinarySectionWriter::visit(const DecompressedSection &Sec) {
-  error("cannot write compressed section '" + Sec.Name + "' ");
+  Reporter.fatalError(errc::operation_not_permitted,
+                      "cannot write compressed section '" + Sec.Name + "' ");
 }
 
 void DecompressedSection::accept(SectionVisitor &Visitor) const {
@@ -472,7 +482,8 @@
 }
 
 void BinarySectionWriter::visit(const CompressedSection &Sec) {
-  error("cannot write compressed section '" + Sec.Name + "' ");
+  Reporter.fatalError(errc::operation_not_permitted,
+                      "cannot write compressed section '" + Sec.Name + "' ");
 }
 
 template <class ELFT>
@@ -504,14 +515,15 @@
 }
 
 CompressedSection::CompressedSection(const SectionBase &Sec,
-                                     DebugCompressionType CompressionType)
+                                     DebugCompressionType CompressionType,
+                                     const ErrorReporter &Reporter)
     : SectionBase(Sec), CompressionType(CompressionType),
       DecompressedSize(Sec.OriginalData.size()), DecompressedAlign(Sec.Align) {
   if (Error E = zlib::compress(
           StringRef(reinterpret_cast<const char *>(OriginalData.data()),
                     OriginalData.size()),
           CompressedData))
-    reportError(Name, std::move(E));
+    Reporter.fatalError(std::move(E), Name);
 
   size_t ChdrSize;
   if (CompressionType == DebugCompressionType::GNU) {
@@ -574,13 +586,15 @@
   llvm::copy(Sec.Indexes, reinterpret_cast<Elf_Word *>(Buf));
 }
 
-void SectionIndexSection::initialize(SectionTableRef SecTable) {
+void SectionIndexSection::initialize(SectionTableRef SecTable,
+                                     const ErrorReporter &Reporter) {
   Size = 0;
   setSymTab(SecTable.getSectionOfType<SymbolTableSection>(
       Link,
       "Link field value " + Twine(Link) + " in section " + Name + " is invalid",
       "Link field value " + Twine(Link) + " in section " + Name +
-          " is not a symbol table"));
+          " is not a symbol table",
+      Reporter));
   Symbols->setShndxTable(this);
 }
 
@@ -718,14 +732,16 @@
       Sym->DefinedIn = To;
 }
 
-void SymbolTableSection::initialize(SectionTableRef SecTable) {
+void SymbolTableSection::initialize(SectionTableRef SecTable,
+                                    const ErrorReporter &Reporter) {
   Size = 0;
   setStrTab(SecTable.getSectionOfType<StringTableSection>(
       Link,
       "Symbol table has link index of " + Twine(Link) +
           " which is not a valid index",
       "Symbol table has link index of " + Twine(Link) +
-          " which is not a string table"));
+          " which is not a string table",
+      Reporter));
 }
 
 void SymbolTableSection::finalize() {
@@ -770,15 +786,20 @@
   }
 }
 
-const Symbol *SymbolTableSection::getSymbolByIndex(uint32_t Index) const {
+const Symbol *
+SymbolTableSection::getSymbolByIndex(uint32_t Index,
+                                     const ErrorReporter &Reporter) const {
   if (Symbols.size() <= Index)
-    error("invalid symbol index: " + Twine(Index));
+    Reporter.fatalError(errc::invalid_argument,
+                        "invalid symbol index: " + Twine(Index));
   return Symbols[Index].get();
 }
 
-Symbol *SymbolTableSection::getSymbolByIndex(uint32_t Index) {
+Symbol *SymbolTableSection::getSymbolByIndex(uint32_t Index,
+                                             const ErrorReporter &Reporter) {
   return const_cast<Symbol *>(
-      static_cast<const SymbolTableSection *>(this)->getSymbolByIndex(Index));
+      static_cast<const SymbolTableSection *>(this)->getSymbolByIndex(
+          Index, Reporter));
 }
 
 template <class ELFT>
@@ -835,19 +856,21 @@
 
 template <class SymTabType>
 void RelocSectionWithSymtabBase<SymTabType>::initialize(
-    SectionTableRef SecTable) {
+    SectionTableRef SecTable, const ErrorReporter &Reporter) {
   if (Link != SHN_UNDEF)
     setSymTab(SecTable.getSectionOfType<SymTabType>(
         Link,
         "Link field value " + Twine(Link) + " in section " + Name +
             " is invalid",
         "Link field value " + Twine(Link) + " in section " + Name +
-            " is not a symbol table"));
+            " is not a symbol table",
+        Reporter));
 
   if (Info != SHN_UNDEF)
-    setSection(SecTable.getSection(Info, "Info field value " + Twine(Info) +
-                                             " in section " + Name +
-                                             " is invalid"));
+    setSection(SecTable.getSection(Info,
+                                   "Info field value " + Twine(Info) +
+                                       " in section " + Name + " is invalid",
+                                   Reporter));
   else
     setSection(nullptr);
 }
@@ -1015,12 +1038,14 @@
     Sec->Flags &= ~SHF_GROUP;
 }
 
-void Section::initialize(SectionTableRef SecTable) {
+void Section::initialize(SectionTableRef SecTable,
+                         const ErrorReporter &Reporter) {
   if (Link == ELF::SHN_UNDEF)
     return;
-  LinkSection =
-      SecTable.getSection(Link, "Link field value " + Twine(Link) +
-                                    " in section " + Name + " is invalid");
+  LinkSection = SecTable.getSection(Link,
+                                    "Link field value " + Twine(Link) +
+                                        " in section " + Name + " is invalid",
+                                    Reporter);
   if (LinkSection->Type == ELF::SHT_SYMTAB)
     LinkSection = nullptr;
 }
@@ -1163,7 +1188,7 @@
 
 void BasicELFBuilder::initSections() {
   for (SectionBase &Sec : Obj->sections())
-    Sec.initialize(Obj->sections());
+    Sec.initialize(Obj->sections(), Reporter);
 }
 
 void BinaryELFBuilder::addData(SymbolTableSection *SymTab) {
@@ -1283,17 +1308,22 @@
       return;
     }
   }
-  error("could not find partition named '" + *ExtractPartition + "'");
+  Reporter.fatalError(errc::invalid_argument,
+                      "could not find partition named '" + *ExtractPartition +
+                          "'");
 }
 
 template <class ELFT>
 void ELFBuilder<ELFT>::readProgramHeaders(const ELFFile<ELFT> &HeadersFile) {
   uint32_t Index = 0;
-  for (const auto &Phdr : unwrapOrError(HeadersFile.program_headers())) {
+  for (const auto &Phdr :
+       unwrapOrFatalError(HeadersFile.program_headers(), Reporter)) {
     if (Phdr.p_offset + Phdr.p_filesz > HeadersFile.getBufSize())
-      error("program header with offset 0x" + Twine::utohexstr(Phdr.p_offset) +
-            " and file size 0x" + Twine::utohexstr(Phdr.p_filesz) +
-            " goes past the end of the file");
+      Reporter.fatalError(
+          errc::invalid_argument,
+          "program header with offset 0x" + Twine::utohexstr(Phdr.p_offset) +
+              " and file size 0x" + Twine::utohexstr(Phdr.p_filesz) +
+              " goes past the end of the file");
 
     ArrayRef<uint8_t> Data{HeadersFile.base() + Phdr.p_offset,
                            (size_t)Phdr.p_filesz};
@@ -1346,8 +1376,9 @@
 template <class ELFT>
 void ELFBuilder<ELFT>::initGroupSection(GroupSection *GroupSec) {
   if (GroupSec->Align % sizeof(ELF::Elf32_Word) != 0)
-    error("invalid alignment " + Twine(GroupSec->Align) + " of group section '" +
-          GroupSec->Name + "'");
+    Reporter.fatalError(errc::invalid_argument,
+                        "invalid alignment " + Twine(GroupSec->Align) +
+                            " of group section '" + GroupSec->Name + "'");
   SectionTableRef SecTable = Obj.sections();
   if (GroupSec->Link != SHN_UNDEF) {
     auto SymTab = SecTable.template getSectionOfType<SymbolTableSection>(
@@ -1355,17 +1386,22 @@
         "link field value '" + Twine(GroupSec->Link) + "' in section '" +
             GroupSec->Name + "' is invalid",
         "link field value '" + Twine(GroupSec->Link) + "' in section '" +
-            GroupSec->Name + "' is not a symbol table");
-    Symbol *Sym = SymTab->getSymbolByIndex(GroupSec->Info);
+            GroupSec->Name + "' is not a symbol table",
+        Reporter);
+    Symbol *Sym = SymTab->getSymbolByIndex(GroupSec->Info, Reporter);
     if (!Sym)
-      error("info field value '" + Twine(GroupSec->Info) + "' in section '" +
-            GroupSec->Name + "' is not a valid symbol index");
+      Reporter.fatalError(errc::invalid_argument,
+                          "info field value '" + Twine(GroupSec->Info) +
+                              "' in section '" + GroupSec->Name +
+                              "' is not a valid symbol index");
     GroupSec->setSymTab(SymTab);
     GroupSec->setSymbol(Sym);
   }
   if (GroupSec->Contents.size() % sizeof(ELF::Elf32_Word) ||
       GroupSec->Contents.empty())
-    error("the content of the section " + GroupSec->Name + " is malformed");
+    Reporter.fatalError(errc::invalid_argument, "the content of the section " +
+                                                    GroupSec->Name +
+                                                    " is malformed");
   const ELF::Elf32_Word *Word =
       reinterpret_cast<const ELF::Elf32_Word *>(GroupSec->Contents.data());
   const ELF::Elf32_Word *End =
@@ -1373,52 +1409,64 @@
   GroupSec->setFlagWord(*Word++);
   for (; Word != End; ++Word) {
     uint32_t Index = support::endian::read32<ELFT::TargetEndianness>(Word);
-    GroupSec->addMember(SecTable.getSection(
-        Index, "group member index " + Twine(Index) + " in section '" +
-                   GroupSec->Name + "' is invalid"));
+    GroupSec->addMember(SecTable.getSection(Index,
+                                            "group member index " +
+                                                Twine(Index) + " in section '" +
+                                                GroupSec->Name + "' is invalid",
+                                            Reporter));
   }
 }
 
 template <class ELFT>
 void ELFBuilder<ELFT>::initSymbolTable(SymbolTableSection *SymTab) {
-  const Elf_Shdr &Shdr = *unwrapOrError(ElfFile.getSection(SymTab->Index));
-  StringRef StrTabData = unwrapOrError(ElfFile.getStringTableForSymtab(Shdr));
+  const Elf_Shdr &Shdr =
+      *unwrapOrFatalError(ElfFile.getSection(SymTab->Index), Reporter);
+  StringRef StrTabData =
+      unwrapOrFatalError(ElfFile.getStringTableForSymtab(Shdr), Reporter);
   ArrayRef<Elf_Word> ShndxData;
 
-  auto Symbols = unwrapOrError(ElfFile.symbols(&Shdr));
+  auto Symbols = unwrapOrFatalError(ElfFile.symbols(&Shdr), Reporter);
   for (const auto &Sym : Symbols) {
     SectionBase *DefSection = nullptr;
-    StringRef Name = unwrapOrError(Sym.getName(StrTabData));
+    StringRef Name = unwrapOrFatalError(Sym.getName(StrTabData), Reporter);
 
     if (Sym.st_shndx == SHN_XINDEX) {
       if (SymTab->getShndxTable() == nullptr)
-        error("symbol '" + Name +
-              "' has index SHN_XINDEX but no SHT_SYMTAB_SHNDX section exists");
+        Reporter.fatalError(errc::invalid_argument,
+                            "symbol '" + Name +
+                                "' has index SHN_XINDEX but no "
+                                "SHT_SYMTAB_SHNDX section exists");
       if (ShndxData.data() == nullptr) {
-        const Elf_Shdr &ShndxSec =
-            *unwrapOrError(ElfFile.getSection(SymTab->getShndxTable()->Index));
-        ShndxData = unwrapOrError(
-            ElfFile.template getSectionContentsAsArray<Elf_Word>(ShndxSec));
+        const Elf_Shdr &ShndxSec = *unwrapOrFatalError(
+            ElfFile.getSection(SymTab->getShndxTable()->Index), Reporter);
+        ShndxData = unwrapOrFatalError(
+            ElfFile.template getSectionContentsAsArray<Elf_Word>(ShndxSec),
+            Reporter);
         if (ShndxData.size() != Symbols.size())
-          error("symbol section index table does not have the same number of "
-                "entries as the symbol table");
+          Reporter.fatalError(
+              errc::invalid_argument,
+              "symbol section index table does not have the same number of "
+              "entries as the symbol table");
       }
       Elf_Word Index = ShndxData[&Sym - Symbols.begin()];
       DefSection = Obj.sections().getSection(
           Index,
-          "symbol '" + Name + "' has invalid section index " + Twine(Index));
+          "symbol '" + Name + "' has invalid section index " + Twine(Index),
+          Reporter);
     } else if (Sym.st_shndx >= SHN_LORESERVE) {
       if (!isValidReservedSectionIndex(Sym.st_shndx, Obj.Machine)) {
-        error(
-            "symbol '" + Name +
-            "' has unsupported value greater than or equal to SHN_LORESERVE: " +
-            Twine(Sym.st_shndx));
+        Reporter.fatalError(errc::invalid_argument,
+                            "symbol '" + Name +
+                                "' has unsupported value greater than or equal "
+                                "to SHN_LORESERVE: " +
+                                Twine(Sym.st_shndx));
       }
     } else if (Sym.st_shndx != SHN_UNDEF) {
       DefSection = Obj.sections().getSection(
-          Sym.st_shndx, "symbol '" + Name +
-                            "' is defined has invalid section index " +
-                            Twine(Sym.st_shndx));
+          Sym.st_shndx,
+          "symbol '" + Name + "' is defined has invalid section index " +
+              Twine(Sym.st_shndx),
+          Reporter);
     }
 
     SymTab->addSymbol(Name, Sym.getBinding(), Sym.getType(), DefSection,
@@ -1436,7 +1484,8 @@
 
 template <class T>
 static void initRelocations(RelocationSection *Relocs,
-                            SymbolTableSection *SymbolTable, T RelRange) {
+                            SymbolTableSection *SymbolTable, T RelRange,
+                            const ErrorReporter &Reporter) {
   for (const auto &Rel : RelRange) {
     Relocation ToAdd;
     ToAdd.Offset = Rel.r_offset;
@@ -1445,28 +1494,31 @@
 
     if (uint32_t Sym = Rel.getSymbol(false)) {
       if (!SymbolTable)
-        error("'" + Relocs->Name +
-              "': relocation references symbol with index " + Twine(Sym) +
-              ", but there is no symbol table");
-      ToAdd.RelocSymbol = SymbolTable->getSymbolByIndex(Sym);
+        Reporter.fatalError(errc::invalid_argument,
+                            "'" + Relocs->Name +
+                                "': relocation references symbol with index " +
+                                Twine(Sym) + ", but there is no symbol table");
+      ToAdd.RelocSymbol = SymbolTable->getSymbolByIndex(Sym, Reporter);
     }
 
     Relocs->addRelocation(ToAdd);
   }
 }
 
-SectionBase *SectionTableRef::getSection(uint32_t Index, Twine ErrMsg) {
+SectionBase *SectionTableRef::getSection(uint32_t Index, Twine ErrMsg,
+                                         const ErrorReporter &Reporter) {
   if (Index == SHN_UNDEF || Index > Sections.size())
-    error(ErrMsg);
+    Reporter.fatalError(errc::invalid_argument, ErrMsg);
   return Sections[Index - 1].get();
 }
 
 template <class T>
 T *SectionTableRef::getSectionOfType(uint32_t Index, Twine IndexErrMsg,
-                                     Twine TypeErrMsg) {
-  if (T *Sec = dyn_cast<T>(getSection(Index, IndexErrMsg)))
+                                     Twine TypeErrMsg,
+                                     const ErrorReporter &Reporter) {
+  if (T *Sec = dyn_cast<T>(getSection(Index, IndexErrMsg, Reporter)))
     return Sec;
-  error(TypeErrMsg);
+  Reporter.fatalError(errc::invalid_argument, TypeErrMsg);
 }
 
 template <class ELFT>
@@ -1476,7 +1528,7 @@
   case SHT_REL:
   case SHT_RELA:
     if (Shdr.sh_flags & SHF_ALLOC) {
-      Data = unwrapOrError(ElfFile.getSectionContents(Shdr));
+      Data = unwrapOrFatalError(ElfFile.getSectionContents(Shdr), Reporter);
       return Obj.addSection<DynamicRelocationSection>(Data);
     }
     return Obj.addSection<RelocationSection>();
@@ -1485,7 +1537,7 @@
     // mean altering the memory image. There are no special link types or
     // anything so we can just use a Section.
     if (Shdr.sh_flags & SHF_ALLOC) {
-      Data = unwrapOrError(ElfFile.getSectionContents(Shdr));
+      Data = unwrapOrFatalError(ElfFile.getSectionContents(Shdr), Reporter);
       return Obj.addSection<Section>(Data);
     }
     return Obj.addSection<StringTableSection>();
@@ -1493,16 +1545,16 @@
   case SHT_GNU_HASH:
     // Hash tables should refer to SHT_DYNSYM which we're not going to change.
     // Because of this we don't need to mess with the hash tables either.
-    Data = unwrapOrError(ElfFile.getSectionContents(Shdr));
+    Data = unwrapOrFatalError(ElfFile.getSectionContents(Shdr), Reporter);
     return Obj.addSection<Section>(Data);
   case SHT_GROUP:
-    Data = unwrapOrError(ElfFile.getSectionContents(Shdr));
+    Data = unwrapOrFatalError(ElfFile.getSectionContents(Shdr), Reporter);
     return Obj.addSection<GroupSection>(Data);
   case SHT_DYNSYM:
-    Data = unwrapOrError(ElfFile.getSectionContents(Shdr));
+    Data = unwrapOrFatalError(ElfFile.getSectionContents(Shdr), Reporter);
     return Obj.addSection<DynamicSymbolTableSection>(Data);
   case SHT_DYNAMIC:
-    Data = unwrapOrError(ElfFile.getSectionContents(Shdr));
+    Data = unwrapOrFatalError(ElfFile.getSectionContents(Shdr), Reporter);
     return Obj.addSection<DynamicSection>(Data);
   case SHT_SYMTAB: {
     auto &SymTab = Obj.addSection<SymbolTableSection>();
@@ -1517,9 +1569,9 @@
   case SHT_NOBITS:
     return Obj.addSection<Section>(Data);
   default: {
-    Data = unwrapOrError(ElfFile.getSectionContents(Shdr));
+    Data = unwrapOrFatalError(ElfFile.getSectionContents(Shdr), Reporter);
 
-    StringRef Name = unwrapOrError(ElfFile.getSectionName(Shdr));
+    StringRef Name = unwrapOrFatalError(ElfFile.getSectionName(Shdr), Reporter);
     if (Name.startswith(".zdebug") || (Shdr.sh_flags & ELF::SHF_COMPRESSED)) {
       uint64_t DecompressedSize, DecompressedAlign;
       std::tie(DecompressedSize, DecompressedAlign) =
@@ -1535,13 +1587,14 @@
 
 template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() {
   uint32_t Index = 0;
-  for (const auto &Shdr : unwrapOrError(ElfFile.sections())) {
+  for (const auto &Shdr : unwrapOrFatalError(ElfFile.sections(), Reporter)) {
     if (Index == 0) {
       ++Index;
       continue;
     }
     auto &Sec = makeSection(Shdr);
-    Sec.Name = std::string(unwrapOrError(ElfFile.getSectionName(Shdr)));
+    Sec.Name =
+        std::string(unwrapOrFatalError(ElfFile.getSectionName(Shdr), Reporter));
     Sec.Type = Sec.OriginalType = Shdr.sh_type;
     Sec.Flags = Sec.OriginalFlags = Shdr.sh_flags;
     Sec.Addr = Shdr.sh_addr;
@@ -1562,7 +1615,7 @@
 template <class ELFT> void ELFBuilder<ELFT>::readSections(bool EnsureSymtab) {
   uint32_t ShstrIndex = ElfFile.getHeader().e_shstrndx;
   if (ShstrIndex == SHN_XINDEX)
-    ShstrIndex = unwrapOrError(ElfFile.getSection(0))->sh_link;
+    ShstrIndex = unwrapOrFatalError(ElfFile.getSection(0), Reporter)->sh_link;
 
   if (ShstrIndex == SHN_UNDEF)
     Obj.HadShdrs = false;
@@ -1573,19 +1626,20 @@
             "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " +
                 " is invalid",
             "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " +
-                " does not reference a string table");
+                " does not reference a string table",
+            Reporter);
 
   // If a section index table exists we'll need to initialize it before we
   // initialize the symbol table because the symbol table might need to
   // reference it.
   if (Obj.SectionIndexTable)
-    Obj.SectionIndexTable->initialize(Obj.sections());
+    Obj.SectionIndexTable->initialize(Obj.sections(), Reporter);
 
   // Now that all of the sections have been added we can fill out some extra
   // details about symbol tables. We need the symbol table filled out before
   // any relocations.
   if (Obj.SymbolTable) {
-    Obj.SymbolTable->initialize(Obj.sections());
+    Obj.SymbolTable->initialize(Obj.sections(), Reporter);
     initSymbolTable(Obj.SymbolTable);
   } else if (EnsureSymtab) {
     Obj.addNewSymbolTable();
@@ -1597,15 +1651,18 @@
   for (auto &Sec : Obj.sections()) {
     if (&Sec == Obj.SymbolTable)
       continue;
-    Sec.initialize(Obj.sections());
+    Sec.initialize(Obj.sections(), Reporter);
     if (auto RelSec = dyn_cast<RelocationSection>(&Sec)) {
-      auto Shdr = unwrapOrError(ElfFile.sections()).begin() + RelSec->Index;
+      auto Shdr = unwrapOrFatalError(ElfFile.sections(), Reporter).begin() +
+                  RelSec->Index;
       if (RelSec->Type == SHT_REL)
         initRelocations(RelSec, Obj.SymbolTable,
-                        unwrapOrError(ElfFile.rels(*Shdr)));
+                        unwrapOrFatalError(ElfFile.rels(*Shdr), Reporter),
+                        Reporter);
       else
         initRelocations(RelSec, Obj.SymbolTable,
-                        unwrapOrError(ElfFile.relas(*Shdr)));
+                        unwrapOrFatalError(ElfFile.relas(*Shdr), Reporter),
+                        Reporter);
     } else if (auto GroupSec = dyn_cast<GroupSection>(&Sec)) {
       initGroupSection(GroupSec);
     }
@@ -1619,8 +1676,10 @@
   // The ELFFile whose ELF headers and program headers are copied into the
   // output file. Normally the same as ElfFile, but if we're extracting a
   // loadable partition it will point to the partition's headers.
-  ELFFile<ELFT> HeadersFile = unwrapOrError(ELFFile<ELFT>::create(toStringRef(
-      {ElfFile.base() + EhdrOffset, ElfFile.getBufSize() - EhdrOffset})));
+  ELFFile<ELFT> HeadersFile = unwrapOrFatalError(
+      ELFFile<ELFT>::create(toStringRef(
+          {ElfFile.base() + EhdrOffset, ElfFile.getBufSize() - EhdrOffset})),
+      Reporter);
 
   auto &Ehdr = HeadersFile.getHeader();
   Obj.OSABI = Ehdr.e_ident[EI_OSABI];
@@ -1640,7 +1699,7 @@
 Reader::~Reader() {}
 
 std::unique_ptr<Object> BinaryReader::create(bool /*EnsureSymtab*/) const {
-  return BinaryELFBuilder(MemBuf, NewSymbolVisibility).build();
+  return BinaryELFBuilder(MemBuf, NewSymbolVisibility, Reporter).build();
 }
 
 Expected<std::vector<IHexRecord>> IHexReader::parse() const {
@@ -1670,30 +1729,30 @@
 }
 
 std::unique_ptr<Object> IHexReader::create(bool /*EnsureSymtab*/) const {
-  std::vector<IHexRecord> Records = unwrapOrError(parse());
-  return IHexELFBuilder(Records).build();
+  std::vector<IHexRecord> Records = unwrapOrFatalError(parse(), Reporter);
+  return IHexELFBuilder(Records, Reporter).build();
 }
 
 std::unique_ptr<Object> ELFReader::create(bool EnsureSymtab) const {
-  auto Obj = std::make_unique<Object>();
+  auto Obj = std::make_unique<Object>(Reporter);
   if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) {
-    ELFBuilder<ELF32LE> Builder(*O, *Obj, ExtractPartition);
+    ELFBuilder<ELF32LE> Builder(*O, *Obj, ExtractPartition, Reporter);
     Builder.build(EnsureSymtab);
     return Obj;
   } else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) {
-    ELFBuilder<ELF64LE> Builder(*O, *Obj, ExtractPartition);
+    ELFBuilder<ELF64LE> Builder(*O, *Obj, ExtractPartition, Reporter);
     Builder.build(EnsureSymtab);
     return Obj;
   } else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) {
-    ELFBuilder<ELF32BE> Builder(*O, *Obj, ExtractPartition);
+    ELFBuilder<ELF32BE> Builder(*O, *Obj, ExtractPartition, Reporter);
     Builder.build(EnsureSymtab);
     return Obj;
   } else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) {
-    ELFBuilder<ELF64BE> Builder(*O, *Obj, ExtractPartition);
+    ELFBuilder<ELF64BE> Builder(*O, *Obj, ExtractPartition, Reporter);
     Builder.build(EnsureSymtab);
     return Obj;
   }
-  error("invalid file type");
+  Reporter.fatalError(errc::invalid_argument, "invalid file type");
 }
 
 template <class ELFT> void ELFWriter<ELFT>::writeEhdr() {
@@ -1816,8 +1875,8 @@
 
 template <class ELFT>
 ELFWriter<ELFT>::ELFWriter(Object &Obj, Buffer &Buf, bool WSH,
-                           bool OnlyKeepDebug)
-    : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs),
+                           bool OnlyKeepDebug, const ErrorReporter &Reporter)
+    : Writer(Obj, Buf, Reporter), WriteSectionHeaders(WSH && Obj.HadShdrs),
       OnlyKeepDebug(OnlyKeepDebug) {}
 
 Error Object::removeSections(bool AllowBrokenLinks,
@@ -1901,7 +1960,7 @@
   SymbolTableSection &SymTab = addSection<SymbolTableSection>();
   SymTab.Name = ".symtab";
   SymTab.Link = StrTab->Index;
-  SymTab.initialize(sections());
+  SymTab.initialize(sections(), Reporter);
   SymTab.addSymbol("", 0, 0, nullptr, 0, 0, 0, 0);
 
   SymbolTable = &SymTab;
@@ -2242,7 +2301,7 @@
 
   if (Error E = Buf.allocate(totalSize()))
     return E;
-  SecWriter = std::make_unique<ELFSectionWriter<ELFT>>(Buf);
+  SecWriter = std::make_unique<ELFSectionWriter<ELFT>>(Buf, Reporter);
   return Error::success();
 }
 
@@ -2279,7 +2338,7 @@
 
   if (Error E = Buf.allocate(TotalSize))
     return E;
-  SecWriter = std::make_unique<BinarySectionWriter>(Buf);
+  SecWriter = std::make_unique<BinarySectionWriter>(Buf, Reporter);
   return Error::success();
 }
 
@@ -2317,7 +2376,7 @@
 }
 
 Error IHexWriter::write() {
-  IHexSectionWriter Writer(Buf);
+  IHexSectionWriter Writer(Buf, Reporter);
   // Write sections.
   for (const SectionBase *Sec : Sections)
     Sec->accept(Writer);
@@ -2372,7 +2431,7 @@
       Sections.insert(&Sec);
     }
 
-  IHexSectionWriterBase LengthCalc(Buf);
+  IHexSectionWriterBase LengthCalc(Buf, Reporter);
   for (const SectionBase *Sec : Sections)
     Sec->accept(LengthCalc);
 
diff --git a/llvm/tools/llvm-objcopy/Error.h b/llvm/tools/llvm-objcopy/Error.h
new file mode 100644
--- /dev/null
+++ b/llvm/tools/llvm-objcopy/Error.h
@@ -0,0 +1,120 @@
+//===- Error.h --------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_OBJCOPY_ERROR_H
+#define LLVM_TOOLS_LLVM_OBJCOPY_ERROR_H
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+
+namespace llvm {
+namespace objcopy {
+
+/// ErrorReporter class reports error messages(errors/fatal errors/warnings)
+/// to llvm::errs() output stream.
+class ErrorReporter {
+public:
+  virtual ~ErrorReporter() {}
+
+  virtual void error(std::error_code EC, Twine Message,
+                     StringRef Context = "") const {
+    RecoverableErrorHandler(createStringError(EC, Message), Context);
+  }
+  virtual void error(Error E, StringRef Context = "") const {
+    RecoverableErrorHandler(std::move(E), Context);
+  }
+
+  virtual LLVM_ATTRIBUTE_NORETURN void
+  fatalError(std::error_code EC, Twine Message, StringRef Context = "") const {
+    UnrecoverableErrorHandler(createStringError(EC, Message), Context);
+    exit(1);
+  }
+  virtual LLVM_ATTRIBUTE_NORETURN void
+  fatalError(Error E, StringRef Context = "") const {
+    UnrecoverableErrorHandler(std::move(E), Context);
+    exit(1);
+  }
+
+  virtual void warning(std::error_code EC, Twine Message,
+                       StringRef Context = "") const {
+    WarningHandler(createStringError(EC, Message), Context);
+  }
+  virtual void warning(Error E, StringRef Context = "") const {
+    WarningHandler(std::move(E), Context);
+  }
+
+  virtual void setGlobalContext(StringRef GlobalContext) {
+    this->GlobalContext = GlobalContext.str();
+  }
+
+  virtual void setRecoverableErrorHandler(
+      std::function<void(Error, StringRef)> RecoverableErrorHandler) {
+    this->RecoverableErrorHandler = RecoverableErrorHandler;
+  }
+
+  virtual void setUnrecoverableErrorHandler(
+      std::function<void(Error, StringRef)> UnrecoverableErrorHandler) {
+    this->UnrecoverableErrorHandler = UnrecoverableErrorHandler;
+  }
+
+  virtual void
+  setWarningHandler(std::function<void(Error, StringRef)> WarningHandler) {
+    this->WarningHandler = WarningHandler;
+  }
+
+protected:
+  // Name of global context(usually binary/utility name).
+  std::string GlobalContext;
+
+  // Handler for recoverable errors.
+  std::function<void(Error, StringRef)> RecoverableErrorHandler =
+      [&](Error Err, StringRef Context) {
+        defaultHandlerImpl(std::move(Err), Context, true);
+      };
+
+  // Handler for unrecoverable errors.
+  std::function<void(Error, StringRef)> UnrecoverableErrorHandler =
+      [&](Error Err, StringRef Context) {
+        defaultHandlerImpl(std::move(Err), Context, true);
+      };
+
+  // Handler for warnings.
+  std::function<void(Error, StringRef)> WarningHandler =
+      [&](Error Err, StringRef Context) {
+        defaultHandlerImpl(std::move(Err), Context, false);
+      };
+
+  void defaultHandlerImpl(Error Err, StringRef Context, bool IsError) {
+    if (!GlobalContext.empty())
+      errs() << GlobalContext << ": ";
+    raw_ostream &Out = IsError ? WithColor::error() : WithColor::warning();
+    handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
+      if (!Context.empty())
+        Out << "'" << Context << "': ";
+
+      Out << Info.message() << '\n';
+    });
+  }
+};
+
+template <class T>
+T unwrapOrFatalError(Expected<T> EO, const ErrorReporter &Reporter) {
+  if (EO)
+    return *EO;
+  Reporter.fatalError(EO.takeError());
+}
+
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_LLVM_OBJCOPY_ERROR_H
diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
--- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
+++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
@@ -354,7 +354,7 @@
 
 Error executeObjcopyOnBinary(const CopyConfig &Config,
                              object::MachOObjectFile &In, Buffer &Out) {
-  MachOReader Reader(In);
+  MachOReader Reader(In, Config.Reporter);
   std::unique_ptr<Object> O = Reader.create();
   if (!O)
     return createFileError(
diff --git a/llvm/tools/llvm-objcopy/MachO/MachOReader.h b/llvm/tools/llvm-objcopy/MachO/MachOReader.h
--- a/llvm/tools/llvm-objcopy/MachO/MachOReader.h
+++ b/llvm/tools/llvm-objcopy/MachO/MachOReader.h
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "Error.h"
 #include "MachOObjcopy.h"
 #include "Object.h"
 #include "llvm/BinaryFormat/MachO.h"
@@ -20,8 +21,12 @@
 // raw binaries and regular MachO object files.
 class Reader {
 public:
+  Reader(const ErrorReporter &Reporter) : Reporter(Reporter) {}
   virtual ~Reader(){};
   virtual std::unique_ptr<Object> create() const = 0;
+
+protected:
+  const ErrorReporter &Reporter;
 };
 
 class MachOReader : public Reader {
@@ -44,7 +49,9 @@
   void readSwiftVersion(Object &O) const;
 
 public:
-  explicit MachOReader(const object::MachOObjectFile &Obj) : MachOObj(Obj) {}
+  explicit MachOReader(const object::MachOObjectFile &Obj,
+                       const ErrorReporter &Reporter)
+      : Reader(Reporter), MachOObj(Obj) {}
 
   std::unique_ptr<Object> create() const override;
 };
diff --git a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp
--- a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp
+++ b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp
@@ -64,7 +64,7 @@
 std::vector<std::unique_ptr<Section>>
 extractSections(const object::MachOObjectFile::LoadCommandInfo &LoadCmd,
                 const object::MachOObjectFile &MachOObj,
-                uint32_t &NextSectionIndex) {
+                uint32_t &NextSectionIndex, const ErrorReporter &Reporter) {
   auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize;
   const SectionType *Curr =
       reinterpret_cast<const SectionType *>(LoadCmd.Ptr + sizeof(SegmentType));
@@ -86,14 +86,14 @@
     Expected<object::SectionRef> SecRef =
         MachOObj.getSection(NextSectionIndex++);
     if (!SecRef)
-      reportError(MachOObj.getFileName(), SecRef.takeError());
+      Reporter.fatalError(SecRef.takeError(), MachOObj.getFileName());
 
     if (Expected<ArrayRef<uint8_t>> E =
             MachOObj.getSectionContents(SecRef->getRawDataRefImpl()))
       S.Content =
           StringRef(reinterpret_cast<const char *>(E->data()), E->size());
     else
-      reportError(MachOObj.getFileName(), E.takeError());
+      Reporter.fatalError(E.takeError(), MachOObj.getFileName());
 
     S.Relocations.reserve(S.NReloc);
     for (auto RI = MachOObj.section_rel_begin(SecRef->getRawDataRefImpl()),
@@ -124,12 +124,12 @@
       break;
     case MachO::LC_SEGMENT:
       LC.Sections = extractSections<MachO::section, MachO::segment_command>(
-          LoadCmd, MachOObj, NextSectionIndex);
+          LoadCmd, MachOObj, NextSectionIndex, Reporter);
       break;
     case MachO::LC_SEGMENT_64:
       LC.Sections =
           extractSections<MachO::section_64, MachO::segment_command_64>(
-              LoadCmd, MachOObj, NextSectionIndex);
+              LoadCmd, MachOObj, NextSectionIndex, Reporter);
       break;
     case MachO::LC_SYMTAB:
       O.SymTabCommandIndex = O.LoadCommands.size();
diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.h b/llvm/tools/llvm-objcopy/llvm-objcopy.h
--- a/llvm/tools/llvm-objcopy/llvm-objcopy.h
+++ b/llvm/tools/llvm-objcopy/llvm-objcopy.h
@@ -18,24 +18,6 @@
 namespace llvm {
 namespace objcopy {
 
-LLVM_ATTRIBUTE_NORETURN extern void error(Twine Message);
-LLVM_ATTRIBUTE_NORETURN extern void error(Error E);
-LLVM_ATTRIBUTE_NORETURN extern void reportError(StringRef File, Error E);
-LLVM_ATTRIBUTE_NORETURN extern void reportError(StringRef File,
-                                                std::error_code EC);
-
-// This is taken from llvm-readobj.
-// [see here](llvm/tools/llvm-readobj/llvm-readobj.h:38)
-template <class T> T unwrapOrError(Expected<T> EO) {
-  if (EO)
-    return *EO;
-  std::string Buf;
-  raw_string_ostream OS(Buf);
-  logAllUnhandledErrors(EO.takeError(), OS);
-  OS.flush();
-  error(Buf);
-}
-
 } // end namespace objcopy
 } // end namespace llvm
 
diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
--- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -57,41 +57,7 @@
 // The name this program was invoked as.
 StringRef ToolName;
 
-LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
-  WithColor::error(errs(), ToolName) << Message << "\n";
-  exit(1);
-}
-
-LLVM_ATTRIBUTE_NORETURN void error(Error E) {
-  assert(E);
-  std::string Buf;
-  raw_string_ostream OS(Buf);
-  logAllUnhandledErrors(std::move(E), OS);
-  OS.flush();
-  WithColor::error(errs(), ToolName) << Buf;
-  exit(1);
-}
-
-LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
-  assert(EC);
-  error(createFileError(File, EC));
-}
-
-LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
-  assert(E);
-  std::string Buf;
-  raw_string_ostream OS(Buf);
-  logAllUnhandledErrors(std::move(E), OS);
-  OS.flush();
-  WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
-  exit(1);
-}
-
-ErrorSuccess reportWarning(Error E) {
-  assert(E);
-  WithColor::warning(errs(), ToolName) << toString(std::move(E)) << '\n';
-  return Error::success();
-}
+ErrorReporter Reporter;
 
 } // end namespace objcopy
 } // end namespace llvm
@@ -327,6 +293,7 @@
 int main(int argc, char **argv) {
   InitLLVM X(argc, argv);
   ToolName = argv[0];
+  Reporter.setGlobalContext(ToolName);
 
   StringRef Stem = sys::path::stem(ToolName);
   auto Is = [=](StringRef Tool) {
@@ -364,12 +331,12 @@
   auto Args = makeArrayRef(NewArgv).drop_front();
   Expected<DriverConfig> DriverConfig =
       (Tool == ToolType::Strip)
-          ? parseStripOptions(Args, reportWarning)
+          ? parseStripOptions(Args, Reporter)
           : ((Tool == ToolType::InstallNameTool)
-                 ? parseInstallNameToolOptions(Args)
+                 ? parseInstallNameToolOptions(Args, Reporter)
                  : ((Tool == ToolType::BitcodeStrip)
-                        ? parseBitcodeStripOptions(Args)
-                        : parseObjcopyOptions(Args, reportWarning)));
+                        ? parseBitcodeStripOptions(Args, Reporter)
+                        : parseObjcopyOptions(Args, Reporter)));
   if (!DriverConfig) {
     logAllUnhandledErrors(DriverConfig.takeError(),
                           WithColor::error(errs(), ToolName));