aboutsummaryrefslogtreecommitdiff
path: root/lib/Object/MachOObjectFile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Object/MachOObjectFile.cpp')
-rw-r--r--lib/Object/MachOObjectFile.cpp445
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);