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,13 @@ Obj.IsPE ? Obj.PeHeader.SectionAlignment : 1); } -static std::vector createGnuDebugLinkSectionContents(StringRef File) { +static std::vector +createGnuDebugLinkSectionContents(StringRef File, ErrorReporter Reporter) { ErrorOr> 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 +83,10 @@ Obj.addSections(Sec); } -static void addGnuDebugLink(Object &Obj, StringRef DebugLinkFile) { +static void addGnuDebugLink(Object &Obj, StringRef DebugLinkFile, + const ErrorReporter &Reporter) { std::vector 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 +187,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 +243,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(ErrorReporter &Reporter) : Reporter(Reporter) {} + // Format-specific options to be initialized lazily when needed. Optional ELF; @@ -232,6 +235,8 @@ bool DecompressDebugSections = false; DebugCompressionType CompressionType = DebugCompressionType::None; + std::reference_wrapper 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 -parseObjcopyOptions(ArrayRef ArgsArr, - llvm::function_ref ErrorCallback); +// exit. ErrorReporter is used to report errors. +Expected parseObjcopyOptions(ArrayRef ArgsArr, + 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 -parseInstallNameToolOptions(ArrayRef ArgsArr); +parseInstallNameToolOptions(ArrayRef ArgsArr, + 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 parseBitcodeStripOptions(ArrayRef ArgsArr); +// messege and exit. ErrorReporter is used to report errors. +Expected parseBitcodeStripOptions(ArrayRef ArgsArr, + 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 -parseStripOptions(ArrayRef ArgsArr, - llvm::function_ref ErrorCallback); +// exit. ErrorReporter is used to handle errors. +Expected parseStripOptions(ArrayRef ArgsArr, + 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 -parseObjcopyOptions(ArrayRef ArgsArr, - llvm::function_ref ErrorCallback) { +Expected parseObjcopyOptions(ArrayRef ArgsArr, + 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 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 -parseInstallNameToolOptions(ArrayRef ArgsArr) { +parseInstallNameToolOptions(ArrayRef ArgsArr, + 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 -parseBitcodeStripOptions(ArrayRef ArgsArr) { +Expected parseBitcodeStripOptions(ArrayRef ArgsArr, + 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 -parseStripOptions(ArrayRef ArgsArr, - llvm::function_ref ErrorCallback) { +Expected parseStripOptions(ArrayRef ArgsArr, + 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 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>(Obj, Buf, !Config.StripSections, - Config.OnlyKeepDebug); + return std::make_unique>( + Obj, Buf, !Config.StripSections, Config.OnlyKeepDebug, Config.Reporter); case ELFT_ELF64LE: - return std::make_unique>(Obj, Buf, !Config.StripSections, - Config.OnlyKeepDebug); + return std::make_unique>( + Obj, Buf, !Config.StripSections, Config.OnlyKeepDebug, Config.Reporter); case ELFT_ELF32BE: - return std::make_unique>(Obj, Buf, !Config.StripSections, - Config.OnlyKeepDebug); + return std::make_unique>( + Obj, Buf, !Config.StripSections, Config.OnlyKeepDebug, Config.Reporter); case ELFT_ELF64BE: - return std::make_unique>(Obj, Buf, !Config.StripSections, - Config.OnlyKeepDebug); + return std::make_unique>( + 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(Obj, Buf); + return std::make_unique(Obj, Buf, Config.Reporter); case FileFormat::IHex: - return std::make_unique(Obj, Buf); + return std::make_unique(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( - *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 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 Obj = Reader.create(true); // Prefer OutputArch (-O) 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 Obj = Reader.create(!Config.SymbolsToAdd.empty()); // Prefer OutputArch (-O) 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 - 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 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 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; @@ -282,7 +291,8 @@ virtual void writeData(uint8_t Type, uint16_t Addr, ArrayRef 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 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 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 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 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 Callable); Error removeSectionReferences(bool AllowBrokenLinks, function_ref 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 create(bool EnsureSymtab) const = 0; + +protected: + const ErrorReporter &Reporter; }; using object::Binary; @@ -886,6 +912,7 @@ class BasicELFBuilder { protected: std::unique_ptr Obj; + const ErrorReporter &Reporter; void initFileHeader(); void initHeaderSegment(); @@ -894,7 +921,8 @@ void initSections(); public: - BasicELFBuilder() : Obj(std::make_unique()) {} + BasicELFBuilder(const ErrorReporter &Reporter) + : Obj(std::make_unique(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 build(); @@ -916,8 +945,9 @@ void addDataSections(); public: - IHexELFBuilder(const std::vector &Records) - : BasicELFBuilder(), Records(Records) {} + IHexELFBuilder(const std::vector &Records, + const ErrorReporter &Reporter) + : BasicELFBuilder(Reporter), Records(Records) {} std::unique_ptr build(); }; @@ -932,6 +962,7 @@ Object &Obj; size_t EhdrOffset = 0; Optional ExtractPartition; + const ErrorReporter &Reporter; void setParentSegment(Segment &Child); void readProgramHeaders(const ELFFile &HeadersFile); @@ -944,9 +975,10 @@ public: ELFBuilder(const ELFObjectFile &ElfObj, Object &Obj, - Optional ExtractPartition) + Optional 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 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 create(bool EnsureSymtab) const override; }; @@ -989,8 +1024,9 @@ public: std::unique_ptr create(bool EnsureSymtab) const override; - explicit ELFReader(Binary *B, Optional ExtractPartition) - : Bin(B), ExtractPartition(ExtractPartition) {} + explicit ELFReader(Binary *B, Optional ExtractPartition, + const ErrorReporter &Reporter) + : Reader(Reporter), Bin(B), ExtractPartition(ExtractPartition) {} }; class Object { @@ -1002,11 +1038,15 @@ std::vector Segments; std::vector RemovedSections; + const ErrorReporter &Reporter; + static bool sectionIsAlloc(const SectionBase &Sec) { return Sec.Flags & ELF::SHF_ALLOC; }; public: + Object(const ErrorReporter &Reporter) : Reporter(Reporter) {} + template using Range = iterator_range< pointee_iterator>::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::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 DecompressedContent; if (Error E = zlib::uncompress(CompressedContent, DecompressedContent, static_cast(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 @@ -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(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(Buf)); } -void SectionIndexSection::initialize(SectionTableRef SecTable) { +void SectionIndexSection::initialize(SectionTableRef SecTable, + const ErrorReporter &Reporter) { Size = 0; setSymTab(SecTable.getSectionOfType( 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( 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( - static_cast(this)->getSymbolByIndex(Index)); + static_cast(this)->getSymbolByIndex( + Index, Reporter)); } template @@ -835,19 +856,21 @@ template void RelocSectionWithSymtabBase::initialize( - SectionTableRef SecTable) { + SectionTableRef SecTable, const ErrorReporter &Reporter) { if (Link != SHN_UNDEF) setSymTab(SecTable.getSectionOfType( 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 void ELFBuilder::readProgramHeaders(const ELFFile &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 Data{HeadersFile.base() + Phdr.p_offset, (size_t)Phdr.p_filesz}; @@ -1346,8 +1376,9 @@ template void ELFBuilder::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( @@ -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(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(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 void ELFBuilder::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 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(ShndxSec)); + const Elf_Shdr &ShndxSec = *unwrapOrFatalError( + ElfFile.getSection(SymTab->getShndxTable()->Index), Reporter); + ShndxData = unwrapOrFatalError( + ElfFile.template getSectionContentsAsArray(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 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 T *SectionTableRef::getSectionOfType(uint32_t Index, Twine IndexErrMsg, - Twine TypeErrMsg) { - if (T *Sec = dyn_cast(getSection(Index, IndexErrMsg))) + Twine TypeErrMsg, + const ErrorReporter &Reporter) { + if (T *Sec = dyn_cast(getSection(Index, IndexErrMsg, Reporter))) return Sec; - error(TypeErrMsg); + Reporter.fatalError(errc::invalid_argument, TypeErrMsg); } template @@ -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(Data); } return Obj.addSection(); @@ -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
(Data); } return Obj.addSection(); @@ -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
(Data); case SHT_GROUP: - Data = unwrapOrError(ElfFile.getSectionContents(Shdr)); + Data = unwrapOrFatalError(ElfFile.getSectionContents(Shdr), Reporter); return Obj.addSection(Data); case SHT_DYNSYM: - Data = unwrapOrError(ElfFile.getSectionContents(Shdr)); + Data = unwrapOrFatalError(ElfFile.getSectionContents(Shdr), Reporter); return Obj.addSection(Data); case SHT_DYNAMIC: - Data = unwrapOrError(ElfFile.getSectionContents(Shdr)); + Data = unwrapOrFatalError(ElfFile.getSectionContents(Shdr), Reporter); return Obj.addSection(Data); case SHT_SYMTAB: { auto &SymTab = Obj.addSection(); @@ -1517,9 +1569,9 @@ case SHT_NOBITS: return Obj.addSection
(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 void ELFBuilder::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 void ELFBuilder::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(&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(&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 HeadersFile = unwrapOrError(ELFFile::create(toStringRef( - {ElfFile.base() + EhdrOffset, ElfFile.getBufSize() - EhdrOffset}))); + ELFFile HeadersFile = unwrapOrFatalError( + ELFFile::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 BinaryReader::create(bool /*EnsureSymtab*/) const { - return BinaryELFBuilder(MemBuf, NewSymbolVisibility).build(); + return BinaryELFBuilder(MemBuf, NewSymbolVisibility, Reporter).build(); } Expected> IHexReader::parse() const { @@ -1670,30 +1729,30 @@ } std::unique_ptr IHexReader::create(bool /*EnsureSymtab*/) const { - std::vector Records = unwrapOrError(parse()); - return IHexELFBuilder(Records).build(); + std::vector Records = unwrapOrFatalError(parse(), Reporter); + return IHexELFBuilder(Records, Reporter).build(); } std::unique_ptr ELFReader::create(bool EnsureSymtab) const { - auto Obj = std::make_unique(); + auto Obj = std::make_unique(Reporter); if (auto *O = dyn_cast>(Bin)) { - ELFBuilder Builder(*O, *Obj, ExtractPartition); + ELFBuilder Builder(*O, *Obj, ExtractPartition, Reporter); Builder.build(EnsureSymtab); return Obj; } else if (auto *O = dyn_cast>(Bin)) { - ELFBuilder Builder(*O, *Obj, ExtractPartition); + ELFBuilder Builder(*O, *Obj, ExtractPartition, Reporter); Builder.build(EnsureSymtab); return Obj; } else if (auto *O = dyn_cast>(Bin)) { - ELFBuilder Builder(*O, *Obj, ExtractPartition); + ELFBuilder Builder(*O, *Obj, ExtractPartition, Reporter); Builder.build(EnsureSymtab); return Obj; } else if (auto *O = dyn_cast>(Bin)) { - ELFBuilder Builder(*O, *Obj, ExtractPartition); + ELFBuilder Builder(*O, *Obj, ExtractPartition, Reporter); Builder.build(EnsureSymtab); return Obj; } - error("invalid file type"); + Reporter.fatalError(errc::invalid_argument, "invalid file type"); } template void ELFWriter::writeEhdr() { @@ -1816,8 +1875,8 @@ template ELFWriter::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(); 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>(Buf); + SecWriter = std::make_unique>(Buf, Reporter); return Error::success(); } @@ -2279,7 +2338,7 @@ if (Error E = Buf.allocate(TotalSize)) return E; - SecWriter = std::make_unique(Buf); + SecWriter = std::make_unique(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_OBJCOPY_ERROR_H +#define LLVM_TOOLS_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 + +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 RecoverableErrorHandler) { + this->RecoverableErrorHandler = RecoverableErrorHandler; + } + + virtual void setUnrecoverableErrorHandler( + std::function UnrecoverableErrorHandler) { + this->UnrecoverableErrorHandler = UnrecoverableErrorHandler; + } + + virtual void + setWarningHandler(std::function WarningHandler) { + this->WarningHandler = WarningHandler; + } + +protected: + // Name of global context(usually binary/utility name). + std::string globalContext; + + // Handler for recoverable errors. + std::function RecoverableErrorHandler = + [&](Error Err, StringRef Context) { + defaultHandlerImpl(std::move(Err), Context, true); + }; + + // Handler for unrecoverable errors. + std::function UnrecoverableErrorHandler = + [&](Error Err, StringRef Context) { + defaultHandlerImpl(std::move(Err), Context, true); + }; + + // Handler for warnings. + std::function 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 +T unwrapOrFatalError(Expected EO, const ErrorReporter &Reporter) { + if (EO) + return *EO; + Reporter.fatalError(EO.takeError()); +} + +} // end namespace objcopy +} // end namespace llvm + +#endif // LLVM_TOOLS_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 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 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 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> 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(LoadCmd.Ptr + sizeof(SegmentType)); @@ -86,14 +86,14 @@ Expected SecRef = MachOObj.getSection(NextSectionIndex++); if (!SecRef) - reportError(MachOObj.getFileName(), SecRef.takeError()); + Reporter.fatalError(SecRef.takeError(), MachOObj.getFileName()); if (Expected> E = MachOObj.getSectionContents(SecRef->getRawDataRefImpl())) S.Content = StringRef(reinterpret_cast(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( - LoadCmd, MachOObj, NextSectionIndex); + LoadCmd, MachOObj, NextSectionIndex, Reporter); break; case MachO::LC_SEGMENT_64: LC.Sections = extractSections( - 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 T unwrapOrError(Expected 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 = (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));