diff options
Diffstat (limited to 'lib/Object/MachOObjectFile.cpp')
-rw-r--r-- | lib/Object/MachOObjectFile.cpp | 445 |
1 files changed, 234 insertions, 211 deletions
diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index ce4d1cf92e20..5aec844003c0 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -1,9 +1,8 @@ //===- MachOObjectFile.cpp - Mach-O object file binding -------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -58,6 +57,12 @@ namespace { } // end anonymous namespace +static const std::array<StringRef, 17> validArchs = { + "i386", "x86_64", "x86_64h", "armv4t", "arm", "armv5e", + "armv6", "armv6m", "armv7", "armv7em", "armv7k", "armv7m", + "armv7s", "arm64", "arm64_32", "ppc", "ppc64", +}; + static Error malformedError(const Twine &Msg) { return make_error<GenericBinaryError>("truncated or malformed object (" + Msg + ")", @@ -292,7 +297,10 @@ static Error parseSegmentLoadCommand( for (unsigned J = 0; J < S.nsects; ++J) { const char *Sec = getSectionPtr(Obj, Load, J); Sections.push_back(Sec); - Section s = getStruct<Section>(Obj, Sec); + auto SectionOrErr = getStructOrErr<Section>(Obj, Sec); + if (!SectionOrErr) + return SectionOrErr.takeError(); + Section s = SectionOrErr.get(); if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB && Obj.getHeader().filetype != MachO::MH_DSYM && s.flags != MachO::S_ZEROFILL && @@ -402,8 +410,10 @@ static Error checkSymtabCommand(const MachOObjectFile &Obj, " LC_SYMTAB cmdsize too small"); if (*SymtabLoadCmd != nullptr) return malformedError("more than one LC_SYMTAB command"); - MachO::symtab_command Symtab = - getStruct<MachO::symtab_command>(Obj, Load.Ptr); + auto SymtabOrErr = getStructOrErr<MachO::symtab_command>(Obj, Load.Ptr); + if (!SymtabOrErr) + return SymtabOrErr.takeError(); + MachO::symtab_command Symtab = SymtabOrErr.get(); if (Symtab.cmdsize != sizeof(MachO::symtab_command)) return malformedError("LC_SYMTAB command " + Twine(LoadCommandIndex) + " has incorrect cmdsize"); @@ -458,8 +468,11 @@ static Error checkDysymtabCommand(const MachOObjectFile &Obj, " LC_DYSYMTAB cmdsize too small"); if (*DysymtabLoadCmd != nullptr) return malformedError("more than one LC_DYSYMTAB command"); - MachO::dysymtab_command Dysymtab = - getStruct<MachO::dysymtab_command>(Obj, Load.Ptr); + auto DysymtabOrErr = + getStructOrErr<MachO::dysymtab_command>(Obj, Load.Ptr); + if (!DysymtabOrErr) + return DysymtabOrErr.takeError(); + MachO::dysymtab_command Dysymtab = DysymtabOrErr.get(); if (Dysymtab.cmdsize != sizeof(MachO::dysymtab_command)) return malformedError("LC_DYSYMTAB command " + Twine(LoadCommandIndex) + " has incorrect cmdsize"); @@ -589,8 +602,11 @@ static Error checkLinkeditDataCommand(const MachOObjectFile &Obj, CmdName + " cmdsize too small"); if (*LoadCmd != nullptr) return malformedError("more than one " + Twine(CmdName) + " command"); - MachO::linkedit_data_command LinkData = - getStruct<MachO::linkedit_data_command>(Obj, Load.Ptr); + auto LinkDataOrError = + getStructOrErr<MachO::linkedit_data_command>(Obj, Load.Ptr); + if (!LinkDataOrError) + return LinkDataOrError.takeError(); + MachO::linkedit_data_command LinkData = LinkDataOrError.get(); if (LinkData.cmdsize != sizeof(MachO::linkedit_data_command)) return malformedError(Twine(CmdName) + " command " + Twine(LoadCommandIndex) + " has incorrect cmdsize"); @@ -624,8 +640,11 @@ static Error checkDyldInfoCommand(const MachOObjectFile &Obj, if (*LoadCmd != nullptr) return malformedError("more than one LC_DYLD_INFO and or LC_DYLD_INFO_ONLY " "command"); - MachO::dyld_info_command DyldInfo = - getStruct<MachO::dyld_info_command>(Obj, Load.Ptr); + auto DyldInfoOrErr = + getStructOrErr<MachO::dyld_info_command>(Obj, Load.Ptr); + if (!DyldInfoOrErr) + return DyldInfoOrErr.takeError(); + MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); if (DyldInfo.cmdsize != sizeof(MachO::dyld_info_command)) return malformedError(Twine(CmdName) + " command " + Twine(LoadCommandIndex) + " has incorrect cmdsize"); @@ -715,7 +734,10 @@ static Error checkDylibCommand(const MachOObjectFile &Obj, if (Load.C.cmdsize < sizeof(MachO::dylib_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " " + CmdName + " cmdsize too small"); - MachO::dylib_command D = getStruct<MachO::dylib_command>(Obj, Load.Ptr); + auto CommandOrErr = getStructOrErr<MachO::dylib_command>(Obj, Load.Ptr); + if (!CommandOrErr) + return CommandOrErr.takeError(); + MachO::dylib_command D = CommandOrErr.get(); if (D.dylib.name < sizeof(MachO::dylib_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " " + CmdName + " name.offset field too small, not past " @@ -761,7 +783,10 @@ static Error checkDyldCommand(const MachOObjectFile &Obj, if (Load.C.cmdsize < sizeof(MachO::dylinker_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " " + CmdName + " cmdsize too small"); - MachO::dylinker_command D = getStruct<MachO::dylinker_command>(Obj, Load.Ptr); + auto CommandOrErr = getStructOrErr<MachO::dylinker_command>(Obj, Load.Ptr); + if (!CommandOrErr) + return CommandOrErr.takeError(); + MachO::dylinker_command D = CommandOrErr.get(); if (D.name < sizeof(MachO::dylinker_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " " + CmdName + " name.offset field too small, not past " @@ -806,7 +831,10 @@ static Error checkNoteCommand(const MachOObjectFile &Obj, if (Load.C.cmdsize != sizeof(MachO::note_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " LC_NOTE has incorrect cmdsize"); - MachO::note_command Nt = getStruct<MachO::note_command>(Obj, Load.Ptr); + auto NoteCmdOrErr = getStructOrErr<MachO::note_command>(Obj, Load.Ptr); + if (!NoteCmdOrErr) + return NoteCmdOrErr.takeError(); + MachO::note_command Nt = NoteCmdOrErr.get(); uint64_t FileSize = Obj.getData().size(); if (Nt.offset > FileSize) return malformedError("offset field of LC_NOTE command " + @@ -829,8 +857,11 @@ parseBuildVersionCommand(const MachOObjectFile &Obj, const MachOObjectFile::LoadCommandInfo &Load, SmallVectorImpl<const char*> &BuildTools, uint32_t LoadCommandIndex) { - MachO::build_version_command BVC = - getStruct<MachO::build_version_command>(Obj, Load.Ptr); + auto BVCOrErr = + getStructOrErr<MachO::build_version_command>(Obj, Load.Ptr); + if (!BVCOrErr) + return BVCOrErr.takeError(); + MachO::build_version_command BVC = BVCOrErr.get(); if (Load.C.cmdsize != sizeof(MachO::build_version_command) + BVC.ntools * sizeof(MachO::build_tool_version)) @@ -851,7 +882,10 @@ static Error checkRpathCommand(const MachOObjectFile &Obj, if (Load.C.cmdsize < sizeof(MachO::rpath_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " LC_RPATH cmdsize too small"); - MachO::rpath_command R = getStruct<MachO::rpath_command>(Obj, Load.Ptr); + auto ROrErr = getStructOrErr<MachO::rpath_command>(Obj, Load.Ptr); + if (!ROrErr) + return ROrErr.takeError(); + MachO::rpath_command R = ROrErr.get(); if (R.path < sizeof(MachO::rpath_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " LC_RPATH path.offset field too small, not past " @@ -904,8 +938,11 @@ static Error checkLinkerOptCommand(const MachOObjectFile &Obj, if (Load.C.cmdsize < sizeof(MachO::linker_option_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " LC_LINKER_OPTION cmdsize too small"); - MachO::linker_option_command L = - getStruct<MachO::linker_option_command>(Obj, Load.Ptr); + auto LinkOptionOrErr = + getStructOrErr<MachO::linker_option_command>(Obj, Load.Ptr); + if (!LinkOptionOrErr) + return LinkOptionOrErr.takeError(); + MachO::linker_option_command L = LinkOptionOrErr.get(); // Make sure the count of strings is correct. const char *string = (const char *)Load.Ptr + sizeof(struct MachO::linker_option_command); @@ -919,6 +956,10 @@ static Error checkLinkerOptCommand(const MachOObjectFile &Obj, if (left > 0) { i++; uint32_t NullPos = StringRef(string, left).find('\0'); + if (0xffffffff == NullPos) + return malformedError("load command " + Twine(LoadCommandIndex) + + " LC_LINKER_OPTION string #" + Twine(i) + + " is not NULL terminated"); uint32_t len = std::min(NullPos, left) + 1; string += len; left -= len; @@ -965,8 +1006,11 @@ static Error checkThreadCommand(const MachOObjectFile &Obj, if (Load.C.cmdsize < sizeof(MachO::thread_command)) return malformedError("load command " + Twine(LoadCommandIndex) + CmdName + " cmdsize too small"); - MachO::thread_command T = - getStruct<MachO::thread_command>(Obj, Load.Ptr); + auto ThreadCommandOrErr = + getStructOrErr<MachO::thread_command>(Obj, Load.Ptr); + if (!ThreadCommandOrErr) + return ThreadCommandOrErr.takeError(); + MachO::thread_command T = ThreadCommandOrErr.get(); const char *state = Load.Ptr + sizeof(MachO::thread_command); const char *end = Load.Ptr + T.cmdsize; uint32_t nflavor = 0; @@ -1097,7 +1141,8 @@ static Error checkThreadCommand(const MachOObjectFile &Obj, "flavor number " + Twine(nflavor) + " in " + CmdName + " command"); } - } else if (cputype == MachO::CPU_TYPE_ARM64) { + } else if (cputype == MachO::CPU_TYPE_ARM64 || + cputype == MachO::CPU_TYPE_ARM64_32) { if (flavor == MachO::ARM_THREAD_STATE64) { if (count != MachO::ARM_THREAD_STATE64_COUNT) return malformedError("load command " + Twine(LoadCommandIndex) + @@ -1156,8 +1201,10 @@ static Error checkTwoLevelHintsCommand(const MachOObjectFile &Obj, " LC_TWOLEVEL_HINTS has incorrect cmdsize"); if (*LoadCmd != nullptr) return malformedError("more than one LC_TWOLEVEL_HINTS command"); - MachO::twolevel_hints_command Hints = - getStruct<MachO::twolevel_hints_command>(Obj, Load.Ptr); + auto HintsOrErr = getStructOrErr<MachO::twolevel_hints_command>(Obj, Load.Ptr); + if(!HintsOrErr) + return HintsOrErr.takeError(); + MachO::twolevel_hints_command Hints = HintsOrErr.get(); uint64_t FileSize = Obj.getData().size(); if (Hints.offset > FileSize) return malformedError("offset field of LC_TWOLEVEL_HINTS command " + @@ -1658,36 +1705,35 @@ Error MachOObjectFile::checkSymbolTable() const { } else { MachO::nlist STE = getSymbolTableEntry(SymDRI); NType = STE.n_type; - NType = STE.n_type; NSect = STE.n_sect; NDesc = STE.n_desc; NStrx = STE.n_strx; NValue = STE.n_value; } - if ((NType & MachO::N_STAB) == 0 && - (NType & MachO::N_TYPE) == MachO::N_SECT) { - if (NSect == 0 || NSect > Sections.size()) - return malformedError("bad section index: " + Twine((int)NSect) + - " for symbol at index " + Twine(SymbolIndex)); - } - if ((NType & MachO::N_STAB) == 0 && - (NType & MachO::N_TYPE) == MachO::N_INDR) { - if (NValue >= S.strsize) - return malformedError("bad n_value: " + Twine((int)NValue) + " past " - "the end of string table, for N_INDR symbol at " - "index " + Twine(SymbolIndex)); - } - if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL && - (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) || - (NType & MachO::N_TYPE) == MachO::N_PBUD)) { - uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc); - if (LibraryOrdinal != 0 && - LibraryOrdinal != MachO::EXECUTABLE_ORDINAL && - LibraryOrdinal != MachO::DYNAMIC_LOOKUP_ORDINAL && - LibraryOrdinal - 1 >= Libraries.size() ) { - return malformedError("bad library ordinal: " + Twine(LibraryOrdinal) + - " for symbol at index " + Twine(SymbolIndex)); + if ((NType & MachO::N_STAB) == 0) { + if ((NType & MachO::N_TYPE) == MachO::N_SECT) { + if (NSect == 0 || NSect > Sections.size()) + return malformedError("bad section index: " + Twine((int)NSect) + + " for symbol at index " + Twine(SymbolIndex)); + } + if ((NType & MachO::N_TYPE) == MachO::N_INDR) { + if (NValue >= S.strsize) + return malformedError("bad n_value: " + Twine((int)NValue) + " past " + "the end of string table, for N_INDR symbol at " + "index " + Twine(SymbolIndex)); } + if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL && + (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) || + (NType & MachO::N_TYPE) == MachO::N_PBUD)) { + uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc); + if (LibraryOrdinal != 0 && + LibraryOrdinal != MachO::EXECUTABLE_ORDINAL && + LibraryOrdinal != MachO::DYNAMIC_LOOKUP_ORDINAL && + LibraryOrdinal - 1 >= Libraries.size() ) { + return malformedError("bad library ordinal: " + Twine(LibraryOrdinal) + + " for symbol at index " + Twine(SymbolIndex)); + } + } } if (NStrx >= S.strsize) return malformedError("bad string table index: " + Twine((int)NStrx) + @@ -1861,11 +1907,9 @@ void MachOObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; } -std::error_code MachOObjectFile::getSectionName(DataRefImpl Sec, - StringRef &Result) const { +Expected<StringRef> MachOObjectFile::getSectionName(DataRefImpl Sec) const { ArrayRef<char> Raw = getSectionRawName(Sec); - Result = parseSegmentOrSectionName(Raw.data()); - return std::error_code(); + return parseSegmentOrSectionName(Raw.data()); } uint64_t MachOObjectFile::getSectionAddress(DataRefImpl Sec) const { @@ -1907,8 +1951,8 @@ uint64_t MachOObjectFile::getSectionSize(DataRefImpl Sec) const { return SectSize; } -std::error_code MachOObjectFile::getSectionContents(DataRefImpl Sec, - StringRef &Res) const { +Expected<ArrayRef<uint8_t>> +MachOObjectFile::getSectionContents(DataRefImpl Sec) const { uint32_t Offset; uint64_t Size; @@ -1922,8 +1966,7 @@ std::error_code MachOObjectFile::getSectionContents(DataRefImpl Sec, Size = Sect.size; } - Res = this->getData().substr(Offset, Size); - return std::error_code(); + return arrayRefFromStringRef(getData().substr(Offset, Size)); } uint64_t MachOObjectFile::getSectionAlignment(DataRefImpl Sec) const { @@ -1998,9 +2041,8 @@ bool MachOObjectFile::isSectionVirtual(DataRefImpl Sec) const { bool MachOObjectFile::isSectionBitcode(DataRefImpl Sec) const { StringRef SegmentName = getSectionFinalSegmentName(Sec); - StringRef SectName; - if (!getSectionName(Sec, SectName)) - return (SegmentName == "__LLVM" && SectName == "__bitcode"); + if (Expected<StringRef> NameOrErr = getSectionName(Sec)) + return (SegmentName == "__LLVM" && *NameOrErr == "__bitcode"); return false; } @@ -2172,7 +2214,8 @@ void MachOObjectFile::getRelocationTypeName( res = Table[RType]; break; } - case Triple::aarch64: { + case Triple::aarch64: + case Triple::aarch64_32: { static const char *const Table[] = { "ARM64_RELOC_UNSIGNED", "ARM64_RELOC_SUBTRACTOR", "ARM64_RELOC_BRANCH26", "ARM64_RELOC_PAGE21", @@ -2242,9 +2285,18 @@ uint8_t MachOObjectFile::getRelocationLength(DataRefImpl Rel) const { // one of the two following forms: // libFoo.A.dylib // libFoo.dylib +// // The library may have a suffix trailing the name Foo of the form: // libFoo_profile.A.dylib // libFoo_profile.dylib +// These dyld image suffixes are separated from the short name by a '_' +// character. Because the '_' character is commonly used to separate words in +// filenames guessLibraryShortName() cannot reliably separate a dylib's short +// name from an arbitrary image suffix; imagine if both the short name and the +// suffix contains an '_' character! To better deal with this ambiguity, +// guessLibraryShortName() will recognize only "_debug" and "_profile" as valid +// Suffix values. Calling code needs to be tolerant of guessLibraryShortName() +// guessing incorrectly. // // The Name of the dynamic library is also recognized as a library name if it // has the following form: @@ -2252,7 +2304,6 @@ uint8_t MachOObjectFile::getRelocationLength(DataRefImpl Rel) const { // // If the Name of the dynamic library is none of the forms above then a NULL // StringRef is returned. -// StringRef MachOObjectFile::guessLibraryShortName(StringRef Name, bool &isFramework, StringRef &Suffix) { @@ -2272,7 +2323,10 @@ StringRef MachOObjectFile::guessLibraryShortName(StringRef Name, Idx = Foo.rfind('_'); if (Idx != Foo.npos && Foo.size() >= 2) { Suffix = Foo.slice(Idx, Foo.npos); - Foo = Foo.slice(0, Idx); + if (Suffix != "_debug" && Suffix != "_profile") + Suffix = StringRef(); + else + Foo = Foo.slice(0, Idx); } // First look for the form Foo.framework/Foo @@ -2333,10 +2387,14 @@ guess_library: else b = b+1; // ignore any suffix after an underbar like Foo_profile.A.dylib - Idx = Name.find('_', b); + Idx = Name.rfind('_'); if (Idx != Name.npos && Idx != b) { Lib = Name.slice(b, Idx); Suffix = Name.slice(Idx, a); + if (Suffix != "_debug" && Suffix != "_profile") { + Suffix = StringRef(); + Lib = Name.slice(b, a); + } } else Lib = Name.slice(b, a); @@ -2381,8 +2439,11 @@ std::error_code MachOObjectFile::getLibraryShortNameByIndex(unsigned Index, // all the Libraries. if (LibrariesShortNames.size() == 0) { for (unsigned i = 0; i < Libraries.size(); i++) { - MachO::dylib_command D = - getStruct<MachO::dylib_command>(*this, Libraries[i]); + auto CommandOrErr = + getStructOrErr<MachO::dylib_command>(*this, Libraries[i]); + if (!CommandOrErr) + return object_error::parse_failed; + MachO::dylib_command D = CommandOrErr.get(); if (D.dylib.name >= D.cmdsize) return object_error::parse_failed; const char *P = (const char *)(Libraries[i]) + D.dylib.name; @@ -2485,6 +2546,8 @@ StringRef MachOObjectFile::getFileFormatName() const { return "Mach-O 32-bit i386"; case MachO::CPU_TYPE_ARM: return "Mach-O arm"; + case MachO::CPU_TYPE_ARM64_32: + return "Mach-O arm64 (ILP32)"; case MachO::CPU_TYPE_POWERPC: return "Mach-O 32-bit ppc"; default: @@ -2514,6 +2577,8 @@ Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType) { return Triple::arm; case MachO::CPU_TYPE_ARM64: return Triple::aarch64; + case MachO::CPU_TYPE_ARM64_32: + return Triple::aarch64_32; case MachO::CPU_TYPE_POWERPC: return Triple::ppc; case MachO::CPU_TYPE_POWERPC64: @@ -2620,6 +2685,17 @@ Triple MachOObjectFile::getArchTriple(uint32_t CPUType, uint32_t CPUSubType, default: return Triple(); } + case MachO::CPU_TYPE_ARM64_32: + switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { + case MachO::CPU_SUBTYPE_ARM64_32_V8: + if (McpuDefault) + *McpuDefault = "cyclone"; + if (ArchFlag) + *ArchFlag = "arm64_32"; + return Triple("arm64_32-apple-darwin"); + default: + return Triple(); + } case MachO::CPU_TYPE_POWERPC: switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { case MachO::CPU_SUBTYPE_POWERPC_ALL: @@ -2648,26 +2724,12 @@ Triple MachOObjectFile::getHostArch() { } bool MachOObjectFile::isValidArch(StringRef ArchFlag) { - return StringSwitch<bool>(ArchFlag) - .Case("i386", true) - .Case("x86_64", true) - .Case("x86_64h", true) - .Case("armv4t", true) - .Case("arm", true) - .Case("armv5e", true) - .Case("armv6", true) - .Case("armv6m", true) - .Case("armv7", true) - .Case("armv7em", true) - .Case("armv7k", true) - .Case("armv7m", true) - .Case("armv7s", true) - .Case("arm64", true) - .Case("ppc", true) - .Case("ppc64", true) - .Default(false); + return std::find(validArchs.cbegin(), validArchs.cend(), ArchFlag) != + validArchs.cend(); } +ArrayRef<StringRef> MachOObjectFile::getValidArchs() { return validArchs; } + Triple::ArchType MachOObjectFile::getArch() const { return getArch(getCPUType(*this)); } @@ -3102,8 +3164,8 @@ void MachORebaseEntry::moveNext() { moveToEnd(); return; } - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - true); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + Twine(error) + " for opcode at: 0x" + @@ -3127,8 +3189,8 @@ void MachORebaseEntry::moveNext() { moveToEnd(); return; } - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - true); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " + Twine(error) + " for opcode at: 0x" + @@ -3142,8 +3204,8 @@ void MachORebaseEntry::moveNext() { SegmentOffset) << "\n"); break; case MachO::REBASE_OPCODE_ADD_ADDR_IMM_SCALED: - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - true); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for REBASE_OPCODE_ADD_ADDR_IMM_SCALED " + Twine(error) + " for opcode at: 0x" + @@ -3152,8 +3214,8 @@ void MachORebaseEntry::moveNext() { return; } SegmentOffset += ImmValue * PointerSize; - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - false); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for REBASE_OPCODE_ADD_ADDR_IMM_SCALED " @@ -3169,15 +3231,6 @@ void MachORebaseEntry::moveNext() { SegmentOffset) << "\n"); break; case MachO::REBASE_OPCODE_DO_REBASE_IMM_TIMES: - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - true); - if (error) { - *E = malformedError("for REBASE_OPCODE_DO_REBASE_IMM_TIMES " + - Twine(error) + " for opcode at: 0x" + - Twine::utohexstr(OpcodeStart - Opcodes.begin())); - moveToEnd(); - return; - } AdvanceAmount = PointerSize; Skip = 0; Count = ImmValue; @@ -3185,8 +3238,8 @@ void MachORebaseEntry::moveNext() { RemainingLoopCount = ImmValue - 1; else RemainingLoopCount = 0; - error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize, - SegmentIndex, SegmentOffset); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize, Count, Skip); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_IMM_TIMES " + Twine(error) + " for opcode at: 0x" + @@ -3203,15 +3256,6 @@ void MachORebaseEntry::moveNext() { << "\n"); return; case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES: - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - true); - if (error) { - *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " + - Twine(error) + " for opcode at: 0x" + - Twine::utohexstr(OpcodeStart - Opcodes.begin())); - moveToEnd(); - return; - } AdvanceAmount = PointerSize; Skip = 0; Count = readULEB128(&error); @@ -3226,8 +3270,8 @@ void MachORebaseEntry::moveNext() { RemainingLoopCount = Count - 1; else RemainingLoopCount = 0; - error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize, - SegmentIndex, SegmentOffset); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize, Count, Skip); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " + Twine(error) + " for opcode at: 0x" + @@ -3244,15 +3288,6 @@ void MachORebaseEntry::moveNext() { << "\n"); return; case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - true); - if (error) { - *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " + - Twine(error) + " for opcode at: 0x" + - Twine::utohexstr(OpcodeStart - Opcodes.begin())); - moveToEnd(); - return; - } Skip = readULEB128(&error); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " + @@ -3264,8 +3299,8 @@ void MachORebaseEntry::moveNext() { AdvanceAmount = Skip + PointerSize; Count = 1; RemainingLoopCount = 0; - error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize, - SegmentIndex, SegmentOffset); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize, Count, Skip); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " + Twine(error) + " for opcode at: 0x" + @@ -3282,16 +3317,6 @@ void MachORebaseEntry::moveNext() { << "\n"); return; case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - true); - if (error) { - *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" - "ULEB " + - Twine(error) + " for opcode at: 0x" + - Twine::utohexstr(OpcodeStart - Opcodes.begin())); - moveToEnd(); - return; - } Count = readULEB128(&error); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" @@ -3316,8 +3341,8 @@ void MachORebaseEntry::moveNext() { } AdvanceAmount = Skip + PointerSize; - error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize, - SegmentIndex, SegmentOffset); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize, Count, Skip); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" "ULEB " + @@ -3624,7 +3649,8 @@ void MachOBindEntry::moveNext() { moveToEnd(); return; } - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + Twine(error) + " for opcode at: 0x" + @@ -3648,7 +3674,8 @@ void MachOBindEntry::moveNext() { moveToEnd(); return; } - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB " + Twine(error) + " for opcode at: 0x" + @@ -3664,7 +3691,8 @@ void MachOBindEntry::moveNext() { case MachO::BIND_OPCODE_DO_BIND: AdvanceAmount = PointerSize; RemainingLoopCount = 0; - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND " + Twine(error) + " for opcode at: 0x" + @@ -3701,7 +3729,8 @@ void MachOBindEntry::moveNext() { moveToEnd(); return; } - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB " + Twine(error) + " for opcode at: 0x" + @@ -3737,8 +3766,8 @@ void MachOBindEntry::moveNext() { // Note, this is not really an error until the next bind but make no sense // for a BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB to not be followed by another // bind operation. - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset + - AdvanceAmount, false); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset + + AdvanceAmount, PointerSize); if (error) { *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB (after adding " "ULEB) " + @@ -3764,7 +3793,8 @@ void MachOBindEntry::moveNext() { moveToEnd(); return; } - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " + Twine(error) + " for opcode at: 0x" + @@ -3792,8 +3822,8 @@ void MachOBindEntry::moveNext() { } AdvanceAmount = ImmValue * PointerSize + PointerSize; RemainingLoopCount = 0; - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset + - AdvanceAmount, false); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset + + AdvanceAmount, PointerSize); if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " @@ -3839,15 +3869,6 @@ void MachOBindEntry::moveNext() { moveToEnd(); return; } - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); - if (error) { - *E = - malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " + - Twine(error) + " for opcode at: 0x" + - Twine::utohexstr(OpcodeStart - Opcodes.begin())); - moveToEnd(); - return; - } if (SymbolName == StringRef()) { *E = malformedError( "for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " @@ -3866,8 +3887,8 @@ void MachOBindEntry::moveNext() { moveToEnd(); return; } - error = O->BindEntryCheckCountAndSkip(Count, Skip, PointerSize, - SegmentIndex, SegmentOffset); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize, Count, Skip); if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " + @@ -3990,53 +4011,40 @@ BindRebaseSegInfo::BindRebaseSegInfo(const object::MachOObjectFile *Obj) { MaxSegIndex = CurSegIndex; } -// For use with a SegIndex,SegOffset pair in MachOBindEntry::moveNext() to -// validate a MachOBindEntry or MachORebaseEntry. -const char * BindRebaseSegInfo::checkSegAndOffset(int32_t SegIndex, - uint64_t SegOffset, - bool endInvalid) { +// For use with a SegIndex, SegOffset, and PointerSize triple in +// MachOBindEntry::moveNext() to validate a MachOBindEntry or MachORebaseEntry. +// +// Given a SegIndex, SegOffset, and PointerSize, verify a valid section exists +// that fully contains a pointer at that location. Multiple fixups in a bind +// (such as with the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode) can +// be tested via the Count and Skip parameters. +const char * BindRebaseSegInfo::checkSegAndOffsets(int32_t SegIndex, + uint64_t SegOffset, + uint8_t PointerSize, + uint32_t Count, + uint32_t Skip) { if (SegIndex == -1) return "missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"; if (SegIndex >= MaxSegIndex) return "bad segIndex (too large)"; - for (const SectionInfo &SI : Sections) { - if (SI.SegmentIndex != SegIndex) - continue; - if (SI.OffsetInSegment > SegOffset) - continue; - if (SegOffset > (SI.OffsetInSegment + SI.Size)) - continue; - if (endInvalid && SegOffset >= (SI.OffsetInSegment + SI.Size)) - continue; - return nullptr; - } - return "bad segOffset, too large"; -} - -// For use in MachOBindEntry::moveNext() to validate a MachOBindEntry for -// the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode and for use in -// MachORebaseEntry::moveNext() to validate a MachORebaseEntry for -// REBASE_OPCODE_DO_*_TIMES* opcodes. The SegIndex and SegOffset must have -// been already checked. -const char * BindRebaseSegInfo::checkCountAndSkip(uint32_t Count, uint32_t Skip, - uint8_t PointerSize, - int32_t SegIndex, - uint64_t SegOffset) { - const SectionInfo &SI = findSection(SegIndex, SegOffset); - uint64_t addr = SI.SegmentStartAddress + SegOffset; - if (addr >= SI.Address + SI.Size) - return "bad segOffset, too large"; - uint64_t i = 0; - if (Count > 1) - i = (Skip + PointerSize) * (Count - 1); - else if (Count == 1) - i = Skip + PointerSize; - if (addr + i >= SI.Address + SI.Size) { - // For rebase opcodes they can step from one section to another. - uint64_t TrailingSegOffset = (addr + i) - SI.SegmentStartAddress; - const char *error = checkSegAndOffset(SegIndex, TrailingSegOffset, false); - if (error) - return "bad count and skip, too large"; + for (uint32_t i = 0; i < Count; ++i) { + uint32_t Start = SegOffset + i * (PointerSize + Skip); + uint32_t End = Start + PointerSize; + bool Found = false; + for (const SectionInfo &SI : Sections) { + if (SI.SegmentIndex != SegIndex) + continue; + if ((SI.OffsetInSegment<=Start) && (Start<(SI.OffsetInSegment+SI.Size))) { + if (End <= SI.OffsetInSegment + SI.Size) { + Found = true; + break; + } + else + return "bad offset, extends beyond section boundary"; + } + } + if (!Found) + return "bad offset, not in section"; } return nullptr; } @@ -4514,8 +4522,11 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoRebaseOpcodes() const { if (!DyldInfoLoadCmd) return None; - MachO::dyld_info_command DyldInfo = - getStruct<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + auto DyldInfoOrErr = + getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + if (!DyldInfoOrErr) + return None; + MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.rebase_off)); return makeArrayRef(Ptr, DyldInfo.rebase_size); @@ -4525,8 +4536,11 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoBindOpcodes() const { if (!DyldInfoLoadCmd) return None; - MachO::dyld_info_command DyldInfo = - getStruct<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + auto DyldInfoOrErr = + getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + if (!DyldInfoOrErr) + return None; + MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.bind_off)); return makeArrayRef(Ptr, DyldInfo.bind_size); @@ -4536,8 +4550,11 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoWeakBindOpcodes() const { if (!DyldInfoLoadCmd) return None; - MachO::dyld_info_command DyldInfo = - getStruct<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + auto DyldInfoOrErr = + getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + if (!DyldInfoOrErr) + return None; + MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.weak_bind_off)); return makeArrayRef(Ptr, DyldInfo.weak_bind_size); @@ -4547,8 +4564,11 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const { if (!DyldInfoLoadCmd) return None; - MachO::dyld_info_command DyldInfo = - getStruct<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + auto DyldInfoOrErr = + getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + if (!DyldInfoOrErr) + return None; + MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.lazy_bind_off)); return makeArrayRef(Ptr, DyldInfo.lazy_bind_size); @@ -4558,8 +4578,11 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const { if (!DyldInfoLoadCmd) return None; - MachO::dyld_info_command DyldInfo = - getStruct<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + auto DyldInfoOrErr = + getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + if (!DyldInfoOrErr) + return None; + MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.export_off)); return makeArrayRef(Ptr, DyldInfo.export_size); |