Index: include/llvm/Object/Binary.h =================================================================== --- include/llvm/Object/Binary.h +++ include/llvm/Object/Binary.h @@ -135,7 +135,8 @@ /// /// @param Source The data to create the Binary from. Expected> createBinary(MemoryBufferRef Source, - LLVMContext *Context = nullptr); + LLVMContext *Context = nullptr, + bool IgnoreValueErrs = false); template class OwningBinary { std::unique_ptr Bin; @@ -185,7 +186,8 @@ return Bin.get(); } -Expected> createBinary(StringRef Path); +Expected> createBinary(StringRef Path, + bool IgnoreValueErrs = false); } } Index: include/llvm/Object/Error.h =================================================================== --- include/llvm/Object/Error.h +++ include/llvm/Object/Error.h @@ -73,6 +73,25 @@ std::string Msg; }; +/// Unknown value error. +/// +/// This type is for unrecognized values in otherwise correct binaries. This is +/// used in the Mach-o parser for unrecognized load command ids, but could be +/// expanded to encompass other unrecognized values that do not impact the +/// ability to parse an object file. +class UnknownValueError : public ErrorInfo { +public: + static char ID; + UnknownValueError(Twine Msg); + UnknownValueError(Twine Msg, object_error ECOverride); + const std::string &getMessage() const { return Msg; } + void log(raw_ostream &OS) const override; +private: + std::string Msg; +}; + +Error filterUnknownValueErrors(Error Err); + /// isNotObjectErrorInvalidFileType() is used when looping through the children /// of an archive after calling getAsBinary() on the child and it returns an /// llvm::Error. In the cases we want to loop through the children and ignore the Index: include/llvm/Object/MachO.h =================================================================== --- include/llvm/Object/MachO.h +++ include/llvm/Object/MachO.h @@ -195,7 +195,8 @@ static Expected> create(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, - uint32_t UniversalCputype = 0, uint32_t UniversalIndex = 0); + uint32_t UniversalCputype = 0, uint32_t UniversalIndex = 0, + bool IgnoreValueErrs = false); void moveSymbolNext(DataRefImpl &Symb) const override; @@ -446,8 +447,8 @@ private: MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, - Error &Err, uint32_t UniversalCputype = 0, - uint32_t UniversalIndex = 0); + Error &Err, Error &ValueErr, uint32_t UniversalCputype = 0, + uint32_t UniversalIndex = 0, bool IgnoreValueErrs = false); uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; Index: include/llvm/Object/ObjectFile.h =================================================================== --- include/llvm/Object/ObjectFile.h +++ include/llvm/Object/ObjectFile.h @@ -277,18 +277,21 @@ /// @returns Pointer to ObjectFile subclass to handle this type of object. /// @param ObjectPath The path to the object file. ObjectPath.isObject must /// return true. + /// @param IgnoreValueErrors Bool to allow creating object files that are not + /// semantically valid, but are structurally correct. /// @brief Create ObjectFile from path. static Expected> - createObjectFile(StringRef ObjectPath); + createObjectFile(StringRef ObjectPath, bool IgnoreValueErrs = false); static Expected> - createObjectFile(MemoryBufferRef Object, sys::fs::file_magic Type); + createObjectFile(MemoryBufferRef Object, sys::fs::file_magic Type, + bool IgnoreValueErrs = false); static Expected> - createObjectFile(MemoryBufferRef Object) { - return createObjectFile(Object, sys::fs::file_magic::unknown); + createObjectFile(MemoryBufferRef Object, bool IgnoreValueErrs = false) { + return createObjectFile(Object, sys::fs::file_magic::unknown, + IgnoreValueErrs); } - static inline bool classof(const Binary *v) { return v->isObject(); } @@ -300,10 +303,9 @@ createELFObjectFile(MemoryBufferRef Object); static Expected> - createMachOObjectFile(MemoryBufferRef Object, + createMachOObjectFile(MemoryBufferRef Object, bool IgnoreValueErrs = false, uint32_t UniversalCputype = 0, uint32_t UniversalIndex = 0); - }; // Inline function definitions. Index: include/llvm/Object/SymbolicFile.h =================================================================== --- include/llvm/Object/SymbolicFile.h +++ include/llvm/Object/SymbolicFile.h @@ -150,14 +150,13 @@ // construction aux. static Expected> createSymbolicFile(MemoryBufferRef Object, sys::fs::file_magic Type, - LLVMContext *Context); + LLVMContext *Context, bool IgnoreValueErrs = false); static Expected> - createSymbolicFile(MemoryBufferRef Object) { - return createSymbolicFile(Object, sys::fs::file_magic::unknown, nullptr); + createSymbolicFile(MemoryBufferRef Object, bool IgnoreValueErrs = false) { + return createSymbolicFile(Object, sys::fs::file_magic::unknown, nullptr, + IgnoreValueErrs); } - static Expected> - createSymbolicFile(StringRef ObjectPath); static inline bool classof(const Binary *v) { return v->isSymbolic(); Index: lib/Object/Binary.cpp =================================================================== --- lib/Object/Binary.cpp +++ lib/Object/Binary.cpp @@ -37,7 +37,8 @@ MemoryBufferRef Binary::getMemoryBufferRef() const { return Data; } Expected> object::createBinary(MemoryBufferRef Buffer, - LLVMContext *Context) { + LLVMContext *Context, + bool IgnoreValueErrs) { sys::fs::file_magic Type = sys::fs::identify_magic(Buffer.getBuffer()); switch (Type) { @@ -63,7 +64,7 @@ case sys::fs::file_magic::coff_import_library: case sys::fs::file_magic::pecoff_executable: case sys::fs::file_magic::bitcode: - return ObjectFile::createSymbolicFile(Buffer, Type, Context); + return ObjectFile::createSymbolicFile(Buffer, Type, Context, IgnoreValueErrs); case sys::fs::file_magic::macho_universal_binary: return MachOUniversalBinary::create(Buffer); case sys::fs::file_magic::unknown: @@ -75,7 +76,8 @@ llvm_unreachable("Unexpected Binary File Type"); } -Expected> object::createBinary(StringRef Path) { +Expected> object::createBinary(StringRef Path, + bool IgnoreValueErrs) { ErrorOr> FileOrErr = MemoryBuffer::getFileOrSTDIN(Path); if (std::error_code EC = FileOrErr.getError()) @@ -83,7 +85,7 @@ std::unique_ptr &Buffer = FileOrErr.get(); Expected> BinOrErr = - createBinary(Buffer->getMemBufferRef()); + createBinary(Buffer->getMemBufferRef(), nullptr, IgnoreValueErrs); if (!BinOrErr) return BinOrErr.takeError(); std::unique_ptr &Bin = BinOrErr.get(); Index: lib/Object/Error.cpp =================================================================== --- lib/Object/Error.cpp +++ lib/Object/Error.cpp @@ -59,6 +59,7 @@ char BinaryError::ID = 0; char GenericBinaryError::ID = 0; +char UnknownValueError::ID = 0; GenericBinaryError::GenericBinaryError(Twine Msg) : Msg(Msg.str()) {} @@ -71,6 +72,25 @@ OS << Msg; } +UnknownValueError::UnknownValueError(Twine Msg) : Msg(Msg.str()) {} + +UnknownValueError::UnknownValueError(Twine Msg, object_error ECOverride) + : Msg(Msg.str()) { + setErrorCode(make_error_code(ECOverride)); +} + +void UnknownValueError::log(raw_ostream &OS) const { + OS << Msg; +} + +Error object::filterUnknownValueErrors(Error Err) { + handleAllErrors(std::move(Err), [&](std::unique_ptr E) { + // Ignore unknown value errors + (void)!E; + }); + return Err; +} + static ManagedStatic<_object_error_category> error_category; const std::error_category &object::object_category() { Index: lib/Object/MachOObjectFile.cpp =================================================================== --- lib/Object/MachOObjectFile.cpp +++ lib/Object/MachOObjectFile.cpp @@ -46,6 +46,13 @@ object_error::parse_failed); } +static Error +unknownValueError(Twine Msg) { + std::string StringMsg = "unknown value found in object (" + Msg.str() + ")"; + return make_error(std::move(StringMsg), + object_error::parse_failed); +} + // FIXME: Replace all uses of this function with getStructOrErr. template static T getStruct(const MachOObjectFile *O, const char *P) { @@ -1072,27 +1079,38 @@ Expected> MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, uint32_t UniversalCputype, - uint32_t UniversalIndex) { + uint32_t UniversalIndex, bool IgnoreValueErrs) { Error Err = Error::success(); + Error ValueErr = Error::success(); std::unique_ptr Obj( - new MachOObjectFile(std::move(Object), IsLittleEndian, - Is64Bits, Err, UniversalCputype, - UniversalIndex)); + new MachOObjectFile(std::move(Object), IsLittleEndian, Is64Bits, Err, ValueErr, + UniversalCputype, UniversalIndex, IgnoreValueErrs)); + + if (ValueErr) { + if (IgnoreValueErrs) + handleAllErrors(std::move(ValueErr), + [&](std::unique_ptr E) {}); + else + Err = joinErrors(std::move(Err), std::move(ValueErr)); + } if (Err) return std::move(Err); return std::move(Obj); } MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, - bool Is64bits, Error &Err, + bool Is64bits, Error &Err, Error &ValueErr, uint32_t UniversalCputype, - uint32_t UniversalIndex) + uint32_t UniversalIndex, + bool IgnoreValueErrs) : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object), SymtabLoadCmd(nullptr), DysymtabLoadCmd(nullptr), DataInCodeLoadCmd(nullptr), LinkOptHintsLoadCmd(nullptr), DyldInfoLoadCmd(nullptr), UuidLoadCmd(nullptr), HasPageZeroSegment(false) { ErrorAsOutParameter ErrAsOutParam(&Err); + ErrorAsOutParameter ValueErrAsOutParam(&ValueErr); + ValueErr = Error::success(); uint64_t SizeOfHeaders; uint32_t cputype; if (is64Bit()) { @@ -1427,10 +1445,15 @@ Twine(Load.C.cmd) + " is obsolete and not " "supported"); return; + } else { + ValueErr = joinErrors(std::move(ValueErr), + unknownValueError("unknown load command " + + Twine(I) + " for cmd value of: " + + Twine(Load.C.cmd))); + if (!IgnoreValueErrs) + return; } - // TODO: generate a error for unknown load commands by default. But still - // need work out an approach to allow or not allow unknown values like this - // as an option for some uses like lldb. + if (I < LoadCommandCount - 1) { if (auto LoadOrErr = getNextLoadCommandInfo(this, I, Load)) Load = *LoadOrErr; @@ -3537,23 +3560,22 @@ return getHeader().filetype == MachO::MH_OBJECT; } -Expected> -ObjectFile::createMachOObjectFile(MemoryBufferRef Buffer, - uint32_t UniversalCputype, - uint32_t UniversalIndex) { +Expected> ObjectFile::createMachOObjectFile( + MemoryBufferRef Buffer, bool IgnoreValueErrs, uint32_t UniversalCputype, + uint32_t UniversalIndex) { StringRef Magic = Buffer.getBuffer().slice(0, 4); if (Magic == "\xFE\xED\xFA\xCE") - return MachOObjectFile::create(Buffer, false, false, - UniversalCputype, UniversalIndex); + return MachOObjectFile::create(Buffer, false, false, UniversalCputype, + UniversalIndex, IgnoreValueErrs); if (Magic == "\xCE\xFA\xED\xFE") - return MachOObjectFile::create(Buffer, true, false, - UniversalCputype, UniversalIndex); + return MachOObjectFile::create(Buffer, true, false, UniversalCputype, + UniversalIndex, IgnoreValueErrs); if (Magic == "\xFE\xED\xFA\xCF") - return MachOObjectFile::create(Buffer, false, true, - UniversalCputype, UniversalIndex); + return MachOObjectFile::create(Buffer, false, true, UniversalCputype, + UniversalIndex, IgnoreValueErrs); if (Magic == "\xCF\xFA\xED\xFE") - return MachOObjectFile::create(Buffer, true, true, - UniversalCputype, UniversalIndex); + return MachOObjectFile::create(Buffer, true, true, UniversalCputype, + UniversalIndex, IgnoreValueErrs); return make_error("Unrecognized MachO magic number", object_error::invalid_file_type); } Index: lib/Object/MachOUniversal.cpp =================================================================== --- lib/Object/MachOUniversal.cpp +++ lib/Object/MachOUniversal.cpp @@ -83,7 +83,7 @@ } StringRef ObjectName = Parent->getFileName(); MemoryBufferRef ObjBuffer(ObjectData, ObjectName); - return ObjectFile::createMachOObjectFile(ObjBuffer, cputype, Index); + return ObjectFile::createMachOObjectFile(ObjBuffer, false, cputype, Index); } Expected> Index: lib/Object/ObjectFile.cpp =================================================================== --- lib/Object/ObjectFile.cpp +++ lib/Object/ObjectFile.cpp @@ -70,7 +70,8 @@ } Expected> -ObjectFile::createObjectFile(MemoryBufferRef Object, sys::fs::file_magic Type) { +ObjectFile::createObjectFile(MemoryBufferRef Object, sys::fs::file_magic Type, + bool IgnoreValueErrs) { StringRef Data = Object.getBuffer(); if (Type == sys::fs::file_magic::unknown) Type = sys::fs::identify_magic(Data); @@ -100,7 +101,7 @@ case sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub: case sys::fs::file_magic::macho_dsym_companion: case sys::fs::file_magic::macho_kext_bundle: - return createMachOObjectFile(Object); + return createMachOObjectFile(Object, IgnoreValueErrs); case sys::fs::file_magic::coff_object: case sys::fs::file_magic::coff_import_library: case sys::fs::file_magic::pecoff_executable: @@ -110,7 +111,7 @@ } Expected> -ObjectFile::createObjectFile(StringRef ObjectPath) { +ObjectFile::createObjectFile(StringRef ObjectPath, bool IgnoreValueErrs) { ErrorOr> FileOrErr = MemoryBuffer::getFile(ObjectPath); if (std::error_code EC = FileOrErr.getError()) @@ -118,7 +119,7 @@ std::unique_ptr Buffer = std::move(FileOrErr.get()); Expected> ObjOrErr = - createObjectFile(Buffer->getMemBufferRef()); + createObjectFile(Buffer->getMemBufferRef(), IgnoreValueErrs); if (Error Err = ObjOrErr.takeError()) return std::move(Err); std::unique_ptr Obj = std::move(ObjOrErr.get()); Index: lib/Object/SymbolicFile.cpp =================================================================== --- lib/Object/SymbolicFile.cpp +++ lib/Object/SymbolicFile.cpp @@ -27,7 +27,8 @@ SymbolicFile::~SymbolicFile() {} Expected> SymbolicFile::createSymbolicFile( - MemoryBufferRef Object, sys::fs::file_magic Type, LLVMContext *Context) { + MemoryBufferRef Object, sys::fs::file_magic Type, LLVMContext *Context, + bool IgnoreValueErrs) { StringRef Data = Object.getBuffer(); if (Type == sys::fs::file_magic::unknown) Type = sys::fs::identify_magic(Data); @@ -58,14 +59,14 @@ case sys::fs::file_magic::macho_dsym_companion: case sys::fs::file_magic::macho_kext_bundle: case sys::fs::file_magic::pecoff_executable: - return ObjectFile::createObjectFile(Object, Type); + return ObjectFile::createObjectFile(Object, Type, IgnoreValueErrs); case sys::fs::file_magic::coff_import_library: return std::unique_ptr(new COFFImportFile(Object)); case sys::fs::file_magic::elf_relocatable: case sys::fs::file_magic::macho_object: case sys::fs::file_magic::coff_object: { Expected> Obj = - ObjectFile::createObjectFile(Object, Type); + ObjectFile::createObjectFile(Object, Type, IgnoreValueErrs); if (!Obj || !Context) return std::move(Obj); Index: test/Object/macho-unknown-lc-id.test =================================================================== --- /dev/null +++ test/Object/macho-unknown-lc-id.test @@ -0,0 +1,2 @@ +#RUN: not llvm-objdump -private-headers %p/Inputs/macho-unknown-lc-id -macho 2>&1 | FileCheck %s +#CHECK: unknown value found in object (unknown load command 0 for cmd value of: 3735928559) Index: tools/obj2yaml/obj2yaml.cpp =================================================================== --- tools/obj2yaml/obj2yaml.cpp +++ tools/obj2yaml/obj2yaml.cpp @@ -29,7 +29,7 @@ } static std::error_code dumpInput(StringRef File) { - Expected> BinaryOrErr = createBinary(File); + Expected> BinaryOrErr = createBinary(File, true); if (!BinaryOrErr) return errorToErrorCode(BinaryOrErr.takeError());