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; @@ -447,7 +448,7 @@ MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, Error &Err, uint32_t UniversalCputype = 0, - uint32_t UniversalIndex = 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,12 +1079,14 @@ Expected> MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, uint32_t UniversalCputype, - uint32_t UniversalIndex) { + uint32_t UniversalIndex, bool IgnoreValueErrs) { Error Err = Error::success(); std::unique_ptr Obj( - new MachOObjectFile(std::move(Object), IsLittleEndian, - Is64Bits, Err, UniversalCputype, - UniversalIndex)); + new MachOObjectFile(std::move(Object), IsLittleEndian, Is64Bits, Err, + UniversalCputype, UniversalIndex, IgnoreValueErrs)); + + if (IgnoreValueErrs) + Err = filterUnknownValueErrors(std::move(Err)); if (Err) return std::move(Err); return std::move(Obj); @@ -1086,7 +1095,8 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64bits, Error &Err, uint32_t UniversalCputype, - uint32_t UniversalIndex) + uint32_t UniversalIndex, + bool IgnoreValueErrs) : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object), SymtabLoadCmd(nullptr), DysymtabLoadCmd(nullptr), DataInCodeLoadCmd(nullptr), LinkOptHintsLoadCmd(nullptr), @@ -1151,295 +1161,323 @@ // allowed since the macOS kernel produces them. if (getHeader().filetype != MachO::MH_CORE || Load.C.cmd != MachO::LC_THREAD || Load.C.cmdsize % 4) { - Err = malformedError("load command " + Twine(I) + " cmdsize not a " - "multiple of 8"); + Err = joinErrors(std::move(Err), + malformedError("load command " + Twine(I) + + " cmdsize not a multiple of 8")); return; } } } else { if (Load.C.cmdsize % 4 != 0) { - Err = malformedError("load command " + Twine(I) + " cmdsize not a " - "multiple of 4"); + Err = joinErrors(std::move(Err), + malformedError("load command " + Twine(I) + + " cmdsize not a multiple of 4")); return; } } LoadCommands.push_back(Load); if (Load.C.cmd == MachO::LC_SYMTAB) { - if ((Err = checkSymtabCommand(this, Load, I, &SymtabLoadCmd, Elements))) - return; + Err = joinErrors( + std::move(Err), + checkSymtabCommand(this, Load, I, &SymtabLoadCmd, Elements)); } else if (Load.C.cmd == MachO::LC_DYSYMTAB) { - if ((Err = checkDysymtabCommand(this, Load, I, &DysymtabLoadCmd, - Elements))) - return; + Err = joinErrors( + std::move(Err), + checkDysymtabCommand(this, Load, I, &DysymtabLoadCmd, Elements)); } else if (Load.C.cmd == MachO::LC_DATA_IN_CODE) { - if ((Err = checkLinkeditDataCommand(this, Load, I, &DataInCodeLoadCmd, - "LC_DATA_IN_CODE", Elements, - "data in code info"))) - return; + Err = joinErrors(std::move(Err), + checkLinkeditDataCommand( + this, Load, I, &DataInCodeLoadCmd, "LC_DATA_IN_CODE", + Elements, "data in code info")); } else if (Load.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT) { - if ((Err = checkLinkeditDataCommand(this, Load, I, &LinkOptHintsLoadCmd, - "LC_LINKER_OPTIMIZATION_HINT", - Elements, "linker optimization " - "hints"))) - return; + Err = joinErrors( + std::move(Err), + checkLinkeditDataCommand(this, Load, I, &LinkOptHintsLoadCmd, + "LC_LINKER_OPTIMIZATION_HINT", Elements, + "linker optimization hints")); } else if (Load.C.cmd == MachO::LC_FUNCTION_STARTS) { - if ((Err = checkLinkeditDataCommand(this, Load, I, &FuncStartsLoadCmd, - "LC_FUNCTION_STARTS", Elements, - "function starts data"))) - return; + Err = + joinErrors(std::move(Err), + checkLinkeditDataCommand(this, Load, I, &FuncStartsLoadCmd, + "LC_FUNCTION_STARTS", Elements, + "function starts data")); } else if (Load.C.cmd == MachO::LC_SEGMENT_SPLIT_INFO) { - if ((Err = checkLinkeditDataCommand(this, Load, I, &SplitInfoLoadCmd, - "LC_SEGMENT_SPLIT_INFO", Elements, - "split info data"))) - return; + Err = + joinErrors(std::move(Err), + checkLinkeditDataCommand(this, Load, I, &SplitInfoLoadCmd, + "LC_SEGMENT_SPLIT_INFO", Elements, + "split info data")); } else if (Load.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS) { - if ((Err = checkLinkeditDataCommand(this, Load, I, &CodeSignDrsLoadCmd, - "LC_DYLIB_CODE_SIGN_DRS", Elements, - "code signing RDs data"))) - return; + Err = joinErrors(std::move(Err), checkLinkeditDataCommand( + this, Load, I, &CodeSignDrsLoadCmd, + "LC_DYLIB_CODE_SIGN_DRS", Elements, + "code signing RDs data")); } else if (Load.C.cmd == MachO::LC_CODE_SIGNATURE) { - if ((Err = checkLinkeditDataCommand(this, Load, I, &CodeSignLoadCmd, - "LC_CODE_SIGNATURE", Elements, - "code signature data"))) - return; + Err = joinErrors(std::move(Err), + checkLinkeditDataCommand(this, Load, I, &CodeSignLoadCmd, + "LC_CODE_SIGNATURE", Elements, + "code signature data")); } else if (Load.C.cmd == MachO::LC_DYLD_INFO) { - if ((Err = checkDyldInfoCommand(this, Load, I, &DyldInfoLoadCmd, - "LC_DYLD_INFO", Elements))) - return; + Err = joinErrors(std::move(Err), + checkDyldInfoCommand(this, Load, I, &DyldInfoLoadCmd, + "LC_DYLD_INFO", Elements)); } else if (Load.C.cmd == MachO::LC_DYLD_INFO_ONLY) { - if ((Err = checkDyldInfoCommand(this, Load, I, &DyldInfoLoadCmd, - "LC_DYLD_INFO_ONLY", Elements))) - return; + Err = joinErrors(std::move(Err), + checkDyldInfoCommand(this, Load, I, &DyldInfoLoadCmd, + "LC_DYLD_INFO_ONLY", Elements)); } else if (Load.C.cmd == MachO::LC_UUID) { - if (Load.C.cmdsize != sizeof(MachO::uuid_command)) { - Err = malformedError("LC_UUID command " + Twine(I) + " has incorrect " - "cmdsize"); - return; - } - if (UuidLoadCmd) { - Err = malformedError("more than one LC_UUID command"); - return; - } - UuidLoadCmd = Load.Ptr; + if (Load.C.cmdsize != sizeof(MachO::uuid_command)) + Err = joinErrors(std::move(Err), + malformedError("LC_UUID command " + Twine(I) + + " has incorrect cmdsize")); + else if (UuidLoadCmd) + Err = joinErrors(std::move(Err), + malformedError("more than one LC_UUID command")); + else + UuidLoadCmd = Load.Ptr; } else if (Load.C.cmd == MachO::LC_SEGMENT_64) { - if ((Err = parseSegmentLoadCommand( - this, Load, Sections, HasPageZeroSegment, I, - "LC_SEGMENT_64", SizeOfHeaders, Elements))) - return; + Err = joinErrors( + std::move(Err), + parseSegmentLoadCommand( + this, Load, Sections, HasPageZeroSegment, I, "LC_SEGMENT_64", + SizeOfHeaders, Elements)); } else if (Load.C.cmd == MachO::LC_SEGMENT) { - if ((Err = parseSegmentLoadCommand( - this, Load, Sections, HasPageZeroSegment, I, - "LC_SEGMENT", SizeOfHeaders, Elements))) - return; + Err = joinErrors( + std::move(Err), + parseSegmentLoadCommand( + this, Load, Sections, HasPageZeroSegment, I, "LC_SEGMENT", + SizeOfHeaders, Elements)); } else if (Load.C.cmd == MachO::LC_ID_DYLIB) { - if ((Err = checkDylibIdCommand(this, Load, I, &DyldIdLoadCmd))) - return; + Err = joinErrors(std::move(Err), + checkDylibIdCommand(this, Load, I, &DyldIdLoadCmd)); } else if (Load.C.cmd == MachO::LC_LOAD_DYLIB) { - if ((Err = checkDylibCommand(this, Load, I, "LC_LOAD_DYLIB"))) - return; - Libraries.push_back(Load.Ptr); + Err = joinErrors(std::move(Err), + checkDylibCommand(this, Load, I, "LC_LOAD_DYLIB")); + // todo: can I make this unchecked again? + if (!Err) + Libraries.push_back(Load.Ptr); } else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB) { - if ((Err = checkDylibCommand(this, Load, I, "LC_LOAD_WEAK_DYLIB"))) - return; - Libraries.push_back(Load.Ptr); + Err = joinErrors(std::move(Err), + checkDylibCommand(this, Load, I, "LC_LOAD_WEAK_DYLIB")); + // todo: can I make this unchecked again? + if (!Err) + Libraries.push_back(Load.Ptr); } else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB) { - if ((Err = checkDylibCommand(this, Load, I, "LC_LAZY_LOAD_DYLIB"))) - return; - Libraries.push_back(Load.Ptr); + Err = joinErrors(std::move(Err), + checkDylibCommand(this, Load, I, "LC_LAZY_LOAD_DYLIB")); + // todo: can I make this unchecked again? + if (!Err) + Libraries.push_back(Load.Ptr); } else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB) { - if ((Err = checkDylibCommand(this, Load, I, "LC_REEXPORT_DYLIB"))) - return; - Libraries.push_back(Load.Ptr); + Err = joinErrors(std::move(Err), + checkDylibCommand(this, Load, I, "LC_REEXPORT_DYLIB")); + // todo: can I make this unchecked again? + if (!Err) + Libraries.push_back(Load.Ptr); } else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) { - if ((Err = checkDylibCommand(this, Load, I, "LC_LOAD_UPWARD_DYLIB"))) - return; - Libraries.push_back(Load.Ptr); + Err = + joinErrors(std::move(Err), + checkDylibCommand(this, Load, I, "LC_LOAD_UPWARD_DYLIB")); + // todo: can I make this unchecked again? + if (!Err) + Libraries.push_back(Load.Ptr); } else if (Load.C.cmd == MachO::LC_ID_DYLINKER) { - if ((Err = checkDyldCommand(this, Load, I, "LC_ID_DYLINKER"))) - return; + Err = joinErrors(std::move(Err), + checkDyldCommand(this, Load, I, "LC_ID_DYLINKER")); } else if (Load.C.cmd == MachO::LC_LOAD_DYLINKER) { - if ((Err = checkDyldCommand(this, Load, I, "LC_LOAD_DYLINKER"))) - return; + Err = joinErrors(std::move(Err), + checkDyldCommand(this, Load, I, "LC_LOAD_DYLINKER")); } else if (Load.C.cmd == MachO::LC_DYLD_ENVIRONMENT) { - if ((Err = checkDyldCommand(this, Load, I, "LC_DYLD_ENVIRONMENT"))) - return; + Err = joinErrors(std::move(Err), + checkDyldCommand(this, Load, I, "LC_DYLD_ENVIRONMENT")); } else if (Load.C.cmd == MachO::LC_VERSION_MIN_MACOSX) { - if ((Err = checkVersCommand(this, Load, I, &VersLoadCmd, - "LC_VERSION_MIN_MACOSX"))) - return; + Err = joinErrors(std::move(Err), + checkVersCommand(this, Load, I, &VersLoadCmd, + "LC_VERSION_MIN_MACOSX")); } else if (Load.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS) { - if ((Err = checkVersCommand(this, Load, I, &VersLoadCmd, - "LC_VERSION_MIN_IPHONEOS"))) - return; + Err = joinErrors(std::move(Err), + checkVersCommand(this, Load, I, &VersLoadCmd, + "LC_VERSION_MIN_IPHONEOS")); } else if (Load.C.cmd == MachO::LC_VERSION_MIN_TVOS) { - if ((Err = checkVersCommand(this, Load, I, &VersLoadCmd, - "LC_VERSION_MIN_TVOS"))) - return; + Err = joinErrors( + std::move(Err), + checkVersCommand(this, Load, I, &VersLoadCmd, "LC_VERSION_MIN_TVOS")); } else if (Load.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) { - if ((Err = checkVersCommand(this, Load, I, &VersLoadCmd, - "LC_VERSION_MIN_WATCHOS"))) - return; + Err = joinErrors(std::move(Err), + checkVersCommand(this, Load, I, &VersLoadCmd, + "LC_VERSION_MIN_WATCHOS")); } else if (Load.C.cmd == MachO::LC_RPATH) { - if ((Err = checkRpathCommand(this, Load, I))) - return; + Err = joinErrors(std::move(Err), checkRpathCommand(this, Load, I)); } else if (Load.C.cmd == MachO::LC_SOURCE_VERSION) { - if (Load.C.cmdsize != sizeof(MachO::source_version_command)) { - Err = malformedError("LC_SOURCE_VERSION command " + Twine(I) + - " has incorrect cmdsize"); - return; - } - if (SourceLoadCmd) { - Err = malformedError("more than one LC_SOURCE_VERSION command"); - return; - } - SourceLoadCmd = Load.Ptr; + if (Load.C.cmdsize != sizeof(MachO::source_version_command)) + Err = joinErrors(std::move(Err), + malformedError("LC_SOURCE_VERSION command " + + Twine(I) + " has incorrect cmdsize")); + else if (SourceLoadCmd) + Err = joinErrors( + std::move(Err), + malformedError("more than one LC_SOURCE_VERSION command")); + else + SourceLoadCmd = Load.Ptr; } else if (Load.C.cmd == MachO::LC_MAIN) { - if (Load.C.cmdsize != sizeof(MachO::entry_point_command)) { - Err = malformedError("LC_MAIN command " + Twine(I) + - " has incorrect cmdsize"); - return; - } - if (EntryPointLoadCmd) { - Err = malformedError("more than one LC_MAIN command"); - return; - } - EntryPointLoadCmd = Load.Ptr; + if (Load.C.cmdsize != sizeof(MachO::entry_point_command)) + Err = joinErrors(std::move(Err), + malformedError("LC_MAIN command " + Twine(I) + + " has incorrect cmdsize")); + else if (EntryPointLoadCmd) + Err = joinErrors(std::move(Err), + malformedError("more than one LC_MAIN command")); + else + EntryPointLoadCmd = Load.Ptr; } else if (Load.C.cmd == MachO::LC_ENCRYPTION_INFO) { - if (Load.C.cmdsize != sizeof(MachO::encryption_info_command)) { - Err = malformedError("LC_ENCRYPTION_INFO command " + Twine(I) + - " has incorrect cmdsize"); - return; + if (Load.C.cmdsize != sizeof(MachO::encryption_info_command)) + Err = joinErrors(std::move(Err), + malformedError("LC_ENCRYPTION_INFO command " + + Twine(I) + " has incorrect cmdsize")); + else { + MachO::encryption_info_command E = + getStruct(this, Load.Ptr); + Err = joinErrors(std::move(Err), + checkEncryptCommand(this, Load, I, E.cryptoff, + E.cryptsize, &EncryptLoadCmd, + "LC_ENCRYPTION_INFO")); } - MachO::encryption_info_command E = - getStruct(this, Load.Ptr); - if ((Err = checkEncryptCommand(this, Load, I, E.cryptoff, E.cryptsize, - &EncryptLoadCmd, "LC_ENCRYPTION_INFO"))) - return; } else if (Load.C.cmd == MachO::LC_ENCRYPTION_INFO_64) { - if (Load.C.cmdsize != sizeof(MachO::encryption_info_command_64)) { - Err = malformedError("LC_ENCRYPTION_INFO_64 command " + Twine(I) + - " has incorrect cmdsize"); - return; + if (Load.C.cmdsize != sizeof(MachO::encryption_info_command_64)) + Err = joinErrors(std::move(Err), + malformedError("LC_ENCRYPTION_INFO_64 command " + + Twine(I) + " has incorrect cmdsize")); + else { + MachO::encryption_info_command_64 E = + getStruct(this, Load.Ptr); + Err = joinErrors(std::move(Err), + checkEncryptCommand(this, Load, I, E.cryptoff, + E.cryptsize, &EncryptLoadCmd, + "LC_ENCRYPTION_INFO_64")); } - MachO::encryption_info_command_64 E = - getStruct(this, Load.Ptr); - if ((Err = checkEncryptCommand(this, Load, I, E.cryptoff, E.cryptsize, - &EncryptLoadCmd, "LC_ENCRYPTION_INFO_64"))) - return; } else if (Load.C.cmd == MachO::LC_LINKER_OPTION) { - if ((Err = checkLinkerOptCommand(this, Load, I))) - return; + Err = joinErrors(std::move(Err), checkLinkerOptCommand(this, Load, I)); } else if (Load.C.cmd == MachO::LC_SUB_FRAMEWORK) { - if (Load.C.cmdsize < sizeof(MachO::sub_framework_command)) { - Err = malformedError("load command " + Twine(I) + - " LC_SUB_FRAMEWORK cmdsize too small"); - return; + if (Load.C.cmdsize < sizeof(MachO::sub_framework_command)) + Err = joinErrors(std::move(Err), + malformedError("load command " + Twine(I) + + " LC_SUB_FRAMEWORK cmdsize too small")); + else { + MachO::sub_framework_command S = + getStruct(this, Load.Ptr); + Err = joinErrors(std::move(Err), + checkSubCommand(this, Load, I, "LC_SUB_FRAMEWORK", + sizeof(MachO::sub_framework_command), + "sub_framework_command", S.umbrella, + "umbrella")); } - MachO::sub_framework_command S = - getStruct(this, Load.Ptr); - if ((Err = checkSubCommand(this, Load, I, "LC_SUB_FRAMEWORK", - sizeof(MachO::sub_framework_command), - "sub_framework_command", S.umbrella, - "umbrella"))) - return; } else if (Load.C.cmd == MachO::LC_SUB_UMBRELLA) { - if (Load.C.cmdsize < sizeof(MachO::sub_umbrella_command)) { - Err = malformedError("load command " + Twine(I) + - " LC_SUB_UMBRELLA cmdsize too small"); - return; + if (Load.C.cmdsize < sizeof(MachO::sub_umbrella_command)) + Err = joinErrors(std::move(Err), + malformedError("load command " + Twine(I) + + " LC_SUB_UMBRELLA cmdsize too small")); + else { + MachO::sub_umbrella_command S = + getStruct(this, Load.Ptr); + Err = joinErrors(std::move(Err), + checkSubCommand(this, Load, I, "LC_SUB_UMBRELLA", + sizeof(MachO::sub_umbrella_command), + "sub_umbrella_command", S.sub_umbrella, + "sub_umbrella")); } - MachO::sub_umbrella_command S = - getStruct(this, Load.Ptr); - if ((Err = checkSubCommand(this, Load, I, "LC_SUB_UMBRELLA", - sizeof(MachO::sub_umbrella_command), - "sub_umbrella_command", S.sub_umbrella, - "sub_umbrella"))) - return; } else if (Load.C.cmd == MachO::LC_SUB_LIBRARY) { if (Load.C.cmdsize < sizeof(MachO::sub_library_command)) { - Err = malformedError("load command " + Twine(I) + - " LC_SUB_LIBRARY cmdsize too small"); - return; + Err = joinErrors(std::move(Err), + malformedError("load command " + Twine(I) + + " LC_SUB_LIBRARY cmdsize too small")); + } else { + MachO::sub_library_command S = + getStruct(this, Load.Ptr); + Err = joinErrors(std::move(Err), + checkSubCommand(this, Load, I, "LC_SUB_LIBRARY", + sizeof(MachO::sub_library_command), + "sub_library_command", S.sub_library, + "sub_library")); } - MachO::sub_library_command S = - getStruct(this, Load.Ptr); - if ((Err = checkSubCommand(this, Load, I, "LC_SUB_LIBRARY", - sizeof(MachO::sub_library_command), - "sub_library_command", S.sub_library, - "sub_library"))) - return; } else if (Load.C.cmd == MachO::LC_SUB_CLIENT) { - if (Load.C.cmdsize < sizeof(MachO::sub_client_command)) { - Err = malformedError("load command " + Twine(I) + - " LC_SUB_CLIENT cmdsize too small"); - return; + if (Load.C.cmdsize < sizeof(MachO::sub_client_command)) + Err = joinErrors(std::move(Err), + malformedError("load command " + Twine(I) + + " LC_SUB_CLIENT cmdsize too small")); + else { + MachO::sub_client_command S = + getStruct(this, Load.Ptr); + Err = joinErrors(std::move(Err), + checkSubCommand(this, Load, I, "LC_SUB_CLIENT", + sizeof(MachO::sub_client_command), + "sub_client_command", S.client, + "client")); } - MachO::sub_client_command S = - getStruct(this, Load.Ptr); - if ((Err = checkSubCommand(this, Load, I, "LC_SUB_CLIENT", - sizeof(MachO::sub_client_command), - "sub_client_command", S.client, "client"))) - return; } else if (Load.C.cmd == MachO::LC_ROUTINES) { - if (Load.C.cmdsize != sizeof(MachO::routines_command)) { - Err = malformedError("LC_ROUTINES command " + Twine(I) + - " has incorrect cmdsize"); - return; - } - if (RoutinesLoadCmd) { - Err = malformedError("more than one LC_ROUTINES and or LC_ROUTINES_64 " - "command"); - return; - } - RoutinesLoadCmd = Load.Ptr; + if (Load.C.cmdsize != sizeof(MachO::routines_command)) + Err = joinErrors(std::move(Err), + malformedError("LC_ROUTINES command " + Twine(I) + + " has incorrect cmdsize")); + else if (RoutinesLoadCmd) + Err = joinErrors( + std::move(Err), + malformedError("more than one LC_ROUTINES and or LC_ROUTINES_64 " + "command")); + else + RoutinesLoadCmd = Load.Ptr; } else if (Load.C.cmd == MachO::LC_ROUTINES_64) { - if (Load.C.cmdsize != sizeof(MachO::routines_command_64)) { - Err = malformedError("LC_ROUTINES_64 command " + Twine(I) + - " has incorrect cmdsize"); - return; - } - if (RoutinesLoadCmd) { - Err = malformedError("more than one LC_ROUTINES_64 and or LC_ROUTINES " - "command"); - return; - } - RoutinesLoadCmd = Load.Ptr; + if (Load.C.cmdsize != sizeof(MachO::routines_command_64)) + Err = joinErrors(std::move(Err), + malformedError("LC_ROUTINES_64 command " + Twine(I) + + " has incorrect cmdsize")); + else if (RoutinesLoadCmd) + Err = joinErrors( + std::move(Err), + malformedError("more than one LC_ROUTINES_64 and or LC_ROUTINES " + "command")); + else + RoutinesLoadCmd = Load.Ptr; } else if (Load.C.cmd == MachO::LC_UNIXTHREAD) { - if ((Err = checkThreadCommand(this, Load, I, "LC_UNIXTHREAD"))) - return; + Err = joinErrors(std::move(Err), + checkThreadCommand(this, Load, I, "LC_UNIXTHREAD")); if (UnixThreadLoadCmd) { - Err = malformedError("more than one LC_UNIXTHREAD command"); - return; + Err = joinErrors(std::move(Err), + malformedError("more than one LC_UNIXTHREAD command")); } - UnixThreadLoadCmd = Load.Ptr; + if (!Err) + UnixThreadLoadCmd = Load.Ptr; } else if (Load.C.cmd == MachO::LC_THREAD) { - if ((Err = checkThreadCommand(this, Load, I, "LC_THREAD"))) - return; - // Note: LC_TWOLEVEL_HINTS is really obsolete and is not supported. + Err = joinErrors(std::move(Err), + checkThreadCommand(this, Load, I, "LC_THREAD")); + // Note: LC_TWOLEVEL_HINTS is really obsolete and is not supported. } else if (Load.C.cmd == MachO::LC_TWOLEVEL_HINTS) { - if ((Err = checkTwoLevelHintsCommand(this, Load, I, - &TwoLevelHintsLoadCmd, Elements))) - return; + Err = joinErrors(std::move(Err), + checkTwoLevelHintsCommand( + this, Load, I, &TwoLevelHintsLoadCmd, Elements)); } else if (isLoadCommandObsolete(Load.C.cmd)) { - Err = malformedError("load command " + Twine(I) + " for cmd value of: " + - Twine(Load.C.cmd) + " is obsolete and not " - "supported"); - return; + Err = joinErrors( + std::move(Err), + malformedError("load command " + Twine(I) + " for cmd value of: " + + Twine(Load.C.cmd) + " is obsolete and not " + "supported")); + } else { + Err = joinErrors(std::move(Err), unknownValueError("unknown load command " + + Twine(I) + " for cmd value of: " + Twine(Load.C.cmd))); } - // 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; else { - Err = LoadOrErr.takeError(); + Err = joinErrors(std::move(Err), LoadOrErr.takeError()); return; } } + if (Err && !IgnoreValueErrs) + return; } + if (Err) + return; if (!SymtabLoadCmd) { if (DysymtabLoadCmd) { Err = malformedError("contains LC_DYSYMTAB load command without a " @@ -1497,8 +1535,6 @@ return; } assert(LoadCommands.size() == LoadCommandCount); - - Err = Error::success(); } Error MachOObjectFile::checkSymbolTable() const { @@ -3537,23 +3573,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());