5442 lines · cpp
1//===- MachOObjectFile.cpp - Mach-O object file binding -------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines the MachOObjectFile class, which binds the MachOObject10// class to the generic ObjectFile wrapper.11//12//===----------------------------------------------------------------------===//13 14#include "llvm/ADT/ArrayRef.h"15#include "llvm/ADT/STLExtras.h"16#include "llvm/ADT/SmallVector.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/ADT/StringSwitch.h"19#include "llvm/ADT/Twine.h"20#include "llvm/ADT/bit.h"21#include "llvm/BinaryFormat/MachO.h"22#include "llvm/BinaryFormat/Swift.h"23#include "llvm/Object/Error.h"24#include "llvm/Object/MachO.h"25#include "llvm/Object/ObjectFile.h"26#include "llvm/Object/SymbolicFile.h"27#include "llvm/Support/DataExtractor.h"28#include "llvm/Support/Debug.h"29#include "llvm/Support/Errc.h"30#include "llvm/Support/Error.h"31#include "llvm/Support/ErrorHandling.h"32#include "llvm/Support/FileSystem.h"33#include "llvm/Support/Format.h"34#include "llvm/Support/LEB128.h"35#include "llvm/Support/MemoryBufferRef.h"36#include "llvm/Support/Path.h"37#include "llvm/Support/SwapByteOrder.h"38#include "llvm/Support/raw_ostream.h"39#include "llvm/TargetParser/Host.h"40#include "llvm/TargetParser/Triple.h"41#include <algorithm>42#include <cassert>43#include <cstddef>44#include <cstdint>45#include <cstring>46#include <limits>47#include <list>48#include <memory>49#include <system_error>50 51using namespace llvm;52using namespace object;53 54namespace {55 56 struct section_base {57 char sectname[16];58 char segname[16];59 };60 61} // end anonymous namespace62 63static Error malformedError(const Twine &Msg) {64 return make_error<GenericBinaryError>("truncated or malformed object (" +65 Msg + ")",66 object_error::parse_failed);67}68 69// FIXME: Replace all uses of this function with getStructOrErr.70template <typename T>71static T getStruct(const MachOObjectFile &O, const char *P) {72 // Don't read before the beginning or past the end of the file73 if (P < O.getData().begin() || P + sizeof(T) > O.getData().end())74 report_fatal_error("Malformed MachO file.");75 76 T Cmd;77 memcpy(&Cmd, P, sizeof(T));78 if (O.isLittleEndian() != sys::IsLittleEndianHost)79 MachO::swapStruct(Cmd);80 return Cmd;81}82 83template <typename T>84static Expected<T> getStructOrErr(const MachOObjectFile &O, const char *P) {85 // Don't read before the beginning or past the end of the file86 if (P < O.getData().begin() || P + sizeof(T) > O.getData().end())87 return malformedError("Structure read out-of-range");88 89 T Cmd;90 memcpy(&Cmd, P, sizeof(T));91 if (O.isLittleEndian() != sys::IsLittleEndianHost)92 MachO::swapStruct(Cmd);93 return Cmd;94}95 96static const char *97getSectionPtr(const MachOObjectFile &O, MachOObjectFile::LoadCommandInfo L,98 unsigned Sec) {99 uintptr_t CommandAddr = reinterpret_cast<uintptr_t>(L.Ptr);100 101 bool Is64 = O.is64Bit();102 unsigned SegmentLoadSize = Is64 ? sizeof(MachO::segment_command_64) :103 sizeof(MachO::segment_command);104 unsigned SectionSize = Is64 ? sizeof(MachO::section_64) :105 sizeof(MachO::section);106 107 uintptr_t SectionAddr = CommandAddr + SegmentLoadSize + Sec * SectionSize;108 return reinterpret_cast<const char*>(SectionAddr);109}110 111static const char *getPtr(const MachOObjectFile &O, size_t Offset,112 size_t MachOFilesetEntryOffset = 0) {113 assert(Offset <= O.getData().size() &&114 MachOFilesetEntryOffset <= O.getData().size());115 return O.getData().data() + Offset + MachOFilesetEntryOffset;116}117 118static MachO::nlist_base119getSymbolTableEntryBase(const MachOObjectFile &O, DataRefImpl DRI) {120 const char *P = reinterpret_cast<const char *>(DRI.p);121 return getStruct<MachO::nlist_base>(O, P);122}123 124static StringRef parseSegmentOrSectionName(const char *P) {125 if (P[15] == 0)126 // Null terminated.127 return P;128 // Not null terminated, so this is a 16 char string.129 return StringRef(P, 16);130}131 132static unsigned getCPUType(const MachOObjectFile &O) {133 return O.getHeader().cputype;134}135 136static unsigned getCPUSubType(const MachOObjectFile &O) {137 return O.getHeader().cpusubtype & ~MachO::CPU_SUBTYPE_MASK;138}139 140static uint32_t141getPlainRelocationAddress(const MachO::any_relocation_info &RE) {142 return RE.r_word0;143}144 145static unsigned146getScatteredRelocationAddress(const MachO::any_relocation_info &RE) {147 return RE.r_word0 & 0xffffff;148}149 150static bool getPlainRelocationPCRel(const MachOObjectFile &O,151 const MachO::any_relocation_info &RE) {152 if (O.isLittleEndian())153 return (RE.r_word1 >> 24) & 1;154 return (RE.r_word1 >> 7) & 1;155}156 157static bool158getScatteredRelocationPCRel(const MachO::any_relocation_info &RE) {159 return (RE.r_word0 >> 30) & 1;160}161 162static unsigned getPlainRelocationLength(const MachOObjectFile &O,163 const MachO::any_relocation_info &RE) {164 if (O.isLittleEndian())165 return (RE.r_word1 >> 25) & 3;166 return (RE.r_word1 >> 5) & 3;167}168 169static unsigned170getScatteredRelocationLength(const MachO::any_relocation_info &RE) {171 return (RE.r_word0 >> 28) & 3;172}173 174static unsigned getPlainRelocationType(const MachOObjectFile &O,175 const MachO::any_relocation_info &RE) {176 if (O.isLittleEndian())177 return RE.r_word1 >> 28;178 return RE.r_word1 & 0xf;179}180 181static uint32_t getSectionFlags(const MachOObjectFile &O,182 DataRefImpl Sec) {183 if (O.is64Bit()) {184 MachO::section_64 Sect = O.getSection64(Sec);185 return Sect.flags;186 }187 MachO::section Sect = O.getSection(Sec);188 return Sect.flags;189}190 191static Expected<MachOObjectFile::LoadCommandInfo>192getLoadCommandInfo(const MachOObjectFile &Obj, const char *Ptr,193 uint32_t LoadCommandIndex) {194 if (auto CmdOrErr = getStructOrErr<MachO::load_command>(Obj, Ptr)) {195 assert(Ptr <= Obj.getData().end() && "Start must be before end");196 if (CmdOrErr->cmdsize > (uintptr_t)(Obj.getData().end() - Ptr))197 return malformedError("load command " + Twine(LoadCommandIndex) +198 " extends past end of file");199 if (CmdOrErr->cmdsize < 8)200 return malformedError("load command " + Twine(LoadCommandIndex) +201 " with size less than 8 bytes");202 return MachOObjectFile::LoadCommandInfo({Ptr, *CmdOrErr});203 } else204 return CmdOrErr.takeError();205}206 207static Expected<MachOObjectFile::LoadCommandInfo>208getFirstLoadCommandInfo(const MachOObjectFile &Obj) {209 unsigned HeaderSize = Obj.is64Bit() ? sizeof(MachO::mach_header_64)210 : sizeof(MachO::mach_header);211 if (sizeof(MachO::load_command) > Obj.getHeader().sizeofcmds)212 return malformedError("load command 0 extends past the end all load "213 "commands in the file");214 return getLoadCommandInfo(215 Obj, getPtr(Obj, HeaderSize, Obj.getMachOFilesetEntryOffset()), 0);216}217 218static Expected<MachOObjectFile::LoadCommandInfo>219getNextLoadCommandInfo(const MachOObjectFile &Obj, uint32_t LoadCommandIndex,220 const MachOObjectFile::LoadCommandInfo &L) {221 unsigned HeaderSize = Obj.is64Bit() ? sizeof(MachO::mach_header_64)222 : sizeof(MachO::mach_header);223 if (L.Ptr + L.C.cmdsize + sizeof(MachO::load_command) >224 Obj.getData().data() + Obj.getMachOFilesetEntryOffset() + HeaderSize +225 Obj.getHeader().sizeofcmds)226 return malformedError("load command " + Twine(LoadCommandIndex + 1) +227 " extends past the end all load commands in the file");228 return getLoadCommandInfo(Obj, L.Ptr + L.C.cmdsize, LoadCommandIndex + 1);229}230 231template <typename T>232static void parseHeader(const MachOObjectFile &Obj, T &Header,233 Error &Err) {234 if (sizeof(T) > Obj.getData().size()) {235 Err = malformedError("the mach header extends past the end of the "236 "file");237 return;238 }239 if (auto HeaderOrErr = getStructOrErr<T>(240 Obj, getPtr(Obj, 0, Obj.getMachOFilesetEntryOffset())))241 Header = *HeaderOrErr;242 else243 Err = HeaderOrErr.takeError();244}245 246// This is used to check for overlapping of Mach-O elements.247struct MachOElement {248 uint64_t Offset;249 uint64_t Size;250 const char *Name;251};252 253static Error checkOverlappingElement(std::list<MachOElement> &Elements,254 uint64_t Offset, uint64_t Size,255 const char *Name) {256 if (Size == 0)257 return Error::success();258 259 for (auto it = Elements.begin(); it != Elements.end(); ++it) {260 const auto &E = *it;261 if ((Offset >= E.Offset && Offset < E.Offset + E.Size) ||262 (Offset + Size > E.Offset && Offset + Size < E.Offset + E.Size) ||263 (Offset <= E.Offset && Offset + Size >= E.Offset + E.Size))264 return malformedError(Twine(Name) + " at offset " + Twine(Offset) +265 " with a size of " + Twine(Size) + ", overlaps " +266 E.Name + " at offset " + Twine(E.Offset) + " with "267 "a size of " + Twine(E.Size));268 auto nt = it;269 nt++;270 if (nt != Elements.end()) {271 const auto &N = *nt;272 if (Offset + Size <= N.Offset) {273 Elements.insert(nt, {Offset, Size, Name});274 return Error::success();275 }276 }277 }278 Elements.push_back({Offset, Size, Name});279 return Error::success();280}281 282// Parses LC_SEGMENT or LC_SEGMENT_64 load command, adds addresses of all283// sections to \param Sections, and optionally sets284// \param IsPageZeroSegment to true.285template <typename Segment, typename Section>286static Error parseSegmentLoadCommand(287 const MachOObjectFile &Obj, const MachOObjectFile::LoadCommandInfo &Load,288 SmallVectorImpl<const char *> &Sections, bool &IsPageZeroSegment,289 uint32_t LoadCommandIndex, const char *CmdName, uint64_t SizeOfHeaders,290 std::list<MachOElement> &Elements) {291 const unsigned SegmentLoadSize = sizeof(Segment);292 if (Load.C.cmdsize < SegmentLoadSize)293 return malformedError("load command " + Twine(LoadCommandIndex) +294 " " + CmdName + " cmdsize too small");295 if (auto SegOrErr = getStructOrErr<Segment>(Obj, Load.Ptr)) {296 Segment S = SegOrErr.get();297 const unsigned SectionSize = sizeof(Section);298 uint64_t FileSize = Obj.getData().size();299 if (S.nsects > std::numeric_limits<uint32_t>::max() / SectionSize ||300 S.nsects * SectionSize > Load.C.cmdsize - SegmentLoadSize)301 return malformedError("load command " + Twine(LoadCommandIndex) +302 " inconsistent cmdsize in " + CmdName +303 " for the number of sections");304 for (unsigned J = 0; J < S.nsects; ++J) {305 const char *Sec = getSectionPtr(Obj, Load, J);306 Sections.push_back(Sec);307 auto SectionOrErr = getStructOrErr<Section>(Obj, Sec);308 if (!SectionOrErr)309 return SectionOrErr.takeError();310 Section s = SectionOrErr.get();311 if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&312 Obj.getHeader().filetype != MachO::MH_DSYM &&313 s.flags != MachO::S_ZEROFILL &&314 s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&315 s.offset > FileSize)316 return malformedError("offset field of section " + Twine(J) + " in " +317 CmdName + " command " + Twine(LoadCommandIndex) +318 " extends past the end of the file");319 if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&320 Obj.getHeader().filetype != MachO::MH_DSYM &&321 s.flags != MachO::S_ZEROFILL &&322 s.flags != MachO::S_THREAD_LOCAL_ZEROFILL && S.fileoff == 0 &&323 s.offset < SizeOfHeaders && s.size != 0)324 return malformedError("offset field of section " + Twine(J) + " in " +325 CmdName + " command " + Twine(LoadCommandIndex) +326 " not past the headers of the file");327 uint64_t BigSize = s.offset;328 BigSize += s.size;329 if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&330 Obj.getHeader().filetype != MachO::MH_DSYM &&331 s.flags != MachO::S_ZEROFILL &&332 s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&333 BigSize > FileSize)334 return malformedError("offset field plus size field of section " +335 Twine(J) + " in " + CmdName + " command " +336 Twine(LoadCommandIndex) +337 " extends past the end of the file");338 if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&339 Obj.getHeader().filetype != MachO::MH_DSYM &&340 s.flags != MachO::S_ZEROFILL &&341 s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&342 s.size > S.filesize)343 return malformedError("size field of section " +344 Twine(J) + " in " + CmdName + " command " +345 Twine(LoadCommandIndex) +346 " greater than the segment");347 if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&348 Obj.getHeader().filetype != MachO::MH_DSYM && s.size != 0 &&349 s.addr < S.vmaddr)350 return malformedError("addr field of section " + Twine(J) + " in " +351 CmdName + " command " + Twine(LoadCommandIndex) +352 " less than the segment's vmaddr");353 BigSize = s.addr;354 BigSize += s.size;355 uint64_t BigEnd = S.vmaddr;356 BigEnd += S.vmsize;357 if (S.vmsize != 0 && s.size != 0 && BigSize > BigEnd)358 return malformedError("addr field plus size of section " + Twine(J) +359 " in " + CmdName + " command " +360 Twine(LoadCommandIndex) +361 " greater than than "362 "the segment's vmaddr plus vmsize");363 if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&364 Obj.getHeader().filetype != MachO::MH_DSYM &&365 s.flags != MachO::S_ZEROFILL &&366 s.flags != MachO::S_THREAD_LOCAL_ZEROFILL)367 if (Error Err = checkOverlappingElement(Elements, s.offset, s.size,368 "section contents"))369 return Err;370 if (s.reloff > FileSize)371 return malformedError("reloff field of section " + Twine(J) + " in " +372 CmdName + " command " + Twine(LoadCommandIndex) +373 " extends past the end of the file");374 BigSize = s.nreloc;375 BigSize *= sizeof(struct MachO::relocation_info);376 BigSize += s.reloff;377 if (BigSize > FileSize)378 return malformedError("reloff field plus nreloc field times sizeof("379 "struct relocation_info) of section " +380 Twine(J) + " in " + CmdName + " command " +381 Twine(LoadCommandIndex) +382 " extends past the end of the file");383 if (Error Err = checkOverlappingElement(Elements, s.reloff, s.nreloc *384 sizeof(struct385 MachO::relocation_info),386 "section relocation entries"))387 return Err;388 }389 if (S.fileoff > FileSize)390 return malformedError("load command " + Twine(LoadCommandIndex) +391 " fileoff field in " + CmdName +392 " extends past the end of the file");393 uint64_t BigSize = S.fileoff;394 BigSize += S.filesize;395 if (BigSize > FileSize)396 return malformedError("load command " + Twine(LoadCommandIndex) +397 " fileoff field plus filesize field in " +398 CmdName + " extends past the end of the file");399 if (S.vmsize != 0 && S.filesize > S.vmsize)400 return malformedError("load command " + Twine(LoadCommandIndex) +401 " filesize field in " + CmdName +402 " greater than vmsize field");403 IsPageZeroSegment |= StringRef("__PAGEZERO") == S.segname;404 } else405 return SegOrErr.takeError();406 407 return Error::success();408}409 410static Error checkSymtabCommand(const MachOObjectFile &Obj,411 const MachOObjectFile::LoadCommandInfo &Load,412 uint32_t LoadCommandIndex,413 const char **SymtabLoadCmd,414 std::list<MachOElement> &Elements) {415 if (Load.C.cmdsize < sizeof(MachO::symtab_command))416 return malformedError("load command " + Twine(LoadCommandIndex) +417 " LC_SYMTAB cmdsize too small");418 if (*SymtabLoadCmd != nullptr)419 return malformedError("more than one LC_SYMTAB command");420 auto SymtabOrErr = getStructOrErr<MachO::symtab_command>(Obj, Load.Ptr);421 if (!SymtabOrErr)422 return SymtabOrErr.takeError();423 MachO::symtab_command Symtab = SymtabOrErr.get();424 if (Symtab.cmdsize != sizeof(MachO::symtab_command))425 return malformedError("LC_SYMTAB command " + Twine(LoadCommandIndex) +426 " has incorrect cmdsize");427 uint64_t FileSize = Obj.getData().size();428 if (Symtab.symoff > FileSize)429 return malformedError("symoff field of LC_SYMTAB command " +430 Twine(LoadCommandIndex) + " extends past the end "431 "of the file");432 uint64_t SymtabSize = Symtab.nsyms;433 const char *struct_nlist_name;434 if (Obj.is64Bit()) {435 SymtabSize *= sizeof(MachO::nlist_64);436 struct_nlist_name = "struct nlist_64";437 } else {438 SymtabSize *= sizeof(MachO::nlist);439 struct_nlist_name = "struct nlist";440 }441 uint64_t BigSize = SymtabSize;442 BigSize += Symtab.symoff;443 if (BigSize > FileSize)444 return malformedError("symoff field plus nsyms field times sizeof(" +445 Twine(struct_nlist_name) + ") of LC_SYMTAB command " +446 Twine(LoadCommandIndex) + " extends past the end "447 "of the file");448 if (Error Err = checkOverlappingElement(Elements, Symtab.symoff, SymtabSize,449 "symbol table"))450 return Err;451 if (Symtab.stroff > FileSize)452 return malformedError("stroff field of LC_SYMTAB command " +453 Twine(LoadCommandIndex) + " extends past the end "454 "of the file");455 BigSize = Symtab.stroff;456 BigSize += Symtab.strsize;457 if (BigSize > FileSize)458 return malformedError("stroff field plus strsize field of LC_SYMTAB "459 "command " + Twine(LoadCommandIndex) + " extends "460 "past the end of the file");461 if (Error Err = checkOverlappingElement(Elements, Symtab.stroff,462 Symtab.strsize, "string table"))463 return Err;464 *SymtabLoadCmd = Load.Ptr;465 return Error::success();466}467 468static Error checkDysymtabCommand(const MachOObjectFile &Obj,469 const MachOObjectFile::LoadCommandInfo &Load,470 uint32_t LoadCommandIndex,471 const char **DysymtabLoadCmd,472 std::list<MachOElement> &Elements) {473 if (Load.C.cmdsize < sizeof(MachO::dysymtab_command))474 return malformedError("load command " + Twine(LoadCommandIndex) +475 " LC_DYSYMTAB cmdsize too small");476 if (*DysymtabLoadCmd != nullptr)477 return malformedError("more than one LC_DYSYMTAB command");478 auto DysymtabOrErr =479 getStructOrErr<MachO::dysymtab_command>(Obj, Load.Ptr);480 if (!DysymtabOrErr)481 return DysymtabOrErr.takeError();482 MachO::dysymtab_command Dysymtab = DysymtabOrErr.get();483 if (Dysymtab.cmdsize != sizeof(MachO::dysymtab_command))484 return malformedError("LC_DYSYMTAB command " + Twine(LoadCommandIndex) +485 " has incorrect cmdsize");486 uint64_t FileSize = Obj.getData().size();487 if (Dysymtab.tocoff > FileSize)488 return malformedError("tocoff field of LC_DYSYMTAB command " +489 Twine(LoadCommandIndex) + " extends past the end of "490 "the file");491 uint64_t BigSize = Dysymtab.ntoc;492 BigSize *= sizeof(MachO::dylib_table_of_contents);493 BigSize += Dysymtab.tocoff;494 if (BigSize > FileSize)495 return malformedError("tocoff field plus ntoc field times sizeof(struct "496 "dylib_table_of_contents) of LC_DYSYMTAB command " +497 Twine(LoadCommandIndex) + " extends past the end of "498 "the file");499 if (Error Err = checkOverlappingElement(Elements, Dysymtab.tocoff,500 Dysymtab.ntoc * sizeof(struct501 MachO::dylib_table_of_contents),502 "table of contents"))503 return Err;504 if (Dysymtab.modtaboff > FileSize)505 return malformedError("modtaboff field of LC_DYSYMTAB command " +506 Twine(LoadCommandIndex) + " extends past the end of "507 "the file");508 BigSize = Dysymtab.nmodtab;509 const char *struct_dylib_module_name;510 uint64_t sizeof_modtab;511 if (Obj.is64Bit()) {512 sizeof_modtab = sizeof(MachO::dylib_module_64);513 struct_dylib_module_name = "struct dylib_module_64";514 } else {515 sizeof_modtab = sizeof(MachO::dylib_module);516 struct_dylib_module_name = "struct dylib_module";517 }518 BigSize *= sizeof_modtab;519 BigSize += Dysymtab.modtaboff;520 if (BigSize > FileSize)521 return malformedError("modtaboff field plus nmodtab field times sizeof(" +522 Twine(struct_dylib_module_name) + ") of LC_DYSYMTAB "523 "command " + Twine(LoadCommandIndex) + " extends "524 "past the end of the file");525 if (Error Err = checkOverlappingElement(Elements, Dysymtab.modtaboff,526 Dysymtab.nmodtab * sizeof_modtab,527 "module table"))528 return Err;529 if (Dysymtab.extrefsymoff > FileSize)530 return malformedError("extrefsymoff field of LC_DYSYMTAB command " +531 Twine(LoadCommandIndex) + " extends past the end of "532 "the file");533 BigSize = Dysymtab.nextrefsyms;534 BigSize *= sizeof(MachO::dylib_reference);535 BigSize += Dysymtab.extrefsymoff;536 if (BigSize > FileSize)537 return malformedError("extrefsymoff field plus nextrefsyms field times "538 "sizeof(struct dylib_reference) of LC_DYSYMTAB "539 "command " + Twine(LoadCommandIndex) + " extends "540 "past the end of the file");541 if (Error Err = checkOverlappingElement(Elements, Dysymtab.extrefsymoff,542 Dysymtab.nextrefsyms *543 sizeof(MachO::dylib_reference),544 "reference table"))545 return Err;546 if (Dysymtab.indirectsymoff > FileSize)547 return malformedError("indirectsymoff field of LC_DYSYMTAB command " +548 Twine(LoadCommandIndex) + " extends past the end of "549 "the file");550 BigSize = Dysymtab.nindirectsyms;551 BigSize *= sizeof(uint32_t);552 BigSize += Dysymtab.indirectsymoff;553 if (BigSize > FileSize)554 return malformedError("indirectsymoff field plus nindirectsyms field times "555 "sizeof(uint32_t) of LC_DYSYMTAB command " +556 Twine(LoadCommandIndex) + " extends past the end of "557 "the file");558 if (Error Err = checkOverlappingElement(Elements, Dysymtab.indirectsymoff,559 Dysymtab.nindirectsyms *560 sizeof(uint32_t),561 "indirect table"))562 return Err;563 if (Dysymtab.extreloff > FileSize)564 return malformedError("extreloff field of LC_DYSYMTAB command " +565 Twine(LoadCommandIndex) + " extends past the end of "566 "the file");567 BigSize = Dysymtab.nextrel;568 BigSize *= sizeof(MachO::relocation_info);569 BigSize += Dysymtab.extreloff;570 if (BigSize > FileSize)571 return malformedError("extreloff field plus nextrel field times sizeof"572 "(struct relocation_info) of LC_DYSYMTAB command " +573 Twine(LoadCommandIndex) + " extends past the end of "574 "the file");575 if (Error Err = checkOverlappingElement(Elements, Dysymtab.extreloff,576 Dysymtab.nextrel *577 sizeof(MachO::relocation_info),578 "external relocation table"))579 return Err;580 if (Dysymtab.locreloff > FileSize)581 return malformedError("locreloff field of LC_DYSYMTAB command " +582 Twine(LoadCommandIndex) + " extends past the end of "583 "the file");584 BigSize = Dysymtab.nlocrel;585 BigSize *= sizeof(MachO::relocation_info);586 BigSize += Dysymtab.locreloff;587 if (BigSize > FileSize)588 return malformedError("locreloff field plus nlocrel field times sizeof"589 "(struct relocation_info) of LC_DYSYMTAB command " +590 Twine(LoadCommandIndex) + " extends past the end of "591 "the file");592 if (Error Err = checkOverlappingElement(Elements, Dysymtab.locreloff,593 Dysymtab.nlocrel *594 sizeof(MachO::relocation_info),595 "local relocation table"))596 return Err;597 *DysymtabLoadCmd = Load.Ptr;598 return Error::success();599}600 601static Error checkLinkeditDataCommand(const MachOObjectFile &Obj,602 const MachOObjectFile::LoadCommandInfo &Load,603 uint32_t LoadCommandIndex,604 const char **LoadCmd, const char *CmdName,605 std::list<MachOElement> &Elements,606 const char *ElementName) {607 if (Load.C.cmdsize < sizeof(MachO::linkedit_data_command))608 return malformedError("load command " + Twine(LoadCommandIndex) + " " +609 CmdName + " cmdsize too small");610 if (*LoadCmd != nullptr)611 return malformedError("more than one " + Twine(CmdName) + " command");612 auto LinkDataOrError =613 getStructOrErr<MachO::linkedit_data_command>(Obj, Load.Ptr);614 if (!LinkDataOrError)615 return LinkDataOrError.takeError();616 MachO::linkedit_data_command LinkData = LinkDataOrError.get();617 if (LinkData.cmdsize != sizeof(MachO::linkedit_data_command))618 return malformedError(Twine(CmdName) + " command " +619 Twine(LoadCommandIndex) + " has incorrect cmdsize");620 uint64_t FileSize = Obj.getData().size();621 if (LinkData.dataoff > FileSize)622 return malformedError("dataoff field of " + Twine(CmdName) + " command " +623 Twine(LoadCommandIndex) + " extends past the end of "624 "the file");625 uint64_t BigSize = LinkData.dataoff;626 BigSize += LinkData.datasize;627 if (BigSize > FileSize)628 return malformedError("dataoff field plus datasize field of " +629 Twine(CmdName) + " command " +630 Twine(LoadCommandIndex) + " extends past the end of "631 "the file");632 if (Error Err = checkOverlappingElement(Elements, LinkData.dataoff,633 LinkData.datasize, ElementName))634 return Err;635 *LoadCmd = Load.Ptr;636 return Error::success();637}638 639static Error checkDyldInfoCommand(const MachOObjectFile &Obj,640 const MachOObjectFile::LoadCommandInfo &Load,641 uint32_t LoadCommandIndex,642 const char **LoadCmd, const char *CmdName,643 std::list<MachOElement> &Elements) {644 if (Load.C.cmdsize < sizeof(MachO::dyld_info_command))645 return malformedError("load command " + Twine(LoadCommandIndex) + " " +646 CmdName + " cmdsize too small");647 if (*LoadCmd != nullptr)648 return malformedError("more than one LC_DYLD_INFO and or LC_DYLD_INFO_ONLY "649 "command");650 auto DyldInfoOrErr =651 getStructOrErr<MachO::dyld_info_command>(Obj, Load.Ptr);652 if (!DyldInfoOrErr)653 return DyldInfoOrErr.takeError();654 MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();655 if (DyldInfo.cmdsize != sizeof(MachO::dyld_info_command))656 return malformedError(Twine(CmdName) + " command " +657 Twine(LoadCommandIndex) + " has incorrect cmdsize");658 uint64_t FileSize = Obj.getData().size();659 if (DyldInfo.rebase_off > FileSize)660 return malformedError("rebase_off field of " + Twine(CmdName) +661 " command " + Twine(LoadCommandIndex) + " extends "662 "past the end of the file");663 uint64_t BigSize = DyldInfo.rebase_off;664 BigSize += DyldInfo.rebase_size;665 if (BigSize > FileSize)666 return malformedError("rebase_off field plus rebase_size field of " +667 Twine(CmdName) + " command " +668 Twine(LoadCommandIndex) + " extends past the end of "669 "the file");670 if (Error Err = checkOverlappingElement(Elements, DyldInfo.rebase_off,671 DyldInfo.rebase_size,672 "dyld rebase info"))673 return Err;674 if (DyldInfo.bind_off > FileSize)675 return malformedError("bind_off field of " + Twine(CmdName) +676 " command " + Twine(LoadCommandIndex) + " extends "677 "past the end of the file");678 BigSize = DyldInfo.bind_off;679 BigSize += DyldInfo.bind_size;680 if (BigSize > FileSize)681 return malformedError("bind_off field plus bind_size field of " +682 Twine(CmdName) + " command " +683 Twine(LoadCommandIndex) + " extends past the end of "684 "the file");685 if (Error Err = checkOverlappingElement(Elements, DyldInfo.bind_off,686 DyldInfo.bind_size,687 "dyld bind info"))688 return Err;689 if (DyldInfo.weak_bind_off > FileSize)690 return malformedError("weak_bind_off field of " + Twine(CmdName) +691 " command " + Twine(LoadCommandIndex) + " extends "692 "past the end of the file");693 BigSize = DyldInfo.weak_bind_off;694 BigSize += DyldInfo.weak_bind_size;695 if (BigSize > FileSize)696 return malformedError("weak_bind_off field plus weak_bind_size field of " +697 Twine(CmdName) + " command " +698 Twine(LoadCommandIndex) + " extends past the end of "699 "the file");700 if (Error Err = checkOverlappingElement(Elements, DyldInfo.weak_bind_off,701 DyldInfo.weak_bind_size,702 "dyld weak bind info"))703 return Err;704 if (DyldInfo.lazy_bind_off > FileSize)705 return malformedError("lazy_bind_off field of " + Twine(CmdName) +706 " command " + Twine(LoadCommandIndex) + " extends "707 "past the end of the file");708 BigSize = DyldInfo.lazy_bind_off;709 BigSize += DyldInfo.lazy_bind_size;710 if (BigSize > FileSize)711 return malformedError("lazy_bind_off field plus lazy_bind_size field of " +712 Twine(CmdName) + " command " +713 Twine(LoadCommandIndex) + " extends past the end of "714 "the file");715 if (Error Err = checkOverlappingElement(Elements, DyldInfo.lazy_bind_off,716 DyldInfo.lazy_bind_size,717 "dyld lazy bind info"))718 return Err;719 if (DyldInfo.export_off > FileSize)720 return malformedError("export_off field of " + Twine(CmdName) +721 " command " + Twine(LoadCommandIndex) + " extends "722 "past the end of the file");723 BigSize = DyldInfo.export_off;724 BigSize += DyldInfo.export_size;725 if (BigSize > FileSize)726 return malformedError("export_off field plus export_size field of " +727 Twine(CmdName) + " command " +728 Twine(LoadCommandIndex) + " extends past the end of "729 "the file");730 if (Error Err = checkOverlappingElement(Elements, DyldInfo.export_off,731 DyldInfo.export_size,732 "dyld export info"))733 return Err;734 *LoadCmd = Load.Ptr;735 return Error::success();736}737 738static Error checkDylibCommand(const MachOObjectFile &Obj,739 const MachOObjectFile::LoadCommandInfo &Load,740 uint32_t LoadCommandIndex, const char *CmdName) {741 if (Load.C.cmdsize < sizeof(MachO::dylib_command))742 return malformedError("load command " + Twine(LoadCommandIndex) + " " +743 CmdName + " cmdsize too small");744 auto CommandOrErr = getStructOrErr<MachO::dylib_command>(Obj, Load.Ptr);745 if (!CommandOrErr)746 return CommandOrErr.takeError();747 MachO::dylib_command D = CommandOrErr.get();748 if (D.dylib.name < sizeof(MachO::dylib_command))749 return malformedError("load command " + Twine(LoadCommandIndex) + " " +750 CmdName + " name.offset field too small, not past "751 "the end of the dylib_command struct");752 if (D.dylib.name >= D.cmdsize)753 return malformedError("load command " + Twine(LoadCommandIndex) + " " +754 CmdName + " name.offset field extends past the end "755 "of the load command");756 // Make sure there is a null between the starting offset of the name and757 // the end of the load command.758 uint32_t i;759 const char *P = (const char *)Load.Ptr;760 for (i = D.dylib.name; i < D.cmdsize; i++)761 if (P[i] == '\0')762 break;763 if (i >= D.cmdsize)764 return malformedError("load command " + Twine(LoadCommandIndex) + " " +765 CmdName + " library name extends past the end of the "766 "load command");767 return Error::success();768}769 770static Error checkDylibIdCommand(const MachOObjectFile &Obj,771 const MachOObjectFile::LoadCommandInfo &Load,772 uint32_t LoadCommandIndex,773 const char **LoadCmd) {774 if (Error Err = checkDylibCommand(Obj, Load, LoadCommandIndex,775 "LC_ID_DYLIB"))776 return Err;777 if (*LoadCmd != nullptr)778 return malformedError("more than one LC_ID_DYLIB command");779 if (Obj.getHeader().filetype != MachO::MH_DYLIB &&780 Obj.getHeader().filetype != MachO::MH_DYLIB_STUB)781 return malformedError("LC_ID_DYLIB load command in non-dynamic library "782 "file type");783 *LoadCmd = Load.Ptr;784 return Error::success();785}786 787static Error checkDyldCommand(const MachOObjectFile &Obj,788 const MachOObjectFile::LoadCommandInfo &Load,789 uint32_t LoadCommandIndex, const char *CmdName) {790 if (Load.C.cmdsize < sizeof(MachO::dylinker_command))791 return malformedError("load command " + Twine(LoadCommandIndex) + " " +792 CmdName + " cmdsize too small");793 auto CommandOrErr = getStructOrErr<MachO::dylinker_command>(Obj, Load.Ptr);794 if (!CommandOrErr)795 return CommandOrErr.takeError();796 MachO::dylinker_command D = CommandOrErr.get();797 if (D.name < sizeof(MachO::dylinker_command))798 return malformedError("load command " + Twine(LoadCommandIndex) + " " +799 CmdName + " name.offset field too small, not past "800 "the end of the dylinker_command struct");801 if (D.name >= D.cmdsize)802 return malformedError("load command " + Twine(LoadCommandIndex) + " " +803 CmdName + " name.offset field extends past the end "804 "of the load command");805 // Make sure there is a null between the starting offset of the name and806 // the end of the load command.807 uint32_t i;808 const char *P = (const char *)Load.Ptr;809 for (i = D.name; i < D.cmdsize; i++)810 if (P[i] == '\0')811 break;812 if (i >= D.cmdsize)813 return malformedError("load command " + Twine(LoadCommandIndex) + " " +814 CmdName + " dyld name extends past the end of the "815 "load command");816 return Error::success();817}818 819static Error checkVersCommand(const MachOObjectFile &Obj,820 const MachOObjectFile::LoadCommandInfo &Load,821 uint32_t LoadCommandIndex,822 const char **LoadCmd, const char *CmdName) {823 if (Load.C.cmdsize != sizeof(MachO::version_min_command))824 return malformedError("load command " + Twine(LoadCommandIndex) + " " +825 CmdName + " has incorrect cmdsize");826 if (*LoadCmd != nullptr)827 return malformedError("more than one LC_VERSION_MIN_MACOSX, "828 "LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_TVOS or "829 "LC_VERSION_MIN_WATCHOS command");830 *LoadCmd = Load.Ptr;831 return Error::success();832}833 834static Error checkNoteCommand(const MachOObjectFile &Obj,835 const MachOObjectFile::LoadCommandInfo &Load,836 uint32_t LoadCommandIndex,837 std::list<MachOElement> &Elements) {838 if (Load.C.cmdsize != sizeof(MachO::note_command))839 return malformedError("load command " + Twine(LoadCommandIndex) +840 " LC_NOTE has incorrect cmdsize");841 auto NoteCmdOrErr = getStructOrErr<MachO::note_command>(Obj, Load.Ptr);842 if (!NoteCmdOrErr)843 return NoteCmdOrErr.takeError();844 MachO::note_command Nt = NoteCmdOrErr.get();845 uint64_t FileSize = Obj.getData().size();846 if (Nt.offset > FileSize)847 return malformedError("offset field of LC_NOTE command " +848 Twine(LoadCommandIndex) + " extends "849 "past the end of the file");850 uint64_t BigSize = Nt.offset;851 BigSize += Nt.size;852 if (BigSize > FileSize)853 return malformedError("size field plus offset field of LC_NOTE command " +854 Twine(LoadCommandIndex) + " extends past the end of "855 "the file");856 if (Error Err = checkOverlappingElement(Elements, Nt.offset, Nt.size,857 "LC_NOTE data"))858 return Err;859 return Error::success();860}861 862static Error863parseBuildVersionCommand(const MachOObjectFile &Obj,864 const MachOObjectFile::LoadCommandInfo &Load,865 SmallVectorImpl<const char*> &BuildTools,866 uint32_t LoadCommandIndex) {867 auto BVCOrErr =868 getStructOrErr<MachO::build_version_command>(Obj, Load.Ptr);869 if (!BVCOrErr)870 return BVCOrErr.takeError();871 MachO::build_version_command BVC = BVCOrErr.get();872 if (Load.C.cmdsize !=873 sizeof(MachO::build_version_command) +874 BVC.ntools * sizeof(MachO::build_tool_version))875 return malformedError("load command " + Twine(LoadCommandIndex) +876 " LC_BUILD_VERSION_COMMAND has incorrect cmdsize");877 878 auto Start = Load.Ptr + sizeof(MachO::build_version_command);879 BuildTools.resize(BVC.ntools);880 for (unsigned i = 0; i < BVC.ntools; ++i)881 BuildTools[i] = Start + i * sizeof(MachO::build_tool_version);882 883 return Error::success();884}885 886static Error checkRpathCommand(const MachOObjectFile &Obj,887 const MachOObjectFile::LoadCommandInfo &Load,888 uint32_t LoadCommandIndex) {889 if (Load.C.cmdsize < sizeof(MachO::rpath_command))890 return malformedError("load command " + Twine(LoadCommandIndex) +891 " LC_RPATH cmdsize too small");892 auto ROrErr = getStructOrErr<MachO::rpath_command>(Obj, Load.Ptr);893 if (!ROrErr)894 return ROrErr.takeError();895 MachO::rpath_command R = ROrErr.get();896 if (R.path < sizeof(MachO::rpath_command))897 return malformedError("load command " + Twine(LoadCommandIndex) +898 " LC_RPATH path.offset field too small, not past "899 "the end of the rpath_command struct");900 if (R.path >= R.cmdsize)901 return malformedError("load command " + Twine(LoadCommandIndex) +902 " LC_RPATH path.offset field extends past the end "903 "of the load command");904 // Make sure there is a null between the starting offset of the path and905 // the end of the load command.906 uint32_t i;907 const char *P = (const char *)Load.Ptr;908 for (i = R.path; i < R.cmdsize; i++)909 if (P[i] == '\0')910 break;911 if (i >= R.cmdsize)912 return malformedError("load command " + Twine(LoadCommandIndex) +913 " LC_RPATH library name extends past the end of the "914 "load command");915 return Error::success();916}917 918static Error checkEncryptCommand(const MachOObjectFile &Obj,919 const MachOObjectFile::LoadCommandInfo &Load,920 uint32_t LoadCommandIndex,921 uint64_t cryptoff, uint64_t cryptsize,922 const char **LoadCmd, const char *CmdName) {923 if (*LoadCmd != nullptr)924 return malformedError("more than one LC_ENCRYPTION_INFO and or "925 "LC_ENCRYPTION_INFO_64 command");926 uint64_t FileSize = Obj.getData().size();927 if (cryptoff > FileSize)928 return malformedError("cryptoff field of " + Twine(CmdName) +929 " command " + Twine(LoadCommandIndex) + " extends "930 "past the end of the file");931 uint64_t BigSize = cryptoff;932 BigSize += cryptsize;933 if (BigSize > FileSize)934 return malformedError("cryptoff field plus cryptsize field of " +935 Twine(CmdName) + " command " +936 Twine(LoadCommandIndex) + " extends past the end of "937 "the file");938 *LoadCmd = Load.Ptr;939 return Error::success();940}941 942static Error checkLinkerOptCommand(const MachOObjectFile &Obj,943 const MachOObjectFile::LoadCommandInfo &Load,944 uint32_t LoadCommandIndex) {945 if (Load.C.cmdsize < sizeof(MachO::linker_option_command))946 return malformedError("load command " + Twine(LoadCommandIndex) +947 " LC_LINKER_OPTION cmdsize too small");948 auto LinkOptionOrErr =949 getStructOrErr<MachO::linker_option_command>(Obj, Load.Ptr);950 if (!LinkOptionOrErr)951 return LinkOptionOrErr.takeError();952 MachO::linker_option_command L = LinkOptionOrErr.get();953 // Make sure the count of strings is correct.954 const char *string = (const char *)Load.Ptr +955 sizeof(struct MachO::linker_option_command);956 uint32_t left = L.cmdsize - sizeof(struct MachO::linker_option_command);957 uint32_t i = 0;958 while (left > 0) {959 while (*string == '\0' && left > 0) {960 string++;961 left--;962 }963 if (left > 0) {964 i++;965 uint32_t NullPos = StringRef(string, left).find('\0');966 if (0xffffffff == NullPos)967 return malformedError("load command " + Twine(LoadCommandIndex) +968 " LC_LINKER_OPTION string #" + Twine(i) +969 " is not NULL terminated");970 uint32_t len = std::min(NullPos, left) + 1;971 string += len;972 left -= len;973 }974 }975 if (L.count != i)976 return malformedError("load command " + Twine(LoadCommandIndex) +977 " LC_LINKER_OPTION string count " + Twine(L.count) +978 " does not match number of strings");979 return Error::success();980}981 982static Error checkSubCommand(const MachOObjectFile &Obj,983 const MachOObjectFile::LoadCommandInfo &Load,984 uint32_t LoadCommandIndex, const char *CmdName,985 size_t SizeOfCmd, const char *CmdStructName,986 uint32_t PathOffset, const char *PathFieldName) {987 if (PathOffset < SizeOfCmd)988 return malformedError("load command " + Twine(LoadCommandIndex) + " " +989 CmdName + " " + PathFieldName + ".offset field too "990 "small, not past the end of the " + CmdStructName);991 if (PathOffset >= Load.C.cmdsize)992 return malformedError("load command " + Twine(LoadCommandIndex) + " " +993 CmdName + " " + PathFieldName + ".offset field "994 "extends past the end of the load command");995 // Make sure there is a null between the starting offset of the path and996 // the end of the load command.997 uint32_t i;998 const char *P = (const char *)Load.Ptr;999 for (i = PathOffset; i < Load.C.cmdsize; i++)1000 if (P[i] == '\0')1001 break;1002 if (i >= Load.C.cmdsize)1003 return malformedError("load command " + Twine(LoadCommandIndex) + " " +1004 CmdName + " " + PathFieldName + " name extends past "1005 "the end of the load command");1006 return Error::success();1007}1008 1009static Error checkThreadCommand(const MachOObjectFile &Obj,1010 const MachOObjectFile::LoadCommandInfo &Load,1011 uint32_t LoadCommandIndex,1012 const char *CmdName) {1013 if (Load.C.cmdsize < sizeof(MachO::thread_command))1014 return malformedError("load command " + Twine(LoadCommandIndex) +1015 CmdName + " cmdsize too small");1016 auto ThreadCommandOrErr =1017 getStructOrErr<MachO::thread_command>(Obj, Load.Ptr);1018 if (!ThreadCommandOrErr)1019 return ThreadCommandOrErr.takeError();1020 MachO::thread_command T = ThreadCommandOrErr.get();1021 const char *state = Load.Ptr + sizeof(MachO::thread_command);1022 const char *end = Load.Ptr + T.cmdsize;1023 uint32_t nflavor = 0;1024 uint32_t cputype = getCPUType(Obj);1025 while (state < end) {1026 if(state + sizeof(uint32_t) > end)1027 return malformedError("load command " + Twine(LoadCommandIndex) +1028 "flavor in " + CmdName + " extends past end of "1029 "command");1030 uint32_t flavor;1031 memcpy(&flavor, state, sizeof(uint32_t));1032 if (Obj.isLittleEndian() != sys::IsLittleEndianHost)1033 sys::swapByteOrder(flavor);1034 state += sizeof(uint32_t);1035 1036 if(state + sizeof(uint32_t) > end)1037 return malformedError("load command " + Twine(LoadCommandIndex) +1038 " count in " + CmdName + " extends past end of "1039 "command");1040 uint32_t count;1041 memcpy(&count, state, sizeof(uint32_t));1042 if (Obj.isLittleEndian() != sys::IsLittleEndianHost)1043 sys::swapByteOrder(count);1044 state += sizeof(uint32_t);1045 1046 if (cputype == MachO::CPU_TYPE_I386) {1047 if (flavor == MachO::x86_THREAD_STATE32) {1048 if (count != MachO::x86_THREAD_STATE32_COUNT)1049 return malformedError("load command " + Twine(LoadCommandIndex) +1050 " count not x86_THREAD_STATE32_COUNT for "1051 "flavor number " + Twine(nflavor) + " which is "1052 "a x86_THREAD_STATE32 flavor in " + CmdName +1053 " command");1054 if (state + sizeof(MachO::x86_thread_state32_t) > end)1055 return malformedError("load command " + Twine(LoadCommandIndex) +1056 " x86_THREAD_STATE32 extends past end of "1057 "command in " + CmdName + " command");1058 state += sizeof(MachO::x86_thread_state32_t);1059 } else {1060 return malformedError("load command " + Twine(LoadCommandIndex) +1061 " unknown flavor (" + Twine(flavor) + ") for "1062 "flavor number " + Twine(nflavor) + " in " +1063 CmdName + " command");1064 }1065 } else if (cputype == MachO::CPU_TYPE_X86_64) {1066 if (flavor == MachO::x86_THREAD_STATE) {1067 if (count != MachO::x86_THREAD_STATE_COUNT)1068 return malformedError("load command " + Twine(LoadCommandIndex) +1069 " count not x86_THREAD_STATE_COUNT for "1070 "flavor number " + Twine(nflavor) + " which is "1071 "a x86_THREAD_STATE flavor in " + CmdName +1072 " command");1073 if (state + sizeof(MachO::x86_thread_state_t) > end)1074 return malformedError("load command " + Twine(LoadCommandIndex) +1075 " x86_THREAD_STATE extends past end of "1076 "command in " + CmdName + " command");1077 state += sizeof(MachO::x86_thread_state_t);1078 } else if (flavor == MachO::x86_FLOAT_STATE) {1079 if (count != MachO::x86_FLOAT_STATE_COUNT)1080 return malformedError("load command " + Twine(LoadCommandIndex) +1081 " count not x86_FLOAT_STATE_COUNT for "1082 "flavor number " + Twine(nflavor) + " which is "1083 "a x86_FLOAT_STATE flavor in " + CmdName +1084 " command");1085 if (state + sizeof(MachO::x86_float_state_t) > end)1086 return malformedError("load command " + Twine(LoadCommandIndex) +1087 " x86_FLOAT_STATE extends past end of "1088 "command in " + CmdName + " command");1089 state += sizeof(MachO::x86_float_state_t);1090 } else if (flavor == MachO::x86_EXCEPTION_STATE) {1091 if (count != MachO::x86_EXCEPTION_STATE_COUNT)1092 return malformedError("load command " + Twine(LoadCommandIndex) +1093 " count not x86_EXCEPTION_STATE_COUNT for "1094 "flavor number " + Twine(nflavor) + " which is "1095 "a x86_EXCEPTION_STATE flavor in " + CmdName +1096 " command");1097 if (state + sizeof(MachO::x86_exception_state_t) > end)1098 return malformedError("load command " + Twine(LoadCommandIndex) +1099 " x86_EXCEPTION_STATE extends past end of "1100 "command in " + CmdName + " command");1101 state += sizeof(MachO::x86_exception_state_t);1102 } else if (flavor == MachO::x86_THREAD_STATE64) {1103 if (count != MachO::x86_THREAD_STATE64_COUNT)1104 return malformedError("load command " + Twine(LoadCommandIndex) +1105 " count not x86_THREAD_STATE64_COUNT for "1106 "flavor number " + Twine(nflavor) + " which is "1107 "a x86_THREAD_STATE64 flavor in " + CmdName +1108 " command");1109 if (state + sizeof(MachO::x86_thread_state64_t) > end)1110 return malformedError("load command " + Twine(LoadCommandIndex) +1111 " x86_THREAD_STATE64 extends past end of "1112 "command in " + CmdName + " command");1113 state += sizeof(MachO::x86_thread_state64_t);1114 } else if (flavor == MachO::x86_EXCEPTION_STATE64) {1115 if (count != MachO::x86_EXCEPTION_STATE64_COUNT)1116 return malformedError("load command " + Twine(LoadCommandIndex) +1117 " count not x86_EXCEPTION_STATE64_COUNT for "1118 "flavor number " + Twine(nflavor) + " which is "1119 "a x86_EXCEPTION_STATE64 flavor in " + CmdName +1120 " command");1121 if (state + sizeof(MachO::x86_exception_state64_t) > end)1122 return malformedError("load command " + Twine(LoadCommandIndex) +1123 " x86_EXCEPTION_STATE64 extends past end of "1124 "command in " + CmdName + " command");1125 state += sizeof(MachO::x86_exception_state64_t);1126 } else {1127 return malformedError("load command " + Twine(LoadCommandIndex) +1128 " unknown flavor (" + Twine(flavor) + ") for "1129 "flavor number " + Twine(nflavor) + " in " +1130 CmdName + " command");1131 }1132 } else if (cputype == MachO::CPU_TYPE_ARM) {1133 if (flavor == MachO::ARM_THREAD_STATE) {1134 if (count != MachO::ARM_THREAD_STATE_COUNT)1135 return malformedError("load command " + Twine(LoadCommandIndex) +1136 " count not ARM_THREAD_STATE_COUNT for "1137 "flavor number " + Twine(nflavor) + " which is "1138 "a ARM_THREAD_STATE flavor in " + CmdName +1139 " command");1140 if (state + sizeof(MachO::arm_thread_state32_t) > end)1141 return malformedError("load command " + Twine(LoadCommandIndex) +1142 " ARM_THREAD_STATE extends past end of "1143 "command in " + CmdName + " command");1144 state += sizeof(MachO::arm_thread_state32_t);1145 } else {1146 return malformedError("load command " + Twine(LoadCommandIndex) +1147 " unknown flavor (" + Twine(flavor) + ") for "1148 "flavor number " + Twine(nflavor) + " in " +1149 CmdName + " command");1150 }1151 } else if (cputype == MachO::CPU_TYPE_ARM64 ||1152 cputype == MachO::CPU_TYPE_ARM64_32) {1153 if (flavor == MachO::ARM_THREAD_STATE64) {1154 if (count != MachO::ARM_THREAD_STATE64_COUNT)1155 return malformedError("load command " + Twine(LoadCommandIndex) +1156 " count not ARM_THREAD_STATE64_COUNT for "1157 "flavor number " + Twine(nflavor) + " which is "1158 "a ARM_THREAD_STATE64 flavor in " + CmdName +1159 " command");1160 if (state + sizeof(MachO::arm_thread_state64_t) > end)1161 return malformedError("load command " + Twine(LoadCommandIndex) +1162 " ARM_THREAD_STATE64 extends past end of "1163 "command in " + CmdName + " command");1164 state += sizeof(MachO::arm_thread_state64_t);1165 } else {1166 return malformedError("load command " + Twine(LoadCommandIndex) +1167 " unknown flavor (" + Twine(flavor) + ") for "1168 "flavor number " + Twine(nflavor) + " in " +1169 CmdName + " command");1170 }1171 } else if (cputype == MachO::CPU_TYPE_POWERPC) {1172 if (flavor == MachO::PPC_THREAD_STATE) {1173 if (count != MachO::PPC_THREAD_STATE_COUNT)1174 return malformedError("load command " + Twine(LoadCommandIndex) +1175 " count not PPC_THREAD_STATE_COUNT for "1176 "flavor number " + Twine(nflavor) + " which is "1177 "a PPC_THREAD_STATE flavor in " + CmdName +1178 " command");1179 if (state + sizeof(MachO::ppc_thread_state32_t) > end)1180 return malformedError("load command " + Twine(LoadCommandIndex) +1181 " PPC_THREAD_STATE extends past end of "1182 "command in " + CmdName + " command");1183 state += sizeof(MachO::ppc_thread_state32_t);1184 } else {1185 return malformedError("load command " + Twine(LoadCommandIndex) +1186 " unknown flavor (" + Twine(flavor) + ") for "1187 "flavor number " + Twine(nflavor) + " in " +1188 CmdName + " command");1189 }1190 } else {1191 return malformedError("unknown cputype (" + Twine(cputype) + ") load "1192 "command " + Twine(LoadCommandIndex) + " for " +1193 CmdName + " command can't be checked");1194 }1195 nflavor++;1196 }1197 return Error::success();1198}1199 1200static Error checkTwoLevelHintsCommand(const MachOObjectFile &Obj,1201 const MachOObjectFile::LoadCommandInfo1202 &Load,1203 uint32_t LoadCommandIndex,1204 const char **LoadCmd,1205 std::list<MachOElement> &Elements) {1206 if (Load.C.cmdsize != sizeof(MachO::twolevel_hints_command))1207 return malformedError("load command " + Twine(LoadCommandIndex) +1208 " LC_TWOLEVEL_HINTS has incorrect cmdsize");1209 if (*LoadCmd != nullptr)1210 return malformedError("more than one LC_TWOLEVEL_HINTS command");1211 auto HintsOrErr = getStructOrErr<MachO::twolevel_hints_command>(Obj, Load.Ptr);1212 if(!HintsOrErr)1213 return HintsOrErr.takeError();1214 MachO::twolevel_hints_command Hints = HintsOrErr.get();1215 uint64_t FileSize = Obj.getData().size();1216 if (Hints.offset > FileSize)1217 return malformedError("offset field of LC_TWOLEVEL_HINTS command " +1218 Twine(LoadCommandIndex) + " extends past the end of "1219 "the file");1220 uint64_t BigSize = Hints.nhints;1221 BigSize *= sizeof(MachO::twolevel_hint);1222 BigSize += Hints.offset;1223 if (BigSize > FileSize)1224 return malformedError("offset field plus nhints times sizeof(struct "1225 "twolevel_hint) field of LC_TWOLEVEL_HINTS command " +1226 Twine(LoadCommandIndex) + " extends past the end of "1227 "the file");1228 if (Error Err = checkOverlappingElement(Elements, Hints.offset, Hints.nhints *1229 sizeof(MachO::twolevel_hint),1230 "two level hints"))1231 return Err;1232 *LoadCmd = Load.Ptr;1233 return Error::success();1234}1235 1236// Returns true if the libObject code does not support the load command and its1237// contents. The cmd value it is treated as an unknown load command but with1238// an error message that says the cmd value is obsolete.1239static bool isLoadCommandObsolete(uint32_t cmd) {1240 if (cmd == MachO::LC_SYMSEG ||1241 cmd == MachO::LC_LOADFVMLIB ||1242 cmd == MachO::LC_IDFVMLIB ||1243 cmd == MachO::LC_IDENT ||1244 cmd == MachO::LC_FVMFILE ||1245 cmd == MachO::LC_PREPAGE ||1246 cmd == MachO::LC_PREBOUND_DYLIB ||1247 cmd == MachO::LC_TWOLEVEL_HINTS ||1248 cmd == MachO::LC_PREBIND_CKSUM)1249 return true;1250 return false;1251}1252 1253Expected<std::unique_ptr<MachOObjectFile>>1254MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian,1255 bool Is64Bits, uint32_t UniversalCputype,1256 uint32_t UniversalIndex,1257 size_t MachOFilesetEntryOffset) {1258 Error Err = Error::success();1259 std::unique_ptr<MachOObjectFile> Obj(new MachOObjectFile(1260 std::move(Object), IsLittleEndian, Is64Bits, Err, UniversalCputype,1261 UniversalIndex, MachOFilesetEntryOffset));1262 if (Err)1263 return std::move(Err);1264 return std::move(Obj);1265}1266 1267MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,1268 bool Is64bits, Error &Err,1269 uint32_t UniversalCputype,1270 uint32_t UniversalIndex,1271 size_t MachOFilesetEntryOffset)1272 : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object),1273 MachOFilesetEntryOffset(MachOFilesetEntryOffset) {1274 ErrorAsOutParameter ErrAsOutParam(Err);1275 uint64_t SizeOfHeaders;1276 uint32_t cputype;1277 if (is64Bit()) {1278 parseHeader(*this, Header64, Err);1279 SizeOfHeaders = sizeof(MachO::mach_header_64);1280 cputype = Header64.cputype;1281 } else {1282 parseHeader(*this, Header, Err);1283 SizeOfHeaders = sizeof(MachO::mach_header);1284 cputype = Header.cputype;1285 }1286 if (Err)1287 return;1288 SizeOfHeaders += getHeader().sizeofcmds;1289 if (getData().data() + SizeOfHeaders > getData().end()) {1290 Err = malformedError("load commands extend past the end of the file");1291 return;1292 }1293 if (UniversalCputype != 0 && cputype != UniversalCputype) {1294 Err = malformedError("universal header architecture: " +1295 Twine(UniversalIndex) + "'s cputype does not match "1296 "object file's mach header");1297 return;1298 }1299 std::list<MachOElement> Elements;1300 Elements.push_back({0, SizeOfHeaders, "Mach-O headers"});1301 1302 uint32_t LoadCommandCount = getHeader().ncmds;1303 LoadCommandInfo Load;1304 if (LoadCommandCount != 0) {1305 if (auto LoadOrErr = getFirstLoadCommandInfo(*this))1306 Load = *LoadOrErr;1307 else {1308 Err = LoadOrErr.takeError();1309 return;1310 }1311 }1312 1313 const char *DyldIdLoadCmd = nullptr;1314 const char *SplitInfoLoadCmd = nullptr;1315 const char *CodeSignDrsLoadCmd = nullptr;1316 const char *CodeSignLoadCmd = nullptr;1317 const char *VersLoadCmd = nullptr;1318 const char *SourceLoadCmd = nullptr;1319 const char *EntryPointLoadCmd = nullptr;1320 const char *EncryptLoadCmd = nullptr;1321 const char *RoutinesLoadCmd = nullptr;1322 const char *UnixThreadLoadCmd = nullptr;1323 const char *TwoLevelHintsLoadCmd = nullptr;1324 for (unsigned I = 0; I < LoadCommandCount; ++I) {1325 if (is64Bit()) {1326 if (Load.C.cmdsize % 8 != 0) {1327 // We have a hack here to allow 64-bit Mach-O core files to have1328 // LC_THREAD commands that are only a multiple of 4 and not 8 to be1329 // allowed since the macOS kernel produces them.1330 if (getHeader().filetype != MachO::MH_CORE ||1331 Load.C.cmd != MachO::LC_THREAD || Load.C.cmdsize % 4) {1332 Err = malformedError("load command " + Twine(I) + " cmdsize not a "1333 "multiple of 8");1334 return;1335 }1336 }1337 } else {1338 if (Load.C.cmdsize % 4 != 0) {1339 Err = malformedError("load command " + Twine(I) + " cmdsize not a "1340 "multiple of 4");1341 return;1342 }1343 }1344 LoadCommands.push_back(Load);1345 if (Load.C.cmd == MachO::LC_SYMTAB) {1346 if ((Err = checkSymtabCommand(*this, Load, I, &SymtabLoadCmd, Elements)))1347 return;1348 } else if (Load.C.cmd == MachO::LC_DYSYMTAB) {1349 if ((Err = checkDysymtabCommand(*this, Load, I, &DysymtabLoadCmd,1350 Elements)))1351 return;1352 } else if (Load.C.cmd == MachO::LC_DATA_IN_CODE) {1353 if ((Err = checkLinkeditDataCommand(*this, Load, I, &DataInCodeLoadCmd,1354 "LC_DATA_IN_CODE", Elements,1355 "data in code info")))1356 return;1357 } else if (Load.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT) {1358 if ((Err = checkLinkeditDataCommand(*this, Load, I, &LinkOptHintsLoadCmd,1359 "LC_LINKER_OPTIMIZATION_HINT",1360 Elements, "linker optimization "1361 "hints")))1362 return;1363 } else if (Load.C.cmd == MachO::LC_FUNCTION_STARTS) {1364 if ((Err = checkLinkeditDataCommand(*this, Load, I, &FuncStartsLoadCmd,1365 "LC_FUNCTION_STARTS", Elements,1366 "function starts data")))1367 return;1368 } else if (Load.C.cmd == MachO::LC_SEGMENT_SPLIT_INFO) {1369 if ((Err = checkLinkeditDataCommand(*this, Load, I, &SplitInfoLoadCmd,1370 "LC_SEGMENT_SPLIT_INFO", Elements,1371 "split info data")))1372 return;1373 } else if (Load.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS) {1374 if ((Err = checkLinkeditDataCommand(*this, Load, I, &CodeSignDrsLoadCmd,1375 "LC_DYLIB_CODE_SIGN_DRS", Elements,1376 "code signing RDs data")))1377 return;1378 } else if (Load.C.cmd == MachO::LC_CODE_SIGNATURE) {1379 if ((Err = checkLinkeditDataCommand(*this, Load, I, &CodeSignLoadCmd,1380 "LC_CODE_SIGNATURE", Elements,1381 "code signature data")))1382 return;1383 } else if (Load.C.cmd == MachO::LC_DYLD_INFO) {1384 if ((Err = checkDyldInfoCommand(*this, Load, I, &DyldInfoLoadCmd,1385 "LC_DYLD_INFO", Elements)))1386 return;1387 } else if (Load.C.cmd == MachO::LC_DYLD_INFO_ONLY) {1388 if ((Err = checkDyldInfoCommand(*this, Load, I, &DyldInfoLoadCmd,1389 "LC_DYLD_INFO_ONLY", Elements)))1390 return;1391 } else if (Load.C.cmd == MachO::LC_DYLD_CHAINED_FIXUPS) {1392 if ((Err = checkLinkeditDataCommand(1393 *this, Load, I, &DyldChainedFixupsLoadCmd,1394 "LC_DYLD_CHAINED_FIXUPS", Elements, "chained fixups")))1395 return;1396 } else if (Load.C.cmd == MachO::LC_DYLD_EXPORTS_TRIE) {1397 if ((Err = checkLinkeditDataCommand(1398 *this, Load, I, &DyldExportsTrieLoadCmd, "LC_DYLD_EXPORTS_TRIE",1399 Elements, "exports trie")))1400 return;1401 } else if (Load.C.cmd == MachO::LC_UUID) {1402 if (Load.C.cmdsize != sizeof(MachO::uuid_command)) {1403 Err = malformedError("LC_UUID command " + Twine(I) + " has incorrect "1404 "cmdsize");1405 return;1406 }1407 if (UuidLoadCmd) {1408 Err = malformedError("more than one LC_UUID command");1409 return;1410 }1411 UuidLoadCmd = Load.Ptr;1412 } else if (Load.C.cmd == MachO::LC_SEGMENT_64) {1413 if ((Err = parseSegmentLoadCommand<MachO::segment_command_64,1414 MachO::section_64>(1415 *this, Load, Sections, HasPageZeroSegment, I,1416 "LC_SEGMENT_64", SizeOfHeaders, Elements)))1417 return;1418 } else if (Load.C.cmd == MachO::LC_SEGMENT) {1419 if ((Err = parseSegmentLoadCommand<MachO::segment_command,1420 MachO::section>(1421 *this, Load, Sections, HasPageZeroSegment, I,1422 "LC_SEGMENT", SizeOfHeaders, Elements)))1423 return;1424 } else if (Load.C.cmd == MachO::LC_ID_DYLIB) {1425 if ((Err = checkDylibIdCommand(*this, Load, I, &DyldIdLoadCmd)))1426 return;1427 } else if (Load.C.cmd == MachO::LC_LOAD_DYLIB) {1428 if ((Err = checkDylibCommand(*this, Load, I, "LC_LOAD_DYLIB")))1429 return;1430 Libraries.push_back(Load.Ptr);1431 } else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB) {1432 if ((Err = checkDylibCommand(*this, Load, I, "LC_LOAD_WEAK_DYLIB")))1433 return;1434 Libraries.push_back(Load.Ptr);1435 } else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB) {1436 if ((Err = checkDylibCommand(*this, Load, I, "LC_LAZY_LOAD_DYLIB")))1437 return;1438 Libraries.push_back(Load.Ptr);1439 } else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB) {1440 if ((Err = checkDylibCommand(*this, Load, I, "LC_REEXPORT_DYLIB")))1441 return;1442 Libraries.push_back(Load.Ptr);1443 } else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {1444 if ((Err = checkDylibCommand(*this, Load, I, "LC_LOAD_UPWARD_DYLIB")))1445 return;1446 Libraries.push_back(Load.Ptr);1447 } else if (Load.C.cmd == MachO::LC_ID_DYLINKER) {1448 if ((Err = checkDyldCommand(*this, Load, I, "LC_ID_DYLINKER")))1449 return;1450 } else if (Load.C.cmd == MachO::LC_LOAD_DYLINKER) {1451 if ((Err = checkDyldCommand(*this, Load, I, "LC_LOAD_DYLINKER")))1452 return;1453 } else if (Load.C.cmd == MachO::LC_DYLD_ENVIRONMENT) {1454 if ((Err = checkDyldCommand(*this, Load, I, "LC_DYLD_ENVIRONMENT")))1455 return;1456 } else if (Load.C.cmd == MachO::LC_VERSION_MIN_MACOSX) {1457 if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,1458 "LC_VERSION_MIN_MACOSX")))1459 return;1460 } else if (Load.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS) {1461 if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,1462 "LC_VERSION_MIN_IPHONEOS")))1463 return;1464 } else if (Load.C.cmd == MachO::LC_VERSION_MIN_TVOS) {1465 if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,1466 "LC_VERSION_MIN_TVOS")))1467 return;1468 } else if (Load.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) {1469 if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,1470 "LC_VERSION_MIN_WATCHOS")))1471 return;1472 } else if (Load.C.cmd == MachO::LC_NOTE) {1473 if ((Err = checkNoteCommand(*this, Load, I, Elements)))1474 return;1475 } else if (Load.C.cmd == MachO::LC_BUILD_VERSION) {1476 if ((Err = parseBuildVersionCommand(*this, Load, BuildTools, I)))1477 return;1478 } else if (Load.C.cmd == MachO::LC_RPATH) {1479 if ((Err = checkRpathCommand(*this, Load, I)))1480 return;1481 } else if (Load.C.cmd == MachO::LC_SOURCE_VERSION) {1482 if (Load.C.cmdsize != sizeof(MachO::source_version_command)) {1483 Err = malformedError("LC_SOURCE_VERSION command " + Twine(I) +1484 " has incorrect cmdsize");1485 return;1486 }1487 if (SourceLoadCmd) {1488 Err = malformedError("more than one LC_SOURCE_VERSION command");1489 return;1490 }1491 SourceLoadCmd = Load.Ptr;1492 } else if (Load.C.cmd == MachO::LC_MAIN) {1493 if (Load.C.cmdsize != sizeof(MachO::entry_point_command)) {1494 Err = malformedError("LC_MAIN command " + Twine(I) +1495 " has incorrect cmdsize");1496 return;1497 }1498 if (EntryPointLoadCmd) {1499 Err = malformedError("more than one LC_MAIN command");1500 return;1501 }1502 EntryPointLoadCmd = Load.Ptr;1503 } else if (Load.C.cmd == MachO::LC_ENCRYPTION_INFO) {1504 if (Load.C.cmdsize != sizeof(MachO::encryption_info_command)) {1505 Err = malformedError("LC_ENCRYPTION_INFO command " + Twine(I) +1506 " has incorrect cmdsize");1507 return;1508 }1509 MachO::encryption_info_command E =1510 getStruct<MachO::encryption_info_command>(*this, Load.Ptr);1511 if ((Err = checkEncryptCommand(*this, Load, I, E.cryptoff, E.cryptsize,1512 &EncryptLoadCmd, "LC_ENCRYPTION_INFO")))1513 return;1514 } else if (Load.C.cmd == MachO::LC_ENCRYPTION_INFO_64) {1515 if (Load.C.cmdsize != sizeof(MachO::encryption_info_command_64)) {1516 Err = malformedError("LC_ENCRYPTION_INFO_64 command " + Twine(I) +1517 " has incorrect cmdsize");1518 return;1519 }1520 MachO::encryption_info_command_64 E =1521 getStruct<MachO::encryption_info_command_64>(*this, Load.Ptr);1522 if ((Err = checkEncryptCommand(*this, Load, I, E.cryptoff, E.cryptsize,1523 &EncryptLoadCmd, "LC_ENCRYPTION_INFO_64")))1524 return;1525 } else if (Load.C.cmd == MachO::LC_LINKER_OPTION) {1526 if ((Err = checkLinkerOptCommand(*this, Load, I)))1527 return;1528 } else if (Load.C.cmd == MachO::LC_SUB_FRAMEWORK) {1529 if (Load.C.cmdsize < sizeof(MachO::sub_framework_command)) {1530 Err = malformedError("load command " + Twine(I) +1531 " LC_SUB_FRAMEWORK cmdsize too small");1532 return;1533 }1534 MachO::sub_framework_command S =1535 getStruct<MachO::sub_framework_command>(*this, Load.Ptr);1536 if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_FRAMEWORK",1537 sizeof(MachO::sub_framework_command),1538 "sub_framework_command", S.umbrella,1539 "umbrella")))1540 return;1541 } else if (Load.C.cmd == MachO::LC_SUB_UMBRELLA) {1542 if (Load.C.cmdsize < sizeof(MachO::sub_umbrella_command)) {1543 Err = malformedError("load command " + Twine(I) +1544 " LC_SUB_UMBRELLA cmdsize too small");1545 return;1546 }1547 MachO::sub_umbrella_command S =1548 getStruct<MachO::sub_umbrella_command>(*this, Load.Ptr);1549 if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_UMBRELLA",1550 sizeof(MachO::sub_umbrella_command),1551 "sub_umbrella_command", S.sub_umbrella,1552 "sub_umbrella")))1553 return;1554 } else if (Load.C.cmd == MachO::LC_SUB_LIBRARY) {1555 if (Load.C.cmdsize < sizeof(MachO::sub_library_command)) {1556 Err = malformedError("load command " + Twine(I) +1557 " LC_SUB_LIBRARY cmdsize too small");1558 return;1559 }1560 MachO::sub_library_command S =1561 getStruct<MachO::sub_library_command>(*this, Load.Ptr);1562 if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_LIBRARY",1563 sizeof(MachO::sub_library_command),1564 "sub_library_command", S.sub_library,1565 "sub_library")))1566 return;1567 } else if (Load.C.cmd == MachO::LC_SUB_CLIENT) {1568 if (Load.C.cmdsize < sizeof(MachO::sub_client_command)) {1569 Err = malformedError("load command " + Twine(I) +1570 " LC_SUB_CLIENT cmdsize too small");1571 return;1572 }1573 MachO::sub_client_command S =1574 getStruct<MachO::sub_client_command>(*this, Load.Ptr);1575 if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_CLIENT",1576 sizeof(MachO::sub_client_command),1577 "sub_client_command", S.client, "client")))1578 return;1579 } else if (Load.C.cmd == MachO::LC_ROUTINES) {1580 if (Load.C.cmdsize != sizeof(MachO::routines_command)) {1581 Err = malformedError("LC_ROUTINES command " + Twine(I) +1582 " has incorrect cmdsize");1583 return;1584 }1585 if (RoutinesLoadCmd) {1586 Err = malformedError("more than one LC_ROUTINES and or LC_ROUTINES_64 "1587 "command");1588 return;1589 }1590 RoutinesLoadCmd = Load.Ptr;1591 } else if (Load.C.cmd == MachO::LC_ROUTINES_64) {1592 if (Load.C.cmdsize != sizeof(MachO::routines_command_64)) {1593 Err = malformedError("LC_ROUTINES_64 command " + Twine(I) +1594 " has incorrect cmdsize");1595 return;1596 }1597 if (RoutinesLoadCmd) {1598 Err = malformedError("more than one LC_ROUTINES_64 and or LC_ROUTINES "1599 "command");1600 return;1601 }1602 RoutinesLoadCmd = Load.Ptr;1603 } else if (Load.C.cmd == MachO::LC_UNIXTHREAD) {1604 if ((Err = checkThreadCommand(*this, Load, I, "LC_UNIXTHREAD")))1605 return;1606 if (UnixThreadLoadCmd) {1607 Err = malformedError("more than one LC_UNIXTHREAD command");1608 return;1609 }1610 UnixThreadLoadCmd = Load.Ptr;1611 } else if (Load.C.cmd == MachO::LC_THREAD) {1612 if ((Err = checkThreadCommand(*this, Load, I, "LC_THREAD")))1613 return;1614 // Note: LC_TWOLEVEL_HINTS is really obsolete and is not supported.1615 } else if (Load.C.cmd == MachO::LC_TWOLEVEL_HINTS) {1616 if ((Err = checkTwoLevelHintsCommand(*this, Load, I,1617 &TwoLevelHintsLoadCmd, Elements)))1618 return;1619 } else if (Load.C.cmd == MachO::LC_IDENT) {1620 // Note: LC_IDENT is ignored.1621 continue;1622 } else if (isLoadCommandObsolete(Load.C.cmd)) {1623 Err = malformedError("load command " + Twine(I) + " for cmd value of: " +1624 Twine(Load.C.cmd) + " is obsolete and not "1625 "supported");1626 return;1627 }1628 // TODO: generate a error for unknown load commands by default. But still1629 // need work out an approach to allow or not allow unknown values like this1630 // as an option for some uses like lldb.1631 if (I < LoadCommandCount - 1) {1632 if (auto LoadOrErr = getNextLoadCommandInfo(*this, I, Load))1633 Load = *LoadOrErr;1634 else {1635 Err = LoadOrErr.takeError();1636 return;1637 }1638 }1639 }1640 if (!SymtabLoadCmd) {1641 if (DysymtabLoadCmd) {1642 Err = malformedError("contains LC_DYSYMTAB load command without a "1643 "LC_SYMTAB load command");1644 return;1645 }1646 } else if (DysymtabLoadCmd) {1647 MachO::symtab_command Symtab =1648 getStruct<MachO::symtab_command>(*this, SymtabLoadCmd);1649 MachO::dysymtab_command Dysymtab =1650 getStruct<MachO::dysymtab_command>(*this, DysymtabLoadCmd);1651 if (Dysymtab.nlocalsym != 0 && Dysymtab.ilocalsym > Symtab.nsyms) {1652 Err = malformedError("ilocalsym in LC_DYSYMTAB load command "1653 "extends past the end of the symbol table");1654 return;1655 }1656 uint64_t BigSize = Dysymtab.ilocalsym;1657 BigSize += Dysymtab.nlocalsym;1658 if (Dysymtab.nlocalsym != 0 && BigSize > Symtab.nsyms) {1659 Err = malformedError("ilocalsym plus nlocalsym in LC_DYSYMTAB load "1660 "command extends past the end of the symbol table");1661 return;1662 }1663 if (Dysymtab.nextdefsym != 0 && Dysymtab.iextdefsym > Symtab.nsyms) {1664 Err = malformedError("iextdefsym in LC_DYSYMTAB load command "1665 "extends past the end of the symbol table");1666 return;1667 }1668 BigSize = Dysymtab.iextdefsym;1669 BigSize += Dysymtab.nextdefsym;1670 if (Dysymtab.nextdefsym != 0 && BigSize > Symtab.nsyms) {1671 Err = malformedError("iextdefsym plus nextdefsym in LC_DYSYMTAB "1672 "load command extends past the end of the symbol "1673 "table");1674 return;1675 }1676 if (Dysymtab.nundefsym != 0 && Dysymtab.iundefsym > Symtab.nsyms) {1677 Err = malformedError("iundefsym in LC_DYSYMTAB load command "1678 "extends past the end of the symbol table");1679 return;1680 }1681 BigSize = Dysymtab.iundefsym;1682 BigSize += Dysymtab.nundefsym;1683 if (Dysymtab.nundefsym != 0 && BigSize > Symtab.nsyms) {1684 Err = malformedError("iundefsym plus nundefsym in LC_DYSYMTAB load "1685 " command extends past the end of the symbol table");1686 return;1687 }1688 }1689 if ((getHeader().filetype == MachO::MH_DYLIB ||1690 getHeader().filetype == MachO::MH_DYLIB_STUB) &&1691 DyldIdLoadCmd == nullptr) {1692 Err = malformedError("no LC_ID_DYLIB load command in dynamic library "1693 "filetype");1694 return;1695 }1696 assert(LoadCommands.size() == LoadCommandCount);1697 1698 Err = Error::success();1699}1700 1701Error MachOObjectFile::checkSymbolTable() const {1702 uint32_t Flags = 0;1703 if (is64Bit()) {1704 MachO::mach_header_64 H_64 = MachOObjectFile::getHeader64();1705 Flags = H_64.flags;1706 } else {1707 MachO::mach_header H = MachOObjectFile::getHeader();1708 Flags = H.flags;1709 }1710 uint8_t NType = 0;1711 uint8_t NSect = 0;1712 uint16_t NDesc = 0;1713 uint32_t NStrx = 0;1714 uint64_t NValue = 0;1715 uint32_t SymbolIndex = 0;1716 MachO::symtab_command S = getSymtabLoadCommand();1717 for (const SymbolRef &Symbol : symbols()) {1718 DataRefImpl SymDRI = Symbol.getRawDataRefImpl();1719 if (is64Bit()) {1720 MachO::nlist_64 STE_64 = getSymbol64TableEntry(SymDRI);1721 NType = STE_64.n_type;1722 NSect = STE_64.n_sect;1723 NDesc = STE_64.n_desc;1724 NStrx = STE_64.n_strx;1725 NValue = STE_64.n_value;1726 } else {1727 MachO::nlist STE = getSymbolTableEntry(SymDRI);1728 NType = STE.n_type;1729 NSect = STE.n_sect;1730 NDesc = STE.n_desc;1731 NStrx = STE.n_strx;1732 NValue = STE.n_value;1733 }1734 if ((NType & MachO::N_STAB) == 0) {1735 if ((NType & MachO::N_TYPE) == MachO::N_SECT) {1736 if (NSect == 0 || NSect > Sections.size())1737 return malformedError("bad section index: " + Twine((int)NSect) +1738 " for symbol at index " + Twine(SymbolIndex));1739 }1740 if ((NType & MachO::N_TYPE) == MachO::N_INDR) {1741 if (NValue >= S.strsize)1742 return malformedError("bad n_value: " + Twine((int)NValue) + " past "1743 "the end of string table, for N_INDR symbol at "1744 "index " + Twine(SymbolIndex));1745 }1746 if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL &&1747 (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) ||1748 (NType & MachO::N_TYPE) == MachO::N_PBUD)) {1749 uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc);1750 if (LibraryOrdinal != 0 &&1751 LibraryOrdinal != MachO::EXECUTABLE_ORDINAL &&1752 LibraryOrdinal != MachO::DYNAMIC_LOOKUP_ORDINAL &&1753 LibraryOrdinal - 1 >= Libraries.size() ) {1754 return malformedError("bad library ordinal: " + Twine(LibraryOrdinal) +1755 " for symbol at index " + Twine(SymbolIndex));1756 }1757 }1758 }1759 if (NStrx >= S.strsize)1760 return malformedError("bad string table index: " + Twine((int)NStrx) +1761 " past the end of string table, for symbol at "1762 "index " + Twine(SymbolIndex));1763 SymbolIndex++;1764 }1765 return Error::success();1766}1767 1768void MachOObjectFile::moveSymbolNext(DataRefImpl &Symb) const {1769 unsigned SymbolTableEntrySize = is64Bit() ?1770 sizeof(MachO::nlist_64) :1771 sizeof(MachO::nlist);1772 Symb.p += SymbolTableEntrySize;1773}1774 1775Expected<StringRef> MachOObjectFile::getSymbolName(DataRefImpl Symb) const {1776 StringRef StringTable = getStringTableData();1777 MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);1778 if (Entry.n_strx == 0)1779 // A n_strx value of 0 indicates that no name is associated with a1780 // particular symbol table entry.1781 return StringRef();1782 const char *Start = &StringTable.data()[Entry.n_strx];1783 if (Start < getData().begin() || Start >= getData().end()) {1784 return malformedError("bad string index: " + Twine(Entry.n_strx) +1785 " for symbol at index " + Twine(getSymbolIndex(Symb)));1786 }1787 return StringRef(Start);1788}1789 1790unsigned MachOObjectFile::getSectionType(SectionRef Sec) const {1791 DataRefImpl DRI = Sec.getRawDataRefImpl();1792 uint32_t Flags = getSectionFlags(*this, DRI);1793 return Flags & MachO::SECTION_TYPE;1794}1795 1796uint64_t MachOObjectFile::getNValue(DataRefImpl Sym) const {1797 if (is64Bit()) {1798 MachO::nlist_64 Entry = getSymbol64TableEntry(Sym);1799 return Entry.n_value;1800 }1801 MachO::nlist Entry = getSymbolTableEntry(Sym);1802 return Entry.n_value;1803}1804 1805// getIndirectName() returns the name of the alias'ed symbol who's string table1806// index is in the n_value field.1807std::error_code MachOObjectFile::getIndirectName(DataRefImpl Symb,1808 StringRef &Res) const {1809 StringRef StringTable = getStringTableData();1810 MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);1811 if ((Entry.n_type & MachO::N_TYPE) != MachO::N_INDR)1812 return object_error::parse_failed;1813 uint64_t NValue = getNValue(Symb);1814 if (NValue >= StringTable.size())1815 return object_error::parse_failed;1816 const char *Start = &StringTable.data()[NValue];1817 Res = StringRef(Start);1818 return std::error_code();1819}1820 1821uint64_t MachOObjectFile::getSymbolValueImpl(DataRefImpl Sym) const {1822 return getNValue(Sym);1823}1824 1825Expected<uint64_t> MachOObjectFile::getSymbolAddress(DataRefImpl Sym) const {1826 return getSymbolValue(Sym);1827}1828 1829uint32_t MachOObjectFile::getSymbolAlignment(DataRefImpl DRI) const {1830 uint32_t Flags = cantFail(getSymbolFlags(DRI));1831 if (Flags & SymbolRef::SF_Common) {1832 MachO::nlist_base Entry = getSymbolTableEntryBase(*this, DRI);1833 return 1 << MachO::GET_COMM_ALIGN(Entry.n_desc);1834 }1835 return 0;1836}1837 1838uint64_t MachOObjectFile::getCommonSymbolSizeImpl(DataRefImpl DRI) const {1839 return getNValue(DRI);1840}1841 1842Expected<SymbolRef::Type>1843MachOObjectFile::getSymbolType(DataRefImpl Symb) const {1844 MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);1845 uint8_t n_type = Entry.n_type;1846 1847 // If this is a STAB debugging symbol, we can do nothing more.1848 if (n_type & MachO::N_STAB)1849 return SymbolRef::ST_Debug;1850 1851 switch (n_type & MachO::N_TYPE) {1852 case MachO::N_UNDF :1853 return SymbolRef::ST_Unknown;1854 case MachO::N_SECT :1855 Expected<section_iterator> SecOrError = getSymbolSection(Symb);1856 if (!SecOrError)1857 return SecOrError.takeError();1858 section_iterator Sec = *SecOrError;1859 if (Sec == section_end())1860 return SymbolRef::ST_Other;1861 if (Sec->isData() || Sec->isBSS())1862 return SymbolRef::ST_Data;1863 return SymbolRef::ST_Function;1864 }1865 return SymbolRef::ST_Other;1866}1867 1868Expected<uint32_t> MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const {1869 MachO::nlist_base Entry = getSymbolTableEntryBase(*this, DRI);1870 1871 uint8_t MachOType = Entry.n_type;1872 uint16_t MachOFlags = Entry.n_desc;1873 1874 uint32_t Result = SymbolRef::SF_None;1875 1876 if ((MachOType & MachO::N_TYPE) == MachO::N_INDR)1877 Result |= SymbolRef::SF_Indirect;1878 1879 if (MachOType & MachO::N_STAB)1880 Result |= SymbolRef::SF_FormatSpecific;1881 1882 if (MachOType & MachO::N_EXT) {1883 Result |= SymbolRef::SF_Global;1884 if ((MachOType & MachO::N_TYPE) == MachO::N_UNDF) {1885 if (getNValue(DRI))1886 Result |= SymbolRef::SF_Common;1887 else1888 Result |= SymbolRef::SF_Undefined;1889 }1890 1891 if (MachOType & MachO::N_PEXT)1892 Result |= SymbolRef::SF_Hidden;1893 else1894 Result |= SymbolRef::SF_Exported;1895 1896 } else if (MachOType & MachO::N_PEXT)1897 Result |= SymbolRef::SF_Hidden;1898 1899 if (MachOFlags & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF))1900 Result |= SymbolRef::SF_Weak;1901 1902 if (MachOFlags & (MachO::N_ARM_THUMB_DEF))1903 Result |= SymbolRef::SF_Thumb;1904 1905 if ((MachOType & MachO::N_TYPE) == MachO::N_ABS)1906 Result |= SymbolRef::SF_Absolute;1907 1908 return Result;1909}1910 1911Expected<section_iterator>1912MachOObjectFile::getSymbolSection(DataRefImpl Symb) const {1913 MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);1914 uint8_t index = Entry.n_sect;1915 1916 if (index == 0)1917 return section_end();1918 DataRefImpl DRI;1919 DRI.d.a = index - 1;1920 if (DRI.d.a >= Sections.size()){1921 return malformedError("bad section index: " + Twine((int)index) +1922 " for symbol at index " + Twine(getSymbolIndex(Symb)));1923 }1924 return section_iterator(SectionRef(DRI, this));1925}1926 1927unsigned MachOObjectFile::getSymbolSectionID(SymbolRef Sym) const {1928 MachO::nlist_base Entry =1929 getSymbolTableEntryBase(*this, Sym.getRawDataRefImpl());1930 return Entry.n_sect - 1;1931}1932 1933void MachOObjectFile::moveSectionNext(DataRefImpl &Sec) const {1934 Sec.d.a++;1935}1936 1937Expected<StringRef> MachOObjectFile::getSectionName(DataRefImpl Sec) const {1938 ArrayRef<char> Raw = getSectionRawName(Sec);1939 return parseSegmentOrSectionName(Raw.data());1940}1941 1942uint64_t MachOObjectFile::getSectionAddress(DataRefImpl Sec) const {1943 if (is64Bit())1944 return getSection64(Sec).addr;1945 return getSection(Sec).addr;1946}1947 1948uint64_t MachOObjectFile::getSectionIndex(DataRefImpl Sec) const {1949 return Sec.d.a;1950}1951 1952uint64_t MachOObjectFile::getSectionSize(DataRefImpl Sec) const {1953 // In the case if a malformed Mach-O file where the section offset is past1954 // the end of the file or some part of the section size is past the end of1955 // the file return a size of zero or a size that covers the rest of the file1956 // but does not extend past the end of the file.1957 uint32_t SectOffset, SectType;1958 uint64_t SectSize;1959 1960 if (is64Bit()) {1961 MachO::section_64 Sect = getSection64(Sec);1962 SectOffset = Sect.offset;1963 SectSize = Sect.size;1964 SectType = Sect.flags & MachO::SECTION_TYPE;1965 } else {1966 MachO::section Sect = getSection(Sec);1967 SectOffset = Sect.offset;1968 SectSize = Sect.size;1969 SectType = Sect.flags & MachO::SECTION_TYPE;1970 }1971 if (SectType == MachO::S_ZEROFILL || SectType == MachO::S_GB_ZEROFILL)1972 return SectSize;1973 uint64_t FileSize = getData().size();1974 if (SectOffset > FileSize)1975 return 0;1976 if (FileSize - SectOffset < SectSize)1977 return FileSize - SectOffset;1978 return SectSize;1979}1980 1981ArrayRef<uint8_t> MachOObjectFile::getSectionContents(uint64_t Offset,1982 uint64_t Size) const {1983 return arrayRefFromStringRef(getData().substr(Offset, Size));1984}1985 1986Expected<ArrayRef<uint8_t>>1987MachOObjectFile::getSectionContents(DataRefImpl Sec) const {1988 uint64_t Offset;1989 uint64_t Size;1990 1991 if (is64Bit()) {1992 MachO::section_64 Sect = getSection64(Sec);1993 Offset = Sect.offset;1994 Size = Sect.size;1995 // Check for large mach-o files where the section contents might exceed1996 // 4GB. MachO::section_64 objects only have 32 bit file offsets to the1997 // section contents and can overflow in dSYM files. We can track this and1998 // adjust the section offset to be 64 bit safe. If sections overflow then1999 // section ordering is enforced. If sections are not ordered, then an error2000 // will be returned stopping invalid section data from being returned.2001 uint64_t PrevTrueOffset = 0;2002 uint64_t SectOffsetAdjust = 0;2003 for (uint32_t SectIdx = 0; SectIdx < Sec.d.a; ++SectIdx) {2004 MachO::section_64 CurrSect =2005 getStruct<MachO::section_64>(*this, Sections[SectIdx]);2006 uint64_t CurrTrueOffset = (uint64_t)CurrSect.offset + SectOffsetAdjust;2007 if ((SectOffsetAdjust > 0) && (PrevTrueOffset > CurrTrueOffset))2008 return malformedError("section data exceeds 4GB and section file "2009 "offsets are not ordered");2010 const uint64_t EndSectFileOffset =2011 (uint64_t)CurrSect.offset + CurrSect.size;2012 if (EndSectFileOffset > UINT32_MAX)2013 SectOffsetAdjust += EndSectFileOffset & 0xFFFFFFFF00000000ull;2014 PrevTrueOffset = CurrTrueOffset;2015 }2016 Offset += SectOffsetAdjust;2017 } else {2018 MachO::section Sect = getSection(Sec);2019 Offset = Sect.offset;2020 Size = Sect.size;2021 }2022 2023 return getSectionContents(Offset, Size);2024}2025 2026uint64_t MachOObjectFile::getSectionAlignment(DataRefImpl Sec) const {2027 uint32_t Align;2028 if (is64Bit()) {2029 MachO::section_64 Sect = getSection64(Sec);2030 Align = Sect.align;2031 } else {2032 MachO::section Sect = getSection(Sec);2033 Align = Sect.align;2034 }2035 2036 return uint64_t(1) << Align;2037}2038 2039Expected<SectionRef> MachOObjectFile::getSection(unsigned SectionIndex) const {2040 if (SectionIndex < 1 || SectionIndex > Sections.size())2041 return malformedError("bad section index: " + Twine((int)SectionIndex));2042 2043 DataRefImpl DRI;2044 DRI.d.a = SectionIndex - 1;2045 return SectionRef(DRI, this);2046}2047 2048Expected<SectionRef> MachOObjectFile::getSection(StringRef SectionName) const {2049 for (const SectionRef &Section : sections()) {2050 auto NameOrErr = Section.getName();2051 if (!NameOrErr)2052 return NameOrErr.takeError();2053 if (*NameOrErr == SectionName)2054 return Section;2055 }2056 return errorCodeToError(object_error::parse_failed);2057}2058 2059bool MachOObjectFile::isSectionCompressed(DataRefImpl Sec) const {2060 return false;2061}2062 2063bool MachOObjectFile::isSectionText(DataRefImpl Sec) const {2064 uint32_t Flags = getSectionFlags(*this, Sec);2065 return Flags & MachO::S_ATTR_PURE_INSTRUCTIONS;2066}2067 2068bool MachOObjectFile::isSectionData(DataRefImpl Sec) const {2069 uint32_t Flags = getSectionFlags(*this, Sec);2070 unsigned SectionType = Flags & MachO::SECTION_TYPE;2071 return !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) &&2072 !(SectionType == MachO::S_ZEROFILL ||2073 SectionType == MachO::S_GB_ZEROFILL);2074}2075 2076bool MachOObjectFile::isSectionBSS(DataRefImpl Sec) const {2077 uint32_t Flags = getSectionFlags(*this, Sec);2078 unsigned SectionType = Flags & MachO::SECTION_TYPE;2079 return !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) &&2080 (SectionType == MachO::S_ZEROFILL ||2081 SectionType == MachO::S_GB_ZEROFILL);2082}2083 2084bool MachOObjectFile::isDebugSection(DataRefImpl Sec) const {2085 Expected<StringRef> SectionNameOrErr = getSectionName(Sec);2086 if (!SectionNameOrErr) {2087 // TODO: Report the error message properly.2088 consumeError(SectionNameOrErr.takeError());2089 return false;2090 }2091 StringRef SectionName = SectionNameOrErr.get();2092 return SectionName.starts_with("__debug") ||2093 SectionName.starts_with("__zdebug") ||2094 SectionName.starts_with("__apple") || SectionName == "__gdb_index" ||2095 SectionName == "__swift_ast";2096}2097 2098namespace {2099template <typename LoadCommandType>2100ArrayRef<uint8_t> getSegmentContents(const MachOObjectFile &Obj,2101 MachOObjectFile::LoadCommandInfo LoadCmd,2102 StringRef SegmentName) {2103 auto SegmentOrErr = getStructOrErr<LoadCommandType>(Obj, LoadCmd.Ptr);2104 if (!SegmentOrErr) {2105 consumeError(SegmentOrErr.takeError());2106 return {};2107 }2108 auto &Segment = SegmentOrErr.get();2109 if (StringRef(Segment.segname, 16).starts_with(SegmentName))2110 return arrayRefFromStringRef(Obj.getData().slice(2111 Segment.fileoff, Segment.fileoff + Segment.filesize));2112 return {};2113}2114 2115template <typename LoadCommandType>2116ArrayRef<uint8_t> getSegmentContents(const MachOObjectFile &Obj,2117 MachOObjectFile::LoadCommandInfo LoadCmd) {2118 auto SegmentOrErr = getStructOrErr<LoadCommandType>(Obj, LoadCmd.Ptr);2119 if (!SegmentOrErr) {2120 consumeError(SegmentOrErr.takeError());2121 return {};2122 }2123 auto &Segment = SegmentOrErr.get();2124 return arrayRefFromStringRef(2125 Obj.getData().substr(Segment.fileoff, Segment.filesize));2126}2127} // namespace2128 2129ArrayRef<uint8_t>2130MachOObjectFile::getSegmentContents(StringRef SegmentName) const {2131 for (auto LoadCmd : load_commands()) {2132 ArrayRef<uint8_t> Contents;2133 switch (LoadCmd.C.cmd) {2134 case MachO::LC_SEGMENT:2135 Contents = ::getSegmentContents<MachO::segment_command>(*this, LoadCmd,2136 SegmentName);2137 break;2138 case MachO::LC_SEGMENT_64:2139 Contents = ::getSegmentContents<MachO::segment_command_64>(*this, LoadCmd,2140 SegmentName);2141 break;2142 default:2143 continue;2144 }2145 if (!Contents.empty())2146 return Contents;2147 }2148 return {};2149}2150 2151ArrayRef<uint8_t>2152MachOObjectFile::getSegmentContents(size_t SegmentIndex) const {2153 size_t Idx = 0;2154 for (auto LoadCmd : load_commands()) {2155 switch (LoadCmd.C.cmd) {2156 case MachO::LC_SEGMENT:2157 if (Idx == SegmentIndex)2158 return ::getSegmentContents<MachO::segment_command>(*this, LoadCmd);2159 ++Idx;2160 break;2161 case MachO::LC_SEGMENT_64:2162 if (Idx == SegmentIndex)2163 return ::getSegmentContents<MachO::segment_command_64>(*this, LoadCmd);2164 ++Idx;2165 break;2166 default:2167 continue;2168 }2169 }2170 return {};2171}2172 2173unsigned MachOObjectFile::getSectionID(SectionRef Sec) const {2174 return Sec.getRawDataRefImpl().d.a;2175}2176 2177bool MachOObjectFile::isSectionVirtual(DataRefImpl Sec) const {2178 uint32_t Flags = getSectionFlags(*this, Sec);2179 unsigned SectionType = Flags & MachO::SECTION_TYPE;2180 return SectionType == MachO::S_ZEROFILL ||2181 SectionType == MachO::S_GB_ZEROFILL;2182}2183 2184bool MachOObjectFile::isSectionBitcode(DataRefImpl Sec) const {2185 StringRef SegmentName = getSectionFinalSegmentName(Sec);2186 if (Expected<StringRef> NameOrErr = getSectionName(Sec))2187 return (SegmentName == "__LLVM" && *NameOrErr == "__bitcode");2188 return false;2189}2190 2191bool MachOObjectFile::isSectionStripped(DataRefImpl Sec) const {2192 if (is64Bit())2193 return getSection64(Sec).offset == 0;2194 return getSection(Sec).offset == 0;2195}2196 2197relocation_iterator MachOObjectFile::section_rel_begin(DataRefImpl Sec) const {2198 DataRefImpl Ret;2199 Ret.d.a = Sec.d.a;2200 Ret.d.b = 0;2201 return relocation_iterator(RelocationRef(Ret, this));2202}2203 2204relocation_iterator2205MachOObjectFile::section_rel_end(DataRefImpl Sec) const {2206 uint32_t Num;2207 if (is64Bit()) {2208 MachO::section_64 Sect = getSection64(Sec);2209 Num = Sect.nreloc;2210 } else {2211 MachO::section Sect = getSection(Sec);2212 Num = Sect.nreloc;2213 }2214 2215 DataRefImpl Ret;2216 Ret.d.a = Sec.d.a;2217 Ret.d.b = Num;2218 return relocation_iterator(RelocationRef(Ret, this));2219}2220 2221relocation_iterator MachOObjectFile::extrel_begin() const {2222 DataRefImpl Ret;2223 // for DYSYMTAB symbols, Ret.d.a == 0 for external relocations2224 Ret.d.a = 0; // Would normally be a section index.2225 Ret.d.b = 0; // Index into the external relocations2226 return relocation_iterator(RelocationRef(Ret, this));2227}2228 2229relocation_iterator MachOObjectFile::extrel_end() const {2230 MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand();2231 DataRefImpl Ret;2232 // for DYSYMTAB symbols, Ret.d.a == 0 for external relocations2233 Ret.d.a = 0; // Would normally be a section index.2234 Ret.d.b = DysymtabLoadCmd.nextrel; // Index into the external relocations2235 return relocation_iterator(RelocationRef(Ret, this));2236}2237 2238relocation_iterator MachOObjectFile::locrel_begin() const {2239 DataRefImpl Ret;2240 // for DYSYMTAB symbols, Ret.d.a == 1 for local relocations2241 Ret.d.a = 1; // Would normally be a section index.2242 Ret.d.b = 0; // Index into the local relocations2243 return relocation_iterator(RelocationRef(Ret, this));2244}2245 2246relocation_iterator MachOObjectFile::locrel_end() const {2247 MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand();2248 DataRefImpl Ret;2249 // for DYSYMTAB symbols, Ret.d.a == 1 for local relocations2250 Ret.d.a = 1; // Would normally be a section index.2251 Ret.d.b = DysymtabLoadCmd.nlocrel; // Index into the local relocations2252 return relocation_iterator(RelocationRef(Ret, this));2253}2254 2255void MachOObjectFile::moveRelocationNext(DataRefImpl &Rel) const {2256 ++Rel.d.b;2257}2258 2259uint64_t MachOObjectFile::getRelocationOffset(DataRefImpl Rel) const {2260 assert((getHeader().filetype == MachO::MH_OBJECT ||2261 getHeader().filetype == MachO::MH_KEXT_BUNDLE) &&2262 "Only implemented for MH_OBJECT && MH_KEXT_BUNDLE");2263 MachO::any_relocation_info RE = getRelocation(Rel);2264 return getAnyRelocationAddress(RE);2265}2266 2267symbol_iterator2268MachOObjectFile::getRelocationSymbol(DataRefImpl Rel) const {2269 MachO::any_relocation_info RE = getRelocation(Rel);2270 if (isRelocationScattered(RE))2271 return symbol_end();2272 2273 uint32_t SymbolIdx = getPlainRelocationSymbolNum(RE);2274 bool isExtern = getPlainRelocationExternal(RE);2275 if (!isExtern)2276 return symbol_end();2277 2278 MachO::symtab_command S = getSymtabLoadCommand();2279 unsigned SymbolTableEntrySize = is64Bit() ?2280 sizeof(MachO::nlist_64) :2281 sizeof(MachO::nlist);2282 uint64_t Offset = S.symoff + SymbolIdx * SymbolTableEntrySize;2283 DataRefImpl Sym;2284 Sym.p = reinterpret_cast<uintptr_t>(getPtr(*this, Offset));2285 return symbol_iterator(SymbolRef(Sym, this));2286}2287 2288section_iterator2289MachOObjectFile::getRelocationSection(DataRefImpl Rel) const {2290 return section_iterator(getAnyRelocationSection(getRelocation(Rel)));2291}2292 2293uint64_t MachOObjectFile::getRelocationType(DataRefImpl Rel) const {2294 MachO::any_relocation_info RE = getRelocation(Rel);2295 return getAnyRelocationType(RE);2296}2297 2298void MachOObjectFile::getRelocationTypeName(2299 DataRefImpl Rel, SmallVectorImpl<char> &Result) const {2300 StringRef res;2301 uint64_t RType = getRelocationType(Rel);2302 2303 unsigned Arch = this->getArch();2304 2305 switch (Arch) {2306 case Triple::x86: {2307 static const char *const Table[] = {2308 "GENERIC_RELOC_VANILLA",2309 "GENERIC_RELOC_PAIR",2310 "GENERIC_RELOC_SECTDIFF",2311 "GENERIC_RELOC_PB_LA_PTR",2312 "GENERIC_RELOC_LOCAL_SECTDIFF",2313 "GENERIC_RELOC_TLV" };2314 2315 if (RType > 5)2316 res = "Unknown";2317 else2318 res = Table[RType];2319 break;2320 }2321 case Triple::x86_64: {2322 static const char *const Table[] = {2323 "X86_64_RELOC_UNSIGNED",2324 "X86_64_RELOC_SIGNED",2325 "X86_64_RELOC_BRANCH",2326 "X86_64_RELOC_GOT_LOAD",2327 "X86_64_RELOC_GOT",2328 "X86_64_RELOC_SUBTRACTOR",2329 "X86_64_RELOC_SIGNED_1",2330 "X86_64_RELOC_SIGNED_2",2331 "X86_64_RELOC_SIGNED_4",2332 "X86_64_RELOC_TLV" };2333 2334 if (RType > 9)2335 res = "Unknown";2336 else2337 res = Table[RType];2338 break;2339 }2340 case Triple::arm: {2341 static const char *const Table[] = {2342 "ARM_RELOC_VANILLA",2343 "ARM_RELOC_PAIR",2344 "ARM_RELOC_SECTDIFF",2345 "ARM_RELOC_LOCAL_SECTDIFF",2346 "ARM_RELOC_PB_LA_PTR",2347 "ARM_RELOC_BR24",2348 "ARM_THUMB_RELOC_BR22",2349 "ARM_THUMB_32BIT_BRANCH",2350 "ARM_RELOC_HALF",2351 "ARM_RELOC_HALF_SECTDIFF" };2352 2353 if (RType > 9)2354 res = "Unknown";2355 else2356 res = Table[RType];2357 break;2358 }2359 case Triple::aarch64:2360 case Triple::aarch64_32: {2361 static const char *const Table[] = {2362 "ARM64_RELOC_UNSIGNED", "ARM64_RELOC_SUBTRACTOR",2363 "ARM64_RELOC_BRANCH26", "ARM64_RELOC_PAGE21",2364 "ARM64_RELOC_PAGEOFF12", "ARM64_RELOC_GOT_LOAD_PAGE21",2365 "ARM64_RELOC_GOT_LOAD_PAGEOFF12", "ARM64_RELOC_POINTER_TO_GOT",2366 "ARM64_RELOC_TLVP_LOAD_PAGE21", "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",2367 "ARM64_RELOC_ADDEND", "ARM64_RELOC_AUTHENTICATED_POINTER"2368 };2369 2370 if (RType >= std::size(Table))2371 res = "Unknown";2372 else2373 res = Table[RType];2374 break;2375 }2376 case Triple::ppc: {2377 static const char *const Table[] = {2378 "PPC_RELOC_VANILLA",2379 "PPC_RELOC_PAIR",2380 "PPC_RELOC_BR14",2381 "PPC_RELOC_BR24",2382 "PPC_RELOC_HI16",2383 "PPC_RELOC_LO16",2384 "PPC_RELOC_HA16",2385 "PPC_RELOC_LO14",2386 "PPC_RELOC_SECTDIFF",2387 "PPC_RELOC_PB_LA_PTR",2388 "PPC_RELOC_HI16_SECTDIFF",2389 "PPC_RELOC_LO16_SECTDIFF",2390 "PPC_RELOC_HA16_SECTDIFF",2391 "PPC_RELOC_JBSR",2392 "PPC_RELOC_LO14_SECTDIFF",2393 "PPC_RELOC_LOCAL_SECTDIFF" };2394 2395 if (RType > 15)2396 res = "Unknown";2397 else2398 res = Table[RType];2399 break;2400 }2401 case Triple::UnknownArch:2402 res = "Unknown";2403 break;2404 }2405 Result.append(res.begin(), res.end());2406}2407 2408uint8_t MachOObjectFile::getRelocationLength(DataRefImpl Rel) const {2409 MachO::any_relocation_info RE = getRelocation(Rel);2410 return getAnyRelocationLength(RE);2411}2412 2413//2414// guessLibraryShortName() is passed a name of a dynamic library and returns a2415// guess on what the short name is. Then name is returned as a substring of the2416// StringRef Name passed in. The name of the dynamic library is recognized as2417// a framework if it has one of the two following forms:2418// Foo.framework/Versions/A/Foo2419// Foo.framework/Foo2420// Where A and Foo can be any string. And may contain a trailing suffix2421// starting with an underbar. If the Name is recognized as a framework then2422// isFramework is set to true else it is set to false. If the Name has a2423// suffix then Suffix is set to the substring in Name that contains the suffix2424// else it is set to a NULL StringRef.2425//2426// The Name of the dynamic library is recognized as a library name if it has2427// one of the two following forms:2428// libFoo.A.dylib2429// libFoo.dylib2430//2431// The library may have a suffix trailing the name Foo of the form:2432// libFoo_profile.A.dylib2433// libFoo_profile.dylib2434// These dyld image suffixes are separated from the short name by a '_'2435// character. Because the '_' character is commonly used to separate words in2436// filenames guessLibraryShortName() cannot reliably separate a dylib's short2437// name from an arbitrary image suffix; imagine if both the short name and the2438// suffix contains an '_' character! To better deal with this ambiguity,2439// guessLibraryShortName() will recognize only "_debug" and "_profile" as valid2440// Suffix values. Calling code needs to be tolerant of guessLibraryShortName()2441// guessing incorrectly.2442//2443// The Name of the dynamic library is also recognized as a library name if it2444// has the following form:2445// Foo.qtx2446//2447// If the Name of the dynamic library is none of the forms above then a NULL2448// StringRef is returned.2449StringRef MachOObjectFile::guessLibraryShortName(StringRef Name,2450 bool &isFramework,2451 StringRef &Suffix) {2452 StringRef Foo, F, DotFramework, V, Dylib, Lib, Dot, Qtx;2453 size_t a, b, c, d, Idx;2454 2455 isFramework = false;2456 Suffix = StringRef();2457 2458 // Pull off the last component and make Foo point to it2459 a = Name.rfind('/');2460 if (a == Name.npos || a == 0)2461 goto guess_library;2462 Foo = Name.substr(a + 1);2463 2464 // Look for a suffix starting with a '_'2465 Idx = Foo.rfind('_');2466 if (Idx != Foo.npos && Foo.size() >= 2) {2467 Suffix = Foo.substr(Idx);2468 if (Suffix != "_debug" && Suffix != "_profile")2469 Suffix = StringRef();2470 else2471 Foo = Foo.slice(0, Idx);2472 }2473 2474 // First look for the form Foo.framework/Foo2475 b = Name.rfind('/', a);2476 if (b == Name.npos)2477 Idx = 0;2478 else2479 Idx = b+1;2480 F = Name.substr(Idx, Foo.size());2481 DotFramework = Name.substr(Idx + Foo.size(), sizeof(".framework/") - 1);2482 if (F == Foo && DotFramework == ".framework/") {2483 isFramework = true;2484 return Foo;2485 }2486 2487 // Next look for the form Foo.framework/Versions/A/Foo2488 if (b == Name.npos)2489 goto guess_library;2490 c = Name.rfind('/', b);2491 if (c == Name.npos || c == 0)2492 goto guess_library;2493 V = Name.substr(c + 1);2494 if (!V.starts_with("Versions/"))2495 goto guess_library;2496 d = Name.rfind('/', c);2497 if (d == Name.npos)2498 Idx = 0;2499 else2500 Idx = d+1;2501 F = Name.substr(Idx, Foo.size());2502 DotFramework = Name.substr(Idx + Foo.size(), sizeof(".framework/") - 1);2503 if (F == Foo && DotFramework == ".framework/") {2504 isFramework = true;2505 return Foo;2506 }2507 2508guess_library:2509 // pull off the suffix after the "." and make a point to it2510 a = Name.rfind('.');2511 if (a == Name.npos || a == 0)2512 return StringRef();2513 Dylib = Name.substr(a);2514 if (Dylib != ".dylib")2515 goto guess_qtx;2516 2517 // First pull off the version letter for the form Foo.A.dylib if any.2518 if (a >= 3) {2519 Dot = Name.substr(a - 2, 1);2520 if (Dot == ".")2521 a = a - 2;2522 }2523 2524 b = Name.rfind('/', a);2525 if (b == Name.npos)2526 b = 0;2527 else2528 b = b+1;2529 // ignore any suffix after an underbar like Foo_profile.A.dylib2530 Idx = Name.rfind('_');2531 if (Idx != Name.npos && Idx != b) {2532 Lib = Name.slice(b, Idx);2533 Suffix = Name.slice(Idx, a);2534 if (Suffix != "_debug" && Suffix != "_profile") {2535 Suffix = StringRef();2536 Lib = Name.slice(b, a);2537 }2538 }2539 else2540 Lib = Name.slice(b, a);2541 // There are incorrect library names of the form:2542 // libATS.A_profile.dylib so check for these.2543 if (Lib.size() >= 3) {2544 Dot = Lib.substr(Lib.size() - 2, 1);2545 if (Dot == ".")2546 Lib = Lib.slice(0, Lib.size()-2);2547 }2548 return Lib;2549 2550guess_qtx:2551 Qtx = Name.substr(a);2552 if (Qtx != ".qtx")2553 return StringRef();2554 b = Name.rfind('/', a);2555 if (b == Name.npos)2556 Lib = Name.slice(0, a);2557 else2558 Lib = Name.slice(b+1, a);2559 // There are library names of the form: QT.A.qtx so check for these.2560 if (Lib.size() >= 3) {2561 Dot = Lib.substr(Lib.size() - 2, 1);2562 if (Dot == ".")2563 Lib = Lib.slice(0, Lib.size()-2);2564 }2565 return Lib;2566}2567 2568// getLibraryShortNameByIndex() is used to get the short name of the library2569// for an undefined symbol in a linked Mach-O binary that was linked with the2570// normal two-level namespace default (that is MH_TWOLEVEL in the header).2571// It is passed the index (0 - based) of the library as translated from2572// GET_LIBRARY_ORDINAL (1 - based).2573std::error_code MachOObjectFile::getLibraryShortNameByIndex(unsigned Index,2574 StringRef &Res) const {2575 if (Index >= Libraries.size())2576 return object_error::parse_failed;2577 2578 // If the cache of LibrariesShortNames is not built up do that first for2579 // all the Libraries.2580 if (LibrariesShortNames.size() == 0) {2581 for (unsigned i = 0; i < Libraries.size(); i++) {2582 auto CommandOrErr =2583 getStructOrErr<MachO::dylib_command>(*this, Libraries[i]);2584 if (!CommandOrErr)2585 return object_error::parse_failed;2586 MachO::dylib_command D = CommandOrErr.get();2587 if (D.dylib.name >= D.cmdsize)2588 return object_error::parse_failed;2589 const char *P = (const char *)(Libraries[i]) + D.dylib.name;2590 StringRef Name = StringRef(P);2591 if (D.dylib.name+Name.size() >= D.cmdsize)2592 return object_error::parse_failed;2593 StringRef Suffix;2594 bool isFramework;2595 StringRef shortName = guessLibraryShortName(Name, isFramework, Suffix);2596 if (shortName.empty())2597 LibrariesShortNames.push_back(Name);2598 else2599 LibrariesShortNames.push_back(shortName);2600 }2601 }2602 2603 Res = LibrariesShortNames[Index];2604 return std::error_code();2605}2606 2607uint32_t MachOObjectFile::getLibraryCount() const {2608 return Libraries.size();2609}2610 2611section_iterator2612MachOObjectFile::getRelocationRelocatedSection(relocation_iterator Rel) const {2613 DataRefImpl Sec;2614 Sec.d.a = Rel->getRawDataRefImpl().d.a;2615 return section_iterator(SectionRef(Sec, this));2616}2617 2618basic_symbol_iterator MachOObjectFile::symbol_begin() const {2619 DataRefImpl DRI;2620 MachO::symtab_command Symtab = getSymtabLoadCommand();2621 if (!SymtabLoadCmd || Symtab.nsyms == 0)2622 return basic_symbol_iterator(SymbolRef(DRI, this));2623 2624 return getSymbolByIndex(0);2625}2626 2627basic_symbol_iterator MachOObjectFile::symbol_end() const {2628 DataRefImpl DRI;2629 MachO::symtab_command Symtab = getSymtabLoadCommand();2630 if (!SymtabLoadCmd || Symtab.nsyms == 0)2631 return basic_symbol_iterator(SymbolRef(DRI, this));2632 2633 unsigned SymbolTableEntrySize = is64Bit() ?2634 sizeof(MachO::nlist_64) :2635 sizeof(MachO::nlist);2636 unsigned Offset = Symtab.symoff +2637 Symtab.nsyms * SymbolTableEntrySize;2638 DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, Offset));2639 return basic_symbol_iterator(SymbolRef(DRI, this));2640}2641 2642symbol_iterator MachOObjectFile::getSymbolByIndex(unsigned Index) const {2643 MachO::symtab_command Symtab = getSymtabLoadCommand();2644 if (!SymtabLoadCmd || Index >= Symtab.nsyms)2645 report_fatal_error("Requested symbol index is out of range.");2646 unsigned SymbolTableEntrySize =2647 is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);2648 DataRefImpl DRI;2649 DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, Symtab.symoff));2650 DRI.p += Index * SymbolTableEntrySize;2651 return basic_symbol_iterator(SymbolRef(DRI, this));2652}2653 2654uint64_t MachOObjectFile::getSymbolIndex(DataRefImpl Symb) const {2655 MachO::symtab_command Symtab = getSymtabLoadCommand();2656 if (!SymtabLoadCmd)2657 report_fatal_error("getSymbolIndex() called with no symbol table symbol");2658 unsigned SymbolTableEntrySize =2659 is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);2660 DataRefImpl DRIstart;2661 DRIstart.p = reinterpret_cast<uintptr_t>(getPtr(*this, Symtab.symoff));2662 uint64_t Index = (Symb.p - DRIstart.p) / SymbolTableEntrySize;2663 return Index;2664}2665 2666section_iterator MachOObjectFile::section_begin() const {2667 DataRefImpl DRI;2668 return section_iterator(SectionRef(DRI, this));2669}2670 2671section_iterator MachOObjectFile::section_end() const {2672 DataRefImpl DRI;2673 DRI.d.a = Sections.size();2674 return section_iterator(SectionRef(DRI, this));2675}2676 2677uint8_t MachOObjectFile::getBytesInAddress() const {2678 return is64Bit() ? 8 : 4;2679}2680 2681StringRef MachOObjectFile::getFileFormatName() const {2682 unsigned CPUType = getCPUType(*this);2683 if (!is64Bit()) {2684 switch (CPUType) {2685 case MachO::CPU_TYPE_I386:2686 return "Mach-O 32-bit i386";2687 case MachO::CPU_TYPE_ARM:2688 return "Mach-O arm";2689 case MachO::CPU_TYPE_ARM64_32:2690 return "Mach-O arm64 (ILP32)";2691 case MachO::CPU_TYPE_POWERPC:2692 return "Mach-O 32-bit ppc";2693 default:2694 return "Mach-O 32-bit unknown";2695 }2696 }2697 2698 switch (CPUType) {2699 case MachO::CPU_TYPE_X86_64:2700 return "Mach-O 64-bit x86-64";2701 case MachO::CPU_TYPE_ARM64:2702 return "Mach-O arm64";2703 case MachO::CPU_TYPE_POWERPC64:2704 return "Mach-O 64-bit ppc64";2705 default:2706 return "Mach-O 64-bit unknown";2707 }2708}2709 2710Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) {2711 switch (CPUType) {2712 case MachO::CPU_TYPE_I386:2713 return Triple::x86;2714 case MachO::CPU_TYPE_X86_64:2715 return Triple::x86_64;2716 case MachO::CPU_TYPE_ARM:2717 return Triple::arm;2718 case MachO::CPU_TYPE_ARM64:2719 return Triple::aarch64;2720 case MachO::CPU_TYPE_ARM64_32:2721 return Triple::aarch64_32;2722 case MachO::CPU_TYPE_POWERPC:2723 return Triple::ppc;2724 case MachO::CPU_TYPE_POWERPC64:2725 return Triple::ppc64;2726 default:2727 return Triple::UnknownArch;2728 }2729}2730 2731Triple MachOObjectFile::getArchTriple(uint32_t CPUType, uint32_t CPUSubType,2732 const char **McpuDefault,2733 const char **ArchFlag) {2734 if (McpuDefault)2735 *McpuDefault = nullptr;2736 if (ArchFlag)2737 *ArchFlag = nullptr;2738 2739 switch (CPUType) {2740 case MachO::CPU_TYPE_I386:2741 switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {2742 case MachO::CPU_SUBTYPE_I386_ALL:2743 if (ArchFlag)2744 *ArchFlag = "i386";2745 return Triple("i386-apple-darwin");2746 default:2747 return Triple();2748 }2749 case MachO::CPU_TYPE_X86_64:2750 switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {2751 case MachO::CPU_SUBTYPE_X86_64_ALL:2752 if (ArchFlag)2753 *ArchFlag = "x86_64";2754 return Triple("x86_64-apple-darwin");2755 case MachO::CPU_SUBTYPE_X86_64_H:2756 if (ArchFlag)2757 *ArchFlag = "x86_64h";2758 return Triple("x86_64h-apple-darwin");2759 default:2760 return Triple();2761 }2762 case MachO::CPU_TYPE_ARM:2763 switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {2764 case MachO::CPU_SUBTYPE_ARM_V4T:2765 if (ArchFlag)2766 *ArchFlag = "armv4t";2767 return Triple("armv4t-apple-darwin");2768 case MachO::CPU_SUBTYPE_ARM_V5TEJ:2769 if (ArchFlag)2770 *ArchFlag = "armv5e";2771 return Triple("armv5e-apple-darwin");2772 case MachO::CPU_SUBTYPE_ARM_XSCALE:2773 if (ArchFlag)2774 *ArchFlag = "xscale";2775 return Triple("xscale-apple-darwin");2776 case MachO::CPU_SUBTYPE_ARM_V6:2777 if (ArchFlag)2778 *ArchFlag = "armv6";2779 return Triple("armv6-apple-darwin");2780 case MachO::CPU_SUBTYPE_ARM_V6M:2781 if (McpuDefault)2782 *McpuDefault = "cortex-m0";2783 if (ArchFlag)2784 *ArchFlag = "armv6m";2785 return Triple("armv6m-apple-darwin");2786 case MachO::CPU_SUBTYPE_ARM_V7:2787 if (ArchFlag)2788 *ArchFlag = "armv7";2789 return Triple("armv7-apple-darwin");2790 case MachO::CPU_SUBTYPE_ARM_V7EM:2791 if (McpuDefault)2792 *McpuDefault = "cortex-m4";2793 if (ArchFlag)2794 *ArchFlag = "armv7em";2795 return Triple("thumbv7em-apple-darwin");2796 case MachO::CPU_SUBTYPE_ARM_V7K:2797 if (McpuDefault)2798 *McpuDefault = "cortex-a7";2799 if (ArchFlag)2800 *ArchFlag = "armv7k";2801 return Triple("armv7k-apple-darwin");2802 case MachO::CPU_SUBTYPE_ARM_V7M:2803 if (McpuDefault)2804 *McpuDefault = "cortex-m3";2805 if (ArchFlag)2806 *ArchFlag = "armv7m";2807 return Triple("thumbv7m-apple-darwin");2808 case MachO::CPU_SUBTYPE_ARM_V7S:2809 if (McpuDefault)2810 *McpuDefault = "cortex-a7";2811 if (ArchFlag)2812 *ArchFlag = "armv7s";2813 return Triple("armv7s-apple-darwin");2814 default:2815 return Triple();2816 }2817 case MachO::CPU_TYPE_ARM64:2818 switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {2819 case MachO::CPU_SUBTYPE_ARM64_ALL:2820 if (McpuDefault)2821 *McpuDefault = "cyclone";2822 if (ArchFlag)2823 *ArchFlag = "arm64";2824 return Triple("arm64-apple-darwin");2825 case MachO::CPU_SUBTYPE_ARM64E:2826 if (McpuDefault)2827 *McpuDefault = "apple-a12";2828 if (ArchFlag)2829 *ArchFlag = "arm64e";2830 return Triple("arm64e-apple-darwin");2831 default:2832 return Triple();2833 }2834 case MachO::CPU_TYPE_ARM64_32:2835 switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {2836 case MachO::CPU_SUBTYPE_ARM64_32_V8:2837 if (McpuDefault)2838 *McpuDefault = "cyclone";2839 if (ArchFlag)2840 *ArchFlag = "arm64_32";2841 return Triple("arm64_32-apple-darwin");2842 default:2843 return Triple();2844 }2845 case MachO::CPU_TYPE_POWERPC:2846 switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {2847 case MachO::CPU_SUBTYPE_POWERPC_ALL:2848 if (ArchFlag)2849 *ArchFlag = "ppc";2850 return Triple("ppc-apple-darwin");2851 default:2852 return Triple();2853 }2854 case MachO::CPU_TYPE_POWERPC64:2855 switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {2856 case MachO::CPU_SUBTYPE_POWERPC_ALL:2857 if (ArchFlag)2858 *ArchFlag = "ppc64";2859 return Triple("ppc64-apple-darwin");2860 default:2861 return Triple();2862 }2863 default:2864 return Triple();2865 }2866}2867 2868Triple MachOObjectFile::getHostArch() {2869 return Triple(sys::getDefaultTargetTriple());2870}2871 2872bool MachOObjectFile::isValidArch(StringRef ArchFlag) {2873 auto validArchs = getValidArchs();2874 return llvm::is_contained(validArchs, ArchFlag);2875}2876 2877ArrayRef<StringRef> MachOObjectFile::getValidArchs() {2878 static const std::array<StringRef, 18> ValidArchs = {{2879 "i386",2880 "x86_64",2881 "x86_64h",2882 "armv4t",2883 "arm",2884 "armv5e",2885 "armv6",2886 "armv6m",2887 "armv7",2888 "armv7em",2889 "armv7k",2890 "armv7m",2891 "armv7s",2892 "arm64",2893 "arm64e",2894 "arm64_32",2895 "ppc",2896 "ppc64",2897 }};2898 2899 return ValidArchs;2900}2901 2902Triple::ArchType MachOObjectFile::getArch() const {2903 return getArch(getCPUType(*this), getCPUSubType(*this));2904}2905 2906Triple MachOObjectFile::getArchTriple(const char **McpuDefault) const {2907 return getArchTriple(Header.cputype, Header.cpusubtype, McpuDefault);2908}2909 2910relocation_iterator MachOObjectFile::section_rel_begin(unsigned Index) const {2911 DataRefImpl DRI;2912 DRI.d.a = Index;2913 return section_rel_begin(DRI);2914}2915 2916relocation_iterator MachOObjectFile::section_rel_end(unsigned Index) const {2917 DataRefImpl DRI;2918 DRI.d.a = Index;2919 return section_rel_end(DRI);2920}2921 2922dice_iterator MachOObjectFile::begin_dices() const {2923 DataRefImpl DRI;2924 if (!DataInCodeLoadCmd)2925 return dice_iterator(DiceRef(DRI, this));2926 2927 MachO::linkedit_data_command DicLC = getDataInCodeLoadCommand();2928 DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, DicLC.dataoff));2929 return dice_iterator(DiceRef(DRI, this));2930}2931 2932dice_iterator MachOObjectFile::end_dices() const {2933 DataRefImpl DRI;2934 if (!DataInCodeLoadCmd)2935 return dice_iterator(DiceRef(DRI, this));2936 2937 MachO::linkedit_data_command DicLC = getDataInCodeLoadCommand();2938 unsigned Offset = DicLC.dataoff + DicLC.datasize;2939 DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, Offset));2940 return dice_iterator(DiceRef(DRI, this));2941}2942 2943ExportEntry::ExportEntry(Error *E, const MachOObjectFile *O,2944 ArrayRef<uint8_t> T) : E(E), O(O), Trie(T) {}2945 2946void ExportEntry::moveToFirst() {2947 ErrorAsOutParameter ErrAsOutParam(E);2948 pushNode(0);2949 if (*E)2950 return;2951 pushDownUntilBottom();2952}2953 2954void ExportEntry::moveToEnd() {2955 Stack.clear();2956 Done = true;2957}2958 2959bool ExportEntry::operator==(const ExportEntry &Other) const {2960 // Common case, one at end, other iterating from begin.2961 if (Done || Other.Done)2962 return (Done == Other.Done);2963 // Not equal if different stack sizes.2964 if (Stack.size() != Other.Stack.size())2965 return false;2966 // Not equal if different cumulative strings.2967 if (!CumulativeString.equals(Other.CumulativeString))2968 return false;2969 // Equal if all nodes in both stacks match.2970 for (unsigned i=0; i < Stack.size(); ++i) {2971 if (Stack[i].Start != Other.Stack[i].Start)2972 return false;2973 }2974 return true;2975}2976 2977uint64_t ExportEntry::readULEB128(const uint8_t *&Ptr, const char **error) {2978 unsigned Count;2979 uint64_t Result = decodeULEB128(Ptr, &Count, Trie.end(), error);2980 Ptr += Count;2981 if (Ptr > Trie.end())2982 Ptr = Trie.end();2983 return Result;2984}2985 2986StringRef ExportEntry::name() const {2987 return CumulativeString;2988}2989 2990uint64_t ExportEntry::flags() const {2991 return Stack.back().Flags;2992}2993 2994uint64_t ExportEntry::address() const {2995 return Stack.back().Address;2996}2997 2998uint64_t ExportEntry::other() const {2999 return Stack.back().Other;3000}3001 3002StringRef ExportEntry::otherName() const {3003 const char* ImportName = Stack.back().ImportName;3004 if (ImportName)3005 return StringRef(ImportName);3006 return StringRef();3007}3008 3009uint32_t ExportEntry::nodeOffset() const {3010 return Stack.back().Start - Trie.begin();3011}3012 3013ExportEntry::NodeState::NodeState(const uint8_t *Ptr)3014 : Start(Ptr), Current(Ptr) {}3015 3016void ExportEntry::pushNode(uint64_t offset) {3017 ErrorAsOutParameter ErrAsOutParam(E);3018 const uint8_t *Ptr = Trie.begin() + offset;3019 NodeState State(Ptr);3020 const char *error = nullptr;3021 uint64_t ExportInfoSize = readULEB128(State.Current, &error);3022 if (error) {3023 *E = malformedError("export info size " + Twine(error) +3024 " in export trie data at node: 0x" +3025 Twine::utohexstr(offset));3026 moveToEnd();3027 return;3028 }3029 State.IsExportNode = (ExportInfoSize != 0);3030 const uint8_t* Children = State.Current + ExportInfoSize;3031 if (Children > Trie.end()) {3032 *E = malformedError(3033 "export info size: 0x" + Twine::utohexstr(ExportInfoSize) +3034 " in export trie data at node: 0x" + Twine::utohexstr(offset) +3035 " too big and extends past end of trie data");3036 moveToEnd();3037 return;3038 }3039 if (State.IsExportNode) {3040 const uint8_t *ExportStart = State.Current;3041 State.Flags = readULEB128(State.Current, &error);3042 if (error) {3043 *E = malformedError("flags " + Twine(error) +3044 " in export trie data at node: 0x" +3045 Twine::utohexstr(offset));3046 moveToEnd();3047 return;3048 }3049 uint64_t Kind = State.Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK;3050 if (State.Flags != 0 &&3051 (Kind != MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR &&3052 Kind != MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE &&3053 Kind != MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL)) {3054 *E = malformedError(3055 "unsupported exported symbol kind: " + Twine((int)Kind) +3056 " in flags: 0x" + Twine::utohexstr(State.Flags) +3057 " in export trie data at node: 0x" + Twine::utohexstr(offset));3058 moveToEnd();3059 return;3060 }3061 if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) {3062 State.Address = 0;3063 State.Other = readULEB128(State.Current, &error); // dylib ordinal3064 if (error) {3065 *E = malformedError("dylib ordinal of re-export " + Twine(error) +3066 " in export trie data at node: 0x" +3067 Twine::utohexstr(offset));3068 moveToEnd();3069 return;3070 }3071 if (O != nullptr) {3072 // Only positive numbers represent library ordinals. Zero and negative3073 // numbers have special meaning (see BindSpecialDylib).3074 if ((int64_t)State.Other > 0 && State.Other > O->getLibraryCount()) {3075 *E = malformedError(3076 "bad library ordinal: " + Twine((int)State.Other) + " (max " +3077 Twine((int)O->getLibraryCount()) +3078 ") in export trie data at node: 0x" + Twine::utohexstr(offset));3079 moveToEnd();3080 return;3081 }3082 }3083 State.ImportName = reinterpret_cast<const char*>(State.Current);3084 if (*State.ImportName == '\0') {3085 State.Current++;3086 } else {3087 const uint8_t *End = State.Current + 1;3088 if (End >= Trie.end()) {3089 *E = malformedError("import name of re-export in export trie data at "3090 "node: 0x" +3091 Twine::utohexstr(offset) +3092 " starts past end of trie data");3093 moveToEnd();3094 return;3095 }3096 while(*End != '\0' && End < Trie.end())3097 End++;3098 if (*End != '\0') {3099 *E = malformedError("import name of re-export in export trie data at "3100 "node: 0x" +3101 Twine::utohexstr(offset) +3102 " extends past end of trie data");3103 moveToEnd();3104 return;3105 }3106 State.Current = End + 1;3107 }3108 } else {3109 State.Address = readULEB128(State.Current, &error);3110 if (error) {3111 *E = malformedError("address " + Twine(error) +3112 " in export trie data at node: 0x" +3113 Twine::utohexstr(offset));3114 moveToEnd();3115 return;3116 }3117 if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) {3118 State.Other = readULEB128(State.Current, &error);3119 if (error) {3120 *E = malformedError("resolver of stub and resolver " + Twine(error) +3121 " in export trie data at node: 0x" +3122 Twine::utohexstr(offset));3123 moveToEnd();3124 return;3125 }3126 }3127 }3128 if (ExportStart + ExportInfoSize < State.Current) {3129 *E = malformedError(3130 "inconsistent export info size: 0x" +3131 Twine::utohexstr(ExportInfoSize) + " where actual size was: 0x" +3132 Twine::utohexstr(State.Current - ExportStart) +3133 " in export trie data at node: 0x" + Twine::utohexstr(offset));3134 moveToEnd();3135 return;3136 }3137 }3138 State.ChildCount = *Children;3139 if (State.ChildCount != 0 && Children + 1 >= Trie.end()) {3140 *E = malformedError("byte for count of children in export trie data at "3141 "node: 0x" +3142 Twine::utohexstr(offset) +3143 " extends past end of trie data");3144 moveToEnd();3145 return;3146 }3147 State.Current = Children + 1;3148 State.NextChildIndex = 0;3149 State.ParentStringLength = CumulativeString.size();3150 Stack.push_back(State);3151}3152 3153void ExportEntry::pushDownUntilBottom() {3154 ErrorAsOutParameter ErrAsOutParam(E);3155 const char *error = nullptr;3156 while (Stack.back().NextChildIndex < Stack.back().ChildCount) {3157 NodeState &Top = Stack.back();3158 CumulativeString.resize(Top.ParentStringLength);3159 for (;*Top.Current != 0 && Top.Current < Trie.end(); Top.Current++) {3160 char C = *Top.Current;3161 CumulativeString.push_back(C);3162 }3163 if (Top.Current >= Trie.end()) {3164 *E = malformedError("edge sub-string in export trie data at node: 0x" +3165 Twine::utohexstr(Top.Start - Trie.begin()) +3166 " for child #" + Twine((int)Top.NextChildIndex) +3167 " extends past end of trie data");3168 moveToEnd();3169 return;3170 }3171 Top.Current += 1;3172 uint64_t childNodeIndex = readULEB128(Top.Current, &error);3173 if (error) {3174 *E = malformedError("child node offset " + Twine(error) +3175 " in export trie data at node: 0x" +3176 Twine::utohexstr(Top.Start - Trie.begin()));3177 moveToEnd();3178 return;3179 }3180 for (const NodeState &node : nodes()) {3181 if (node.Start == Trie.begin() + childNodeIndex){3182 *E = malformedError("loop in children in export trie data at node: 0x" +3183 Twine::utohexstr(Top.Start - Trie.begin()) +3184 " back to node: 0x" +3185 Twine::utohexstr(childNodeIndex));3186 moveToEnd();3187 return;3188 }3189 }3190 Top.NextChildIndex += 1;3191 pushNode(childNodeIndex);3192 if (*E)3193 return;3194 }3195 if (!Stack.back().IsExportNode) {3196 *E = malformedError("node is not an export node in export trie data at "3197 "node: 0x" +3198 Twine::utohexstr(Stack.back().Start - Trie.begin()));3199 moveToEnd();3200 return;3201 }3202}3203 3204// We have a trie data structure and need a way to walk it that is compatible3205// with the C++ iterator model. The solution is a non-recursive depth first3206// traversal where the iterator contains a stack of parent nodes along with a3207// string that is the accumulation of all edge strings along the parent chain3208// to this point.3209//3210// There is one "export" node for each exported symbol. But because some3211// symbols may be a prefix of another symbol (e.g. _dup and _dup2), an export3212// node may have child nodes too.3213//3214// The algorithm for moveNext() is to keep moving down the leftmost unvisited3215// child until hitting a node with no children (which is an export node or3216// else the trie is malformed). On the way down, each node is pushed on the3217// stack ivar. If there is no more ways down, it pops up one and tries to go3218// down a sibling path until a childless node is reached.3219void ExportEntry::moveNext() {3220 assert(!Stack.empty() && "ExportEntry::moveNext() with empty node stack");3221 if (!Stack.back().IsExportNode) {3222 *E = malformedError("node is not an export node in export trie data at "3223 "node: 0x" +3224 Twine::utohexstr(Stack.back().Start - Trie.begin()));3225 moveToEnd();3226 return;3227 }3228 3229 Stack.pop_back();3230 while (!Stack.empty()) {3231 NodeState &Top = Stack.back();3232 if (Top.NextChildIndex < Top.ChildCount) {3233 pushDownUntilBottom();3234 // Now at the next export node.3235 return;3236 } else {3237 if (Top.IsExportNode) {3238 // This node has no children but is itself an export node.3239 CumulativeString.resize(Top.ParentStringLength);3240 return;3241 }3242 Stack.pop_back();3243 }3244 }3245 Done = true;3246}3247 3248iterator_range<export_iterator>3249MachOObjectFile::exports(Error &E, ArrayRef<uint8_t> Trie,3250 const MachOObjectFile *O) {3251 ExportEntry Start(&E, O, Trie);3252 if (Trie.empty())3253 Start.moveToEnd();3254 else3255 Start.moveToFirst();3256 3257 ExportEntry Finish(&E, O, Trie);3258 Finish.moveToEnd();3259 3260 return make_range(export_iterator(Start), export_iterator(Finish));3261}3262 3263iterator_range<export_iterator> MachOObjectFile::exports(Error &Err) const {3264 ArrayRef<uint8_t> Trie;3265 if (DyldInfoLoadCmd)3266 Trie = getDyldInfoExportsTrie();3267 else if (DyldExportsTrieLoadCmd)3268 Trie = getDyldExportsTrie();3269 3270 return exports(Err, Trie, this);3271}3272 3273MachOAbstractFixupEntry::MachOAbstractFixupEntry(Error *E,3274 const MachOObjectFile *O)3275 : E(E), O(O) {3276 // Cache the vmaddress of __TEXT3277 for (const auto &Command : O->load_commands()) {3278 if (Command.C.cmd == MachO::LC_SEGMENT) {3279 MachO::segment_command SLC = O->getSegmentLoadCommand(Command);3280 if (StringRef(SLC.segname) == "__TEXT") {3281 TextAddress = SLC.vmaddr;3282 break;3283 }3284 } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {3285 MachO::segment_command_64 SLC_64 = O->getSegment64LoadCommand(Command);3286 if (StringRef(SLC_64.segname) == "__TEXT") {3287 TextAddress = SLC_64.vmaddr;3288 break;3289 }3290 }3291 }3292}3293 3294int32_t MachOAbstractFixupEntry::segmentIndex() const { return SegmentIndex; }3295 3296uint64_t MachOAbstractFixupEntry::segmentOffset() const {3297 return SegmentOffset;3298}3299 3300uint64_t MachOAbstractFixupEntry::segmentAddress() const {3301 return O->BindRebaseAddress(SegmentIndex, 0);3302}3303 3304StringRef MachOAbstractFixupEntry::segmentName() const {3305 return O->BindRebaseSegmentName(SegmentIndex);3306}3307 3308StringRef MachOAbstractFixupEntry::sectionName() const {3309 return O->BindRebaseSectionName(SegmentIndex, SegmentOffset);3310}3311 3312uint64_t MachOAbstractFixupEntry::address() const {3313 return O->BindRebaseAddress(SegmentIndex, SegmentOffset);3314}3315 3316StringRef MachOAbstractFixupEntry::symbolName() const { return SymbolName; }3317 3318int64_t MachOAbstractFixupEntry::addend() const { return Addend; }3319 3320uint32_t MachOAbstractFixupEntry::flags() const { return Flags; }3321 3322int MachOAbstractFixupEntry::ordinal() const { return Ordinal; }3323 3324StringRef MachOAbstractFixupEntry::typeName() const { return "unknown"; }3325 3326void MachOAbstractFixupEntry::moveToFirst() {3327 SegmentOffset = 0;3328 SegmentIndex = -1;3329 Ordinal = 0;3330 Flags = 0;3331 Addend = 0;3332 Done = false;3333}3334 3335void MachOAbstractFixupEntry::moveToEnd() { Done = true; }3336 3337void MachOAbstractFixupEntry::moveNext() {}3338 3339MachOChainedFixupEntry::MachOChainedFixupEntry(Error *E,3340 const MachOObjectFile *O,3341 bool Parse)3342 : MachOAbstractFixupEntry(E, O) {3343 ErrorAsOutParameter e(E);3344 if (!Parse)3345 return;3346 3347 if (auto FixupTargetsOrErr = O->getDyldChainedFixupTargets()) {3348 FixupTargets = *FixupTargetsOrErr;3349 } else {3350 *E = FixupTargetsOrErr.takeError();3351 return;3352 }3353 3354 if (auto SegmentsOrErr = O->getChainedFixupsSegments()) {3355 Segments = std::move(SegmentsOrErr->second);3356 } else {3357 *E = SegmentsOrErr.takeError();3358 return;3359 }3360}3361 3362void MachOChainedFixupEntry::findNextPageWithFixups() {3363 auto FindInSegment = [this]() {3364 const ChainedFixupsSegment &SegInfo = Segments[InfoSegIndex];3365 while (PageIndex < SegInfo.PageStarts.size() &&3366 SegInfo.PageStarts[PageIndex] == MachO::DYLD_CHAINED_PTR_START_NONE)3367 ++PageIndex;3368 return PageIndex < SegInfo.PageStarts.size();3369 };3370 3371 while (InfoSegIndex < Segments.size()) {3372 if (FindInSegment()) {3373 PageOffset = Segments[InfoSegIndex].PageStarts[PageIndex];3374 SegmentData = O->getSegmentContents(Segments[InfoSegIndex].SegIdx);3375 return;3376 }3377 3378 InfoSegIndex++;3379 PageIndex = 0;3380 }3381}3382 3383void MachOChainedFixupEntry::moveToFirst() {3384 MachOAbstractFixupEntry::moveToFirst();3385 if (Segments.empty()) {3386 Done = true;3387 return;3388 }3389 3390 InfoSegIndex = 0;3391 PageIndex = 0;3392 3393 findNextPageWithFixups();3394 moveNext();3395}3396 3397void MachOChainedFixupEntry::moveToEnd() {3398 MachOAbstractFixupEntry::moveToEnd();3399}3400 3401void MachOChainedFixupEntry::moveNext() {3402 ErrorAsOutParameter ErrAsOutParam(E);3403 3404 if (InfoSegIndex == Segments.size()) {3405 Done = true;3406 return;3407 }3408 3409 const ChainedFixupsSegment &SegInfo = Segments[InfoSegIndex];3410 SegmentIndex = SegInfo.SegIdx;3411 SegmentOffset = SegInfo.Header.page_size * PageIndex + PageOffset;3412 3413 // FIXME: Handle other pointer formats.3414 uint16_t PointerFormat = SegInfo.Header.pointer_format;3415 if (PointerFormat != MachO::DYLD_CHAINED_PTR_64 &&3416 PointerFormat != MachO::DYLD_CHAINED_PTR_64_OFFSET) {3417 *E = createError("segment " + Twine(SegmentIndex) +3418 " has unsupported chained fixup pointer_format " +3419 Twine(PointerFormat));3420 moveToEnd();3421 return;3422 }3423 3424 Ordinal = 0;3425 Flags = 0;3426 Addend = 0;3427 PointerValue = 0;3428 SymbolName = {};3429 3430 if (SegmentOffset + sizeof(RawValue) > SegmentData.size()) {3431 *E = malformedError("fixup in segment " + Twine(SegmentIndex) +3432 " at offset " + Twine(SegmentOffset) +3433 " extends past segment's end");3434 moveToEnd();3435 return;3436 }3437 3438 static_assert(sizeof(RawValue) == sizeof(MachO::dyld_chained_import_addend));3439 memcpy(&RawValue, SegmentData.data() + SegmentOffset, sizeof(RawValue));3440 if (O->isLittleEndian() != sys::IsLittleEndianHost)3441 sys::swapByteOrder(RawValue);3442 3443 // The bit extraction below assumes little-endian fixup entries.3444 assert(O->isLittleEndian() && "big-endian object should have been rejected "3445 "by getDyldChainedFixupTargets()");3446 auto Field = [this](uint8_t Right, uint8_t Count) {3447 return (RawValue >> Right) & ((1ULL << Count) - 1);3448 };3449 3450 // The `bind` field (most significant bit) of the encoded fixup determines3451 // whether it is dyld_chained_ptr_64_bind or dyld_chained_ptr_64_rebase.3452 bool IsBind = Field(63, 1);3453 Kind = IsBind ? FixupKind::Bind : FixupKind::Rebase;3454 uint32_t Next = Field(51, 12);3455 if (IsBind) {3456 uint32_t ImportOrdinal = Field(0, 24);3457 uint8_t InlineAddend = Field(24, 8);3458 3459 if (ImportOrdinal >= FixupTargets.size()) {3460 *E = malformedError("fixup in segment " + Twine(SegmentIndex) +3461 " at offset " + Twine(SegmentOffset) +3462 " has out-of range import ordinal " +3463 Twine(ImportOrdinal));3464 moveToEnd();3465 return;3466 }3467 3468 ChainedFixupTarget &Target = FixupTargets[ImportOrdinal];3469 Ordinal = Target.libOrdinal();3470 Addend = InlineAddend ? InlineAddend : Target.addend();3471 Flags = Target.weakImport() ? MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT : 0;3472 SymbolName = Target.symbolName();3473 } else {3474 uint64_t Target = Field(0, 36);3475 uint64_t High8 = Field(36, 8);3476 3477 PointerValue = Target | (High8 << 56);3478 if (PointerFormat == MachO::DYLD_CHAINED_PTR_64_OFFSET)3479 PointerValue += textAddress();3480 }3481 3482 // The stride is 4 bytes for DYLD_CHAINED_PTR_64(_OFFSET).3483 if (Next != 0) {3484 PageOffset += 4 * Next;3485 } else {3486 ++PageIndex;3487 findNextPageWithFixups();3488 }3489}3490 3491bool MachOChainedFixupEntry::operator==(3492 const MachOChainedFixupEntry &Other) const {3493 if (Done && Other.Done)3494 return true;3495 if (Done != Other.Done)3496 return false;3497 return InfoSegIndex == Other.InfoSegIndex && PageIndex == Other.PageIndex &&3498 PageOffset == Other.PageOffset;3499}3500 3501MachORebaseEntry::MachORebaseEntry(Error *E, const MachOObjectFile *O,3502 ArrayRef<uint8_t> Bytes, bool is64Bit)3503 : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()),3504 PointerSize(is64Bit ? 8 : 4) {}3505 3506void MachORebaseEntry::moveToFirst() {3507 Ptr = Opcodes.begin();3508 moveNext();3509}3510 3511void MachORebaseEntry::moveToEnd() {3512 Ptr = Opcodes.end();3513 RemainingLoopCount = 0;3514 Done = true;3515}3516 3517void MachORebaseEntry::moveNext() {3518 ErrorAsOutParameter ErrAsOutParam(E);3519 // If in the middle of some loop, move to next rebasing in loop.3520 SegmentOffset += AdvanceAmount;3521 if (RemainingLoopCount) {3522 --RemainingLoopCount;3523 return;3524 }3525 3526 bool More = true;3527 while (More) {3528 // REBASE_OPCODE_DONE is only used for padding if we are not aligned to3529 // pointer size. Therefore it is possible to reach the end without ever3530 // having seen REBASE_OPCODE_DONE.3531 if (Ptr == Opcodes.end()) {3532 Done = true;3533 return;3534 }3535 3536 // Parse next opcode and set up next loop.3537 const uint8_t *OpcodeStart = Ptr;3538 uint8_t Byte = *Ptr++;3539 uint8_t ImmValue = Byte & MachO::REBASE_IMMEDIATE_MASK;3540 uint8_t Opcode = Byte & MachO::REBASE_OPCODE_MASK;3541 uint64_t Count, Skip;3542 const char *error = nullptr;3543 switch (Opcode) {3544 case MachO::REBASE_OPCODE_DONE:3545 More = false;3546 Done = true;3547 moveToEnd();3548 DEBUG_WITH_TYPE("mach-o-rebase", dbgs() << "REBASE_OPCODE_DONE\n");3549 break;3550 case MachO::REBASE_OPCODE_SET_TYPE_IMM:3551 RebaseType = ImmValue;3552 if (RebaseType > MachO::REBASE_TYPE_TEXT_PCREL32) {3553 *E = malformedError("for REBASE_OPCODE_SET_TYPE_IMM bad bind type: " +3554 Twine((int)RebaseType) + " for opcode at: 0x" +3555 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3556 moveToEnd();3557 return;3558 }3559 DEBUG_WITH_TYPE(3560 "mach-o-rebase",3561 dbgs() << "REBASE_OPCODE_SET_TYPE_IMM: "3562 << "RebaseType=" << (int) RebaseType << "\n");3563 break;3564 case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:3565 SegmentIndex = ImmValue;3566 SegmentOffset = readULEB128(&error);3567 if (error) {3568 *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +3569 Twine(error) + " for opcode at: 0x" +3570 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3571 moveToEnd();3572 return;3573 }3574 error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,3575 PointerSize);3576 if (error) {3577 *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +3578 Twine(error) + " for opcode at: 0x" +3579 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3580 moveToEnd();3581 return;3582 }3583 DEBUG_WITH_TYPE(3584 "mach-o-rebase",3585 dbgs() << "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: "3586 << "SegmentIndex=" << SegmentIndex << ", "3587 << format("SegmentOffset=0x%06X", SegmentOffset)3588 << "\n");3589 break;3590 case MachO::REBASE_OPCODE_ADD_ADDR_ULEB:3591 SegmentOffset += readULEB128(&error);3592 if (error) {3593 *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " + Twine(error) +3594 " for opcode at: 0x" +3595 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3596 moveToEnd();3597 return;3598 }3599 error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,3600 PointerSize);3601 if (error) {3602 *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " + Twine(error) +3603 " for opcode at: 0x" +3604 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3605 moveToEnd();3606 return;3607 }3608 DEBUG_WITH_TYPE("mach-o-rebase",3609 dbgs() << "REBASE_OPCODE_ADD_ADDR_ULEB: "3610 << format("SegmentOffset=0x%06X",3611 SegmentOffset) << "\n");3612 break;3613 case MachO::REBASE_OPCODE_ADD_ADDR_IMM_SCALED:3614 SegmentOffset += ImmValue * PointerSize;3615 error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,3616 PointerSize);3617 if (error) {3618 *E = malformedError("for REBASE_OPCODE_ADD_ADDR_IMM_SCALED " +3619 Twine(error) + " for opcode at: 0x" +3620 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3621 moveToEnd();3622 return;3623 }3624 DEBUG_WITH_TYPE("mach-o-rebase",3625 dbgs() << "REBASE_OPCODE_ADD_ADDR_IMM_SCALED: "3626 << format("SegmentOffset=0x%06X",3627 SegmentOffset) << "\n");3628 break;3629 case MachO::REBASE_OPCODE_DO_REBASE_IMM_TIMES:3630 AdvanceAmount = PointerSize;3631 Skip = 0;3632 Count = ImmValue;3633 if (ImmValue != 0)3634 RemainingLoopCount = ImmValue - 1;3635 else3636 RemainingLoopCount = 0;3637 error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,3638 PointerSize, Count, Skip);3639 if (error) {3640 *E = malformedError("for REBASE_OPCODE_DO_REBASE_IMM_TIMES " +3641 Twine(error) + " for opcode at: 0x" +3642 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3643 moveToEnd();3644 return;3645 }3646 DEBUG_WITH_TYPE(3647 "mach-o-rebase",3648 dbgs() << "REBASE_OPCODE_DO_REBASE_IMM_TIMES: "3649 << format("SegmentOffset=0x%06X", SegmentOffset)3650 << ", AdvanceAmount=" << AdvanceAmount3651 << ", RemainingLoopCount=" << RemainingLoopCount3652 << "\n");3653 return;3654 case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES:3655 AdvanceAmount = PointerSize;3656 Skip = 0;3657 Count = readULEB128(&error);3658 if (error) {3659 *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " +3660 Twine(error) + " for opcode at: 0x" +3661 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3662 moveToEnd();3663 return;3664 }3665 if (Count != 0)3666 RemainingLoopCount = Count - 1;3667 else3668 RemainingLoopCount = 0;3669 error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,3670 PointerSize, Count, Skip);3671 if (error) {3672 *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " +3673 Twine(error) + " for opcode at: 0x" +3674 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3675 moveToEnd();3676 return;3677 }3678 DEBUG_WITH_TYPE(3679 "mach-o-rebase",3680 dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES: "3681 << format("SegmentOffset=0x%06X", SegmentOffset)3682 << ", AdvanceAmount=" << AdvanceAmount3683 << ", RemainingLoopCount=" << RemainingLoopCount3684 << "\n");3685 return;3686 case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:3687 Skip = readULEB128(&error);3688 if (error) {3689 *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " +3690 Twine(error) + " for opcode at: 0x" +3691 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3692 moveToEnd();3693 return;3694 }3695 AdvanceAmount = Skip + PointerSize;3696 Count = 1;3697 RemainingLoopCount = 0;3698 error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,3699 PointerSize, Count, Skip);3700 if (error) {3701 *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " +3702 Twine(error) + " for opcode at: 0x" +3703 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3704 moveToEnd();3705 return;3706 }3707 DEBUG_WITH_TYPE(3708 "mach-o-rebase",3709 dbgs() << "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: "3710 << format("SegmentOffset=0x%06X", SegmentOffset)3711 << ", AdvanceAmount=" << AdvanceAmount3712 << ", RemainingLoopCount=" << RemainingLoopCount3713 << "\n");3714 return;3715 case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:3716 Count = readULEB128(&error);3717 if (error) {3718 *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"3719 "ULEB " +3720 Twine(error) + " for opcode at: 0x" +3721 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3722 moveToEnd();3723 return;3724 }3725 if (Count != 0)3726 RemainingLoopCount = Count - 1;3727 else3728 RemainingLoopCount = 0;3729 Skip = readULEB128(&error);3730 if (error) {3731 *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"3732 "ULEB " +3733 Twine(error) + " for opcode at: 0x" +3734 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3735 moveToEnd();3736 return;3737 }3738 AdvanceAmount = Skip + PointerSize;3739 3740 error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,3741 PointerSize, Count, Skip);3742 if (error) {3743 *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"3744 "ULEB " +3745 Twine(error) + " for opcode at: 0x" +3746 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3747 moveToEnd();3748 return;3749 }3750 DEBUG_WITH_TYPE(3751 "mach-o-rebase",3752 dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: "3753 << format("SegmentOffset=0x%06X", SegmentOffset)3754 << ", AdvanceAmount=" << AdvanceAmount3755 << ", RemainingLoopCount=" << RemainingLoopCount3756 << "\n");3757 return;3758 default:3759 *E = malformedError("bad rebase info (bad opcode value 0x" +3760 Twine::utohexstr(Opcode) + " for opcode at: 0x" +3761 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3762 moveToEnd();3763 return;3764 }3765 }3766}3767 3768uint64_t MachORebaseEntry::readULEB128(const char **error) {3769 unsigned Count;3770 uint64_t Result = decodeULEB128(Ptr, &Count, Opcodes.end(), error);3771 Ptr += Count;3772 if (Ptr > Opcodes.end())3773 Ptr = Opcodes.end();3774 return Result;3775}3776 3777int32_t MachORebaseEntry::segmentIndex() const { return SegmentIndex; }3778 3779uint64_t MachORebaseEntry::segmentOffset() const { return SegmentOffset; }3780 3781StringRef MachORebaseEntry::typeName() const {3782 switch (RebaseType) {3783 case MachO::REBASE_TYPE_POINTER:3784 return "pointer";3785 case MachO::REBASE_TYPE_TEXT_ABSOLUTE32:3786 return "text abs32";3787 case MachO::REBASE_TYPE_TEXT_PCREL32:3788 return "text rel32";3789 }3790 return "unknown";3791}3792 3793// For use with the SegIndex of a checked Mach-O Rebase entry3794// to get the segment name.3795StringRef MachORebaseEntry::segmentName() const {3796 return O->BindRebaseSegmentName(SegmentIndex);3797}3798 3799// For use with a SegIndex,SegOffset pair from a checked Mach-O Rebase entry3800// to get the section name.3801StringRef MachORebaseEntry::sectionName() const {3802 return O->BindRebaseSectionName(SegmentIndex, SegmentOffset);3803}3804 3805// For use with a SegIndex,SegOffset pair from a checked Mach-O Rebase entry3806// to get the address.3807uint64_t MachORebaseEntry::address() const {3808 return O->BindRebaseAddress(SegmentIndex, SegmentOffset);3809}3810 3811bool MachORebaseEntry::operator==(const MachORebaseEntry &Other) const {3812#ifdef EXPENSIVE_CHECKS3813 assert(Opcodes == Other.Opcodes && "compare iterators of different files");3814#else3815 assert(Opcodes.data() == Other.Opcodes.data() && "compare iterators of different files");3816#endif3817 return (Ptr == Other.Ptr) &&3818 (RemainingLoopCount == Other.RemainingLoopCount) &&3819 (Done == Other.Done);3820}3821 3822iterator_range<rebase_iterator>3823MachOObjectFile::rebaseTable(Error &Err, MachOObjectFile *O,3824 ArrayRef<uint8_t> Opcodes, bool is64) {3825 if (O->BindRebaseSectionTable == nullptr)3826 O->BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(O);3827 MachORebaseEntry Start(&Err, O, Opcodes, is64);3828 Start.moveToFirst();3829 3830 MachORebaseEntry Finish(&Err, O, Opcodes, is64);3831 Finish.moveToEnd();3832 3833 return make_range(rebase_iterator(Start), rebase_iterator(Finish));3834}3835 3836iterator_range<rebase_iterator> MachOObjectFile::rebaseTable(Error &Err) {3837 return rebaseTable(Err, this, getDyldInfoRebaseOpcodes(), is64Bit());3838}3839 3840MachOBindEntry::MachOBindEntry(Error *E, const MachOObjectFile *O,3841 ArrayRef<uint8_t> Bytes, bool is64Bit, Kind BK)3842 : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()),3843 PointerSize(is64Bit ? 8 : 4), TableKind(BK) {}3844 3845void MachOBindEntry::moveToFirst() {3846 Ptr = Opcodes.begin();3847 moveNext();3848}3849 3850void MachOBindEntry::moveToEnd() {3851 Ptr = Opcodes.end();3852 RemainingLoopCount = 0;3853 Done = true;3854}3855 3856void MachOBindEntry::moveNext() {3857 ErrorAsOutParameter ErrAsOutParam(E);3858 // If in the middle of some loop, move to next binding in loop.3859 SegmentOffset += AdvanceAmount;3860 if (RemainingLoopCount) {3861 --RemainingLoopCount;3862 return;3863 }3864 3865 bool More = true;3866 while (More) {3867 // BIND_OPCODE_DONE is only used for padding if we are not aligned to3868 // pointer size. Therefore it is possible to reach the end without ever3869 // having seen BIND_OPCODE_DONE.3870 if (Ptr == Opcodes.end()) {3871 Done = true;3872 return;3873 }3874 3875 // Parse next opcode and set up next loop.3876 const uint8_t *OpcodeStart = Ptr;3877 uint8_t Byte = *Ptr++;3878 uint8_t ImmValue = Byte & MachO::BIND_IMMEDIATE_MASK;3879 uint8_t Opcode = Byte & MachO::BIND_OPCODE_MASK;3880 int8_t SignExtended;3881 const uint8_t *SymStart;3882 uint64_t Count, Skip;3883 const char *error = nullptr;3884 switch (Opcode) {3885 case MachO::BIND_OPCODE_DONE:3886 if (TableKind == Kind::Lazy) {3887 // Lazying bindings have a DONE opcode between entries. Need to ignore3888 // it to advance to next entry. But need not if this is last entry.3889 bool NotLastEntry = false;3890 for (const uint8_t *P = Ptr; P < Opcodes.end(); ++P) {3891 if (*P) {3892 NotLastEntry = true;3893 }3894 }3895 if (NotLastEntry)3896 break;3897 }3898 More = false;3899 moveToEnd();3900 DEBUG_WITH_TYPE("mach-o-bind", dbgs() << "BIND_OPCODE_DONE\n");3901 break;3902 case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:3903 if (TableKind == Kind::Weak) {3904 *E = malformedError("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM not allowed in "3905 "weak bind table for opcode at: 0x" +3906 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3907 moveToEnd();3908 return;3909 }3910 Ordinal = ImmValue;3911 LibraryOrdinalSet = true;3912 if (ImmValue > O->getLibraryCount()) {3913 *E = malformedError("for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB bad "3914 "library ordinal: " +3915 Twine((int)ImmValue) + " (max " +3916 Twine((int)O->getLibraryCount()) +3917 ") for opcode at: 0x" +3918 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3919 moveToEnd();3920 return;3921 }3922 DEBUG_WITH_TYPE(3923 "mach-o-bind",3924 dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: "3925 << "Ordinal=" << Ordinal << "\n");3926 break;3927 case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:3928 if (TableKind == Kind::Weak) {3929 *E = malformedError("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB not allowed in "3930 "weak bind table for opcode at: 0x" +3931 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3932 moveToEnd();3933 return;3934 }3935 Ordinal = readULEB128(&error);3936 LibraryOrdinalSet = true;3937 if (error) {3938 *E = malformedError("for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB " +3939 Twine(error) + " for opcode at: 0x" +3940 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3941 moveToEnd();3942 return;3943 }3944 if (Ordinal > (int)O->getLibraryCount()) {3945 *E = malformedError("for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB bad "3946 "library ordinal: " +3947 Twine((int)Ordinal) + " (max " +3948 Twine((int)O->getLibraryCount()) +3949 ") for opcode at: 0x" +3950 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3951 moveToEnd();3952 return;3953 }3954 DEBUG_WITH_TYPE(3955 "mach-o-bind",3956 dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: "3957 << "Ordinal=" << Ordinal << "\n");3958 break;3959 case MachO::BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:3960 if (TableKind == Kind::Weak) {3961 *E = malformedError("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM not allowed in "3962 "weak bind table for opcode at: 0x" +3963 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3964 moveToEnd();3965 return;3966 }3967 if (ImmValue) {3968 SignExtended = MachO::BIND_OPCODE_MASK | ImmValue;3969 Ordinal = SignExtended;3970 if (Ordinal < MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP) {3971 *E = malformedError("for BIND_OPCODE_SET_DYLIB_SPECIAL_IMM unknown "3972 "special ordinal: " +3973 Twine((int)Ordinal) + " for opcode at: 0x" +3974 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3975 moveToEnd();3976 return;3977 }3978 } else3979 Ordinal = 0;3980 LibraryOrdinalSet = true;3981 DEBUG_WITH_TYPE(3982 "mach-o-bind",3983 dbgs() << "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: "3984 << "Ordinal=" << Ordinal << "\n");3985 break;3986 case MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:3987 Flags = ImmValue;3988 SymStart = Ptr;3989 while (*Ptr && (Ptr < Opcodes.end())) {3990 ++Ptr;3991 }3992 if (Ptr == Opcodes.end()) {3993 *E = malformedError(3994 "for BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM "3995 "symbol name extends past opcodes for opcode at: 0x" +3996 Twine::utohexstr(OpcodeStart - Opcodes.begin()));3997 moveToEnd();3998 return;3999 }4000 SymbolName = StringRef(reinterpret_cast<const char*>(SymStart),4001 Ptr-SymStart);4002 ++Ptr;4003 DEBUG_WITH_TYPE(4004 "mach-o-bind",4005 dbgs() << "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: "4006 << "SymbolName=" << SymbolName << "\n");4007 if (TableKind == Kind::Weak) {4008 if (ImmValue & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION)4009 return;4010 }4011 break;4012 case MachO::BIND_OPCODE_SET_TYPE_IMM:4013 BindType = ImmValue;4014 if (ImmValue > MachO::BIND_TYPE_TEXT_PCREL32) {4015 *E = malformedError("for BIND_OPCODE_SET_TYPE_IMM bad bind type: " +4016 Twine((int)ImmValue) + " for opcode at: 0x" +4017 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4018 moveToEnd();4019 return;4020 }4021 DEBUG_WITH_TYPE(4022 "mach-o-bind",4023 dbgs() << "BIND_OPCODE_SET_TYPE_IMM: "4024 << "BindType=" << (int)BindType << "\n");4025 break;4026 case MachO::BIND_OPCODE_SET_ADDEND_SLEB:4027 Addend = readSLEB128(&error);4028 if (error) {4029 *E = malformedError("for BIND_OPCODE_SET_ADDEND_SLEB " + Twine(error) +4030 " for opcode at: 0x" +4031 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4032 moveToEnd();4033 return;4034 }4035 DEBUG_WITH_TYPE(4036 "mach-o-bind",4037 dbgs() << "BIND_OPCODE_SET_ADDEND_SLEB: "4038 << "Addend=" << Addend << "\n");4039 break;4040 case MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:4041 SegmentIndex = ImmValue;4042 SegmentOffset = readULEB128(&error);4043 if (error) {4044 *E = malformedError("for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +4045 Twine(error) + " for opcode at: 0x" +4046 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4047 moveToEnd();4048 return;4049 }4050 error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,4051 PointerSize);4052 if (error) {4053 *E = malformedError("for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +4054 Twine(error) + " for opcode at: 0x" +4055 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4056 moveToEnd();4057 return;4058 }4059 DEBUG_WITH_TYPE(4060 "mach-o-bind",4061 dbgs() << "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: "4062 << "SegmentIndex=" << SegmentIndex << ", "4063 << format("SegmentOffset=0x%06X", SegmentOffset)4064 << "\n");4065 break;4066 case MachO::BIND_OPCODE_ADD_ADDR_ULEB:4067 SegmentOffset += readULEB128(&error);4068 if (error) {4069 *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB " + Twine(error) +4070 " for opcode at: 0x" +4071 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4072 moveToEnd();4073 return;4074 }4075 error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,4076 PointerSize);4077 if (error) {4078 *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB " + Twine(error) +4079 " for opcode at: 0x" +4080 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4081 moveToEnd();4082 return;4083 }4084 DEBUG_WITH_TYPE("mach-o-bind",4085 dbgs() << "BIND_OPCODE_ADD_ADDR_ULEB: "4086 << format("SegmentOffset=0x%06X",4087 SegmentOffset) << "\n");4088 break;4089 case MachO::BIND_OPCODE_DO_BIND:4090 AdvanceAmount = PointerSize;4091 RemainingLoopCount = 0;4092 error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,4093 PointerSize);4094 if (error) {4095 *E = malformedError("for BIND_OPCODE_DO_BIND " + Twine(error) +4096 " for opcode at: 0x" +4097 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4098 moveToEnd();4099 return;4100 }4101 if (SymbolName == StringRef()) {4102 *E = malformedError(4103 "for BIND_OPCODE_DO_BIND missing preceding "4104 "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for opcode at: 0x" +4105 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4106 moveToEnd();4107 return;4108 }4109 if (!LibraryOrdinalSet && TableKind != Kind::Weak) {4110 *E =4111 malformedError("for BIND_OPCODE_DO_BIND missing preceding "4112 "BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode at: 0x" +4113 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4114 moveToEnd();4115 return;4116 }4117 DEBUG_WITH_TYPE("mach-o-bind",4118 dbgs() << "BIND_OPCODE_DO_BIND: "4119 << format("SegmentOffset=0x%06X",4120 SegmentOffset) << "\n");4121 return;4122 case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:4123 if (TableKind == Kind::Lazy) {4124 *E = malformedError("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB not allowed in "4125 "lazy bind table for opcode at: 0x" +4126 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4127 moveToEnd();4128 return;4129 }4130 error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,4131 PointerSize);4132 if (error) {4133 *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB " +4134 Twine(error) + " for opcode at: 0x" +4135 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4136 moveToEnd();4137 return;4138 }4139 if (SymbolName == StringRef()) {4140 *E = malformedError(4141 "for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB missing "4142 "preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for opcode "4143 "at: 0x" +4144 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4145 moveToEnd();4146 return;4147 }4148 if (!LibraryOrdinalSet && TableKind != Kind::Weak) {4149 *E = malformedError(4150 "for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB missing "4151 "preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode at: 0x" +4152 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4153 moveToEnd();4154 return;4155 }4156 AdvanceAmount = readULEB128(&error) + PointerSize;4157 if (error) {4158 *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB " +4159 Twine(error) + " for opcode at: 0x" +4160 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4161 moveToEnd();4162 return;4163 }4164 // Note, this is not really an error until the next bind but make no sense4165 // for a BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB to not be followed by another4166 // bind operation.4167 error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset +4168 AdvanceAmount, PointerSize);4169 if (error) {4170 *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB (after adding "4171 "ULEB) " +4172 Twine(error) + " for opcode at: 0x" +4173 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4174 moveToEnd();4175 return;4176 }4177 RemainingLoopCount = 0;4178 DEBUG_WITH_TYPE(4179 "mach-o-bind",4180 dbgs() << "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: "4181 << format("SegmentOffset=0x%06X", SegmentOffset)4182 << ", AdvanceAmount=" << AdvanceAmount4183 << ", RemainingLoopCount=" << RemainingLoopCount4184 << "\n");4185 return;4186 case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:4187 if (TableKind == Kind::Lazy) {4188 *E = malformedError("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED not "4189 "allowed in lazy bind table for opcode at: 0x" +4190 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4191 moveToEnd();4192 return;4193 }4194 if (SymbolName == StringRef()) {4195 *E = malformedError(4196 "for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED "4197 "missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for "4198 "opcode at: 0x" +4199 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4200 moveToEnd();4201 return;4202 }4203 if (!LibraryOrdinalSet && TableKind != Kind::Weak) {4204 *E = malformedError(4205 "for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED "4206 "missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode "4207 "at: 0x" +4208 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4209 moveToEnd();4210 return;4211 }4212 AdvanceAmount = ImmValue * PointerSize + PointerSize;4213 RemainingLoopCount = 0;4214 error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset +4215 AdvanceAmount, PointerSize);4216 if (error) {4217 *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " +4218 Twine(error) + " for opcode at: 0x" +4219 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4220 moveToEnd();4221 return;4222 }4223 DEBUG_WITH_TYPE("mach-o-bind",4224 dbgs()4225 << "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: "4226 << format("SegmentOffset=0x%06X", SegmentOffset) << "\n");4227 return;4228 case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:4229 if (TableKind == Kind::Lazy) {4230 *E = malformedError("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB not "4231 "allowed in lazy bind table for opcode at: 0x" +4232 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4233 moveToEnd();4234 return;4235 }4236 Count = readULEB128(&error);4237 if (Count != 0)4238 RemainingLoopCount = Count - 1;4239 else4240 RemainingLoopCount = 0;4241 if (error) {4242 *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB "4243 " (count value) " +4244 Twine(error) + " for opcode at: 0x" +4245 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4246 moveToEnd();4247 return;4248 }4249 Skip = readULEB128(&error);4250 AdvanceAmount = Skip + PointerSize;4251 if (error) {4252 *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB "4253 " (skip value) " +4254 Twine(error) + " for opcode at: 0x" +4255 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4256 moveToEnd();4257 return;4258 }4259 if (SymbolName == StringRef()) {4260 *E = malformedError(4261 "for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB "4262 "missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for "4263 "opcode at: 0x" +4264 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4265 moveToEnd();4266 return;4267 }4268 if (!LibraryOrdinalSet && TableKind != Kind::Weak) {4269 *E = malformedError(4270 "for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB "4271 "missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode "4272 "at: 0x" +4273 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4274 moveToEnd();4275 return;4276 }4277 error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,4278 PointerSize, Count, Skip);4279 if (error) {4280 *E =4281 malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " +4282 Twine(error) + " for opcode at: 0x" +4283 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4284 moveToEnd();4285 return;4286 }4287 DEBUG_WITH_TYPE(4288 "mach-o-bind",4289 dbgs() << "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: "4290 << format("SegmentOffset=0x%06X", SegmentOffset)4291 << ", AdvanceAmount=" << AdvanceAmount4292 << ", RemainingLoopCount=" << RemainingLoopCount4293 << "\n");4294 return;4295 default:4296 *E = malformedError("bad bind info (bad opcode value 0x" +4297 Twine::utohexstr(Opcode) + " for opcode at: 0x" +4298 Twine::utohexstr(OpcodeStart - Opcodes.begin()));4299 moveToEnd();4300 return;4301 }4302 }4303}4304 4305uint64_t MachOBindEntry::readULEB128(const char **error) {4306 unsigned Count;4307 uint64_t Result = decodeULEB128(Ptr, &Count, Opcodes.end(), error);4308 Ptr += Count;4309 if (Ptr > Opcodes.end())4310 Ptr = Opcodes.end();4311 return Result;4312}4313 4314int64_t MachOBindEntry::readSLEB128(const char **error) {4315 unsigned Count;4316 int64_t Result = decodeSLEB128(Ptr, &Count, Opcodes.end(), error);4317 Ptr += Count;4318 if (Ptr > Opcodes.end())4319 Ptr = Opcodes.end();4320 return Result;4321}4322 4323int32_t MachOBindEntry::segmentIndex() const { return SegmentIndex; }4324 4325uint64_t MachOBindEntry::segmentOffset() const { return SegmentOffset; }4326 4327StringRef MachOBindEntry::typeName() const {4328 switch (BindType) {4329 case MachO::BIND_TYPE_POINTER:4330 return "pointer";4331 case MachO::BIND_TYPE_TEXT_ABSOLUTE32:4332 return "text abs32";4333 case MachO::BIND_TYPE_TEXT_PCREL32:4334 return "text rel32";4335 }4336 return "unknown";4337}4338 4339StringRef MachOBindEntry::symbolName() const { return SymbolName; }4340 4341int64_t MachOBindEntry::addend() const { return Addend; }4342 4343uint32_t MachOBindEntry::flags() const { return Flags; }4344 4345int MachOBindEntry::ordinal() const { return Ordinal; }4346 4347// For use with the SegIndex of a checked Mach-O Bind entry4348// to get the segment name.4349StringRef MachOBindEntry::segmentName() const {4350 return O->BindRebaseSegmentName(SegmentIndex);4351}4352 4353// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind entry4354// to get the section name.4355StringRef MachOBindEntry::sectionName() const {4356 return O->BindRebaseSectionName(SegmentIndex, SegmentOffset);4357}4358 4359// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind entry4360// to get the address.4361uint64_t MachOBindEntry::address() const {4362 return O->BindRebaseAddress(SegmentIndex, SegmentOffset);4363}4364 4365bool MachOBindEntry::operator==(const MachOBindEntry &Other) const {4366#ifdef EXPENSIVE_CHECKS4367 assert(Opcodes == Other.Opcodes && "compare iterators of different files");4368#else4369 assert(Opcodes.data() == Other.Opcodes.data() && "compare iterators of different files");4370#endif4371 return (Ptr == Other.Ptr) &&4372 (RemainingLoopCount == Other.RemainingLoopCount) &&4373 (Done == Other.Done);4374}4375 4376// Build table of sections so SegIndex/SegOffset pairs can be translated.4377BindRebaseSegInfo::BindRebaseSegInfo(const object::MachOObjectFile *Obj) {4378 uint32_t CurSegIndex = Obj->hasPageZeroSegment() ? 1 : 0;4379 StringRef CurSegName;4380 uint64_t CurSegAddress;4381 for (const SectionRef &Section : Obj->sections()) {4382 SectionInfo Info;4383 Expected<StringRef> NameOrErr = Section.getName();4384 if (!NameOrErr)4385 consumeError(NameOrErr.takeError());4386 else4387 Info.SectionName = *NameOrErr;4388 Info.Address = Section.getAddress();4389 Info.Size = Section.getSize();4390 Info.SegmentName =4391 Obj->getSectionFinalSegmentName(Section.getRawDataRefImpl());4392 if (Info.SegmentName != CurSegName) {4393 ++CurSegIndex;4394 CurSegName = Info.SegmentName;4395 CurSegAddress = Info.Address;4396 }4397 Info.SegmentIndex = CurSegIndex - 1;4398 Info.OffsetInSegment = Info.Address - CurSegAddress;4399 Info.SegmentStartAddress = CurSegAddress;4400 Sections.push_back(Info);4401 }4402 MaxSegIndex = CurSegIndex;4403}4404 4405// For use with a SegIndex, SegOffset, and PointerSize triple in4406// MachOBindEntry::moveNext() to validate a MachOBindEntry or MachORebaseEntry.4407//4408// Given a SegIndex, SegOffset, and PointerSize, verify a valid section exists4409// that fully contains a pointer at that location. Multiple fixups in a bind4410// (such as with the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode) can4411// be tested via the Count and Skip parameters.4412const char *BindRebaseSegInfo::checkSegAndOffsets(int32_t SegIndex,4413 uint64_t SegOffset,4414 uint8_t PointerSize,4415 uint64_t Count,4416 uint64_t Skip) {4417 if (SegIndex == -1)4418 return "missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB";4419 if (SegIndex >= MaxSegIndex)4420 return "bad segIndex (too large)";4421 for (uint64_t i = 0; i < Count; ++i) {4422 uint64_t Start = SegOffset + i * (PointerSize + Skip);4423 uint64_t End = Start + PointerSize;4424 bool Found = false;4425 for (const SectionInfo &SI : Sections) {4426 if (SI.SegmentIndex != SegIndex)4427 continue;4428 if ((SI.OffsetInSegment<=Start) && (Start<(SI.OffsetInSegment+SI.Size))) {4429 if (End <= SI.OffsetInSegment + SI.Size) {4430 Found = true;4431 break;4432 }4433 else4434 return "bad offset, extends beyond section boundary";4435 }4436 }4437 if (!Found)4438 return "bad offset, not in section";4439 }4440 return nullptr;4441}4442 4443// For use with the SegIndex of a checked Mach-O Bind or Rebase entry4444// to get the segment name.4445StringRef BindRebaseSegInfo::segmentName(int32_t SegIndex) {4446 for (const SectionInfo &SI : Sections) {4447 if (SI.SegmentIndex == SegIndex)4448 return SI.SegmentName;4449 }4450 llvm_unreachable("invalid SegIndex");4451}4452 4453// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase4454// to get the SectionInfo.4455const BindRebaseSegInfo::SectionInfo &BindRebaseSegInfo::findSection(4456 int32_t SegIndex, uint64_t SegOffset) {4457 for (const SectionInfo &SI : Sections) {4458 if (SI.SegmentIndex != SegIndex)4459 continue;4460 if (SI.OffsetInSegment > SegOffset)4461 continue;4462 if (SegOffset >= (SI.OffsetInSegment + SI.Size))4463 continue;4464 return SI;4465 }4466 llvm_unreachable("SegIndex and SegOffset not in any section");4467}4468 4469// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase4470// entry to get the section name.4471StringRef BindRebaseSegInfo::sectionName(int32_t SegIndex,4472 uint64_t SegOffset) {4473 return findSection(SegIndex, SegOffset).SectionName;4474}4475 4476// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase4477// entry to get the address.4478uint64_t BindRebaseSegInfo::address(uint32_t SegIndex, uint64_t OffsetInSeg) {4479 const SectionInfo &SI = findSection(SegIndex, OffsetInSeg);4480 return SI.SegmentStartAddress + OffsetInSeg;4481}4482 4483iterator_range<bind_iterator>4484MachOObjectFile::bindTable(Error &Err, MachOObjectFile *O,4485 ArrayRef<uint8_t> Opcodes, bool is64,4486 MachOBindEntry::Kind BKind) {4487 if (O->BindRebaseSectionTable == nullptr)4488 O->BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(O);4489 MachOBindEntry Start(&Err, O, Opcodes, is64, BKind);4490 Start.moveToFirst();4491 4492 MachOBindEntry Finish(&Err, O, Opcodes, is64, BKind);4493 Finish.moveToEnd();4494 4495 return make_range(bind_iterator(Start), bind_iterator(Finish));4496}4497 4498iterator_range<bind_iterator> MachOObjectFile::bindTable(Error &Err) {4499 return bindTable(Err, this, getDyldInfoBindOpcodes(), is64Bit(),4500 MachOBindEntry::Kind::Regular);4501}4502 4503iterator_range<bind_iterator> MachOObjectFile::lazyBindTable(Error &Err) {4504 return bindTable(Err, this, getDyldInfoLazyBindOpcodes(), is64Bit(),4505 MachOBindEntry::Kind::Lazy);4506}4507 4508iterator_range<bind_iterator> MachOObjectFile::weakBindTable(Error &Err) {4509 return bindTable(Err, this, getDyldInfoWeakBindOpcodes(), is64Bit(),4510 MachOBindEntry::Kind::Weak);4511}4512 4513iterator_range<fixup_iterator> MachOObjectFile::fixupTable(Error &Err) {4514 if (BindRebaseSectionTable == nullptr)4515 BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(this);4516 4517 MachOChainedFixupEntry Start(&Err, this, true);4518 Start.moveToFirst();4519 4520 MachOChainedFixupEntry Finish(&Err, this, false);4521 Finish.moveToEnd();4522 4523 return make_range(fixup_iterator(Start), fixup_iterator(Finish));4524}4525 4526MachOObjectFile::load_command_iterator4527MachOObjectFile::begin_load_commands() const {4528 return LoadCommands.begin();4529}4530 4531MachOObjectFile::load_command_iterator4532MachOObjectFile::end_load_commands() const {4533 return LoadCommands.end();4534}4535 4536iterator_range<MachOObjectFile::load_command_iterator>4537MachOObjectFile::load_commands() const {4538 return make_range(begin_load_commands(), end_load_commands());4539}4540 4541StringRef4542MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const {4543 ArrayRef<char> Raw = getSectionRawFinalSegmentName(Sec);4544 return parseSegmentOrSectionName(Raw.data());4545}4546 4547ArrayRef<char>4548MachOObjectFile::getSectionRawName(DataRefImpl Sec) const {4549 assert(Sec.d.a < Sections.size() && "Should have detected this earlier");4550 const section_base *Base =4551 reinterpret_cast<const section_base *>(Sections[Sec.d.a]);4552 return ArrayRef(Base->sectname);4553}4554 4555ArrayRef<char>4556MachOObjectFile::getSectionRawFinalSegmentName(DataRefImpl Sec) const {4557 assert(Sec.d.a < Sections.size() && "Should have detected this earlier");4558 const section_base *Base =4559 reinterpret_cast<const section_base *>(Sections[Sec.d.a]);4560 return ArrayRef(Base->segname);4561}4562 4563bool4564MachOObjectFile::isRelocationScattered(const MachO::any_relocation_info &RE)4565 const {4566 if (getCPUType(*this) == MachO::CPU_TYPE_X86_64)4567 return false;4568 return getPlainRelocationAddress(RE) & MachO::R_SCATTERED;4569}4570 4571unsigned MachOObjectFile::getPlainRelocationSymbolNum(4572 const MachO::any_relocation_info &RE) const {4573 if (isLittleEndian())4574 return RE.r_word1 & 0xffffff;4575 return RE.r_word1 >> 8;4576}4577 4578bool MachOObjectFile::getPlainRelocationExternal(4579 const MachO::any_relocation_info &RE) const {4580 if (isLittleEndian())4581 return (RE.r_word1 >> 27) & 1;4582 return (RE.r_word1 >> 4) & 1;4583}4584 4585bool MachOObjectFile::getScatteredRelocationScattered(4586 const MachO::any_relocation_info &RE) const {4587 return RE.r_word0 >> 31;4588}4589 4590uint32_t MachOObjectFile::getScatteredRelocationValue(4591 const MachO::any_relocation_info &RE) const {4592 return RE.r_word1;4593}4594 4595uint32_t MachOObjectFile::getScatteredRelocationType(4596 const MachO::any_relocation_info &RE) const {4597 return (RE.r_word0 >> 24) & 0xf;4598}4599 4600unsigned MachOObjectFile::getAnyRelocationAddress(4601 const MachO::any_relocation_info &RE) const {4602 if (isRelocationScattered(RE))4603 return getScatteredRelocationAddress(RE);4604 return getPlainRelocationAddress(RE);4605}4606 4607unsigned MachOObjectFile::getAnyRelocationPCRel(4608 const MachO::any_relocation_info &RE) const {4609 if (isRelocationScattered(RE))4610 return getScatteredRelocationPCRel(RE);4611 return getPlainRelocationPCRel(*this, RE);4612}4613 4614unsigned MachOObjectFile::getAnyRelocationLength(4615 const MachO::any_relocation_info &RE) const {4616 if (isRelocationScattered(RE))4617 return getScatteredRelocationLength(RE);4618 return getPlainRelocationLength(*this, RE);4619}4620 4621unsigned4622MachOObjectFile::getAnyRelocationType(4623 const MachO::any_relocation_info &RE) const {4624 if (isRelocationScattered(RE))4625 return getScatteredRelocationType(RE);4626 return getPlainRelocationType(*this, RE);4627}4628 4629SectionRef4630MachOObjectFile::getAnyRelocationSection(4631 const MachO::any_relocation_info &RE) const {4632 if (isRelocationScattered(RE) || getPlainRelocationExternal(RE))4633 return *section_end();4634 unsigned SecNum = getPlainRelocationSymbolNum(RE);4635 if (SecNum == MachO::R_ABS || SecNum > Sections.size())4636 return *section_end();4637 DataRefImpl DRI;4638 DRI.d.a = SecNum - 1;4639 return SectionRef(DRI, this);4640}4641 4642MachO::section MachOObjectFile::getSection(DataRefImpl DRI) const {4643 assert(DRI.d.a < Sections.size() && "Should have detected this earlier");4644 return getStruct<MachO::section>(*this, Sections[DRI.d.a]);4645}4646 4647MachO::section_64 MachOObjectFile::getSection64(DataRefImpl DRI) const {4648 assert(DRI.d.a < Sections.size() && "Should have detected this earlier");4649 return getStruct<MachO::section_64>(*this, Sections[DRI.d.a]);4650}4651 4652MachO::section MachOObjectFile::getSection(const LoadCommandInfo &L,4653 unsigned Index) const {4654 const char *Sec = getSectionPtr(*this, L, Index);4655 return getStruct<MachO::section>(*this, Sec);4656}4657 4658MachO::section_64 MachOObjectFile::getSection64(const LoadCommandInfo &L,4659 unsigned Index) const {4660 const char *Sec = getSectionPtr(*this, L, Index);4661 return getStruct<MachO::section_64>(*this, Sec);4662}4663 4664MachO::nlist4665MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI) const {4666 const char *P = reinterpret_cast<const char *>(DRI.p);4667 return getStruct<MachO::nlist>(*this, P);4668}4669 4670MachO::nlist_644671MachOObjectFile::getSymbol64TableEntry(DataRefImpl DRI) const {4672 const char *P = reinterpret_cast<const char *>(DRI.p);4673 return getStruct<MachO::nlist_64>(*this, P);4674}4675 4676MachO::linkedit_data_command4677MachOObjectFile::getLinkeditDataLoadCommand(const LoadCommandInfo &L) const {4678 return getStruct<MachO::linkedit_data_command>(*this, L.Ptr);4679}4680 4681MachO::segment_command4682MachOObjectFile::getSegmentLoadCommand(const LoadCommandInfo &L) const {4683 return getStruct<MachO::segment_command>(*this, L.Ptr);4684}4685 4686MachO::segment_command_644687MachOObjectFile::getSegment64LoadCommand(const LoadCommandInfo &L) const {4688 return getStruct<MachO::segment_command_64>(*this, L.Ptr);4689}4690 4691MachO::linker_option_command4692MachOObjectFile::getLinkerOptionLoadCommand(const LoadCommandInfo &L) const {4693 return getStruct<MachO::linker_option_command>(*this, L.Ptr);4694}4695 4696MachO::version_min_command4697MachOObjectFile::getVersionMinLoadCommand(const LoadCommandInfo &L) const {4698 return getStruct<MachO::version_min_command>(*this, L.Ptr);4699}4700 4701MachO::note_command4702MachOObjectFile::getNoteLoadCommand(const LoadCommandInfo &L) const {4703 return getStruct<MachO::note_command>(*this, L.Ptr);4704}4705 4706MachO::build_version_command4707MachOObjectFile::getBuildVersionLoadCommand(const LoadCommandInfo &L) const {4708 return getStruct<MachO::build_version_command>(*this, L.Ptr);4709}4710 4711MachO::build_tool_version4712MachOObjectFile::getBuildToolVersion(unsigned index) const {4713 return getStruct<MachO::build_tool_version>(*this, BuildTools[index]);4714}4715 4716MachO::dylib_command4717MachOObjectFile::getDylibIDLoadCommand(const LoadCommandInfo &L) const {4718 return getStruct<MachO::dylib_command>(*this, L.Ptr);4719}4720 4721MachO::dyld_info_command4722MachOObjectFile::getDyldInfoLoadCommand(const LoadCommandInfo &L) const {4723 return getStruct<MachO::dyld_info_command>(*this, L.Ptr);4724}4725 4726MachO::dylinker_command4727MachOObjectFile::getDylinkerCommand(const LoadCommandInfo &L) const {4728 return getStruct<MachO::dylinker_command>(*this, L.Ptr);4729}4730 4731MachO::uuid_command4732MachOObjectFile::getUuidCommand(const LoadCommandInfo &L) const {4733 return getStruct<MachO::uuid_command>(*this, L.Ptr);4734}4735 4736MachO::rpath_command4737MachOObjectFile::getRpathCommand(const LoadCommandInfo &L) const {4738 return getStruct<MachO::rpath_command>(*this, L.Ptr);4739}4740 4741MachO::source_version_command4742MachOObjectFile::getSourceVersionCommand(const LoadCommandInfo &L) const {4743 return getStruct<MachO::source_version_command>(*this, L.Ptr);4744}4745 4746MachO::entry_point_command4747MachOObjectFile::getEntryPointCommand(const LoadCommandInfo &L) const {4748 return getStruct<MachO::entry_point_command>(*this, L.Ptr);4749}4750 4751MachO::encryption_info_command4752MachOObjectFile::getEncryptionInfoCommand(const LoadCommandInfo &L) const {4753 return getStruct<MachO::encryption_info_command>(*this, L.Ptr);4754}4755 4756MachO::encryption_info_command_644757MachOObjectFile::getEncryptionInfoCommand64(const LoadCommandInfo &L) const {4758 return getStruct<MachO::encryption_info_command_64>(*this, L.Ptr);4759}4760 4761MachO::sub_framework_command4762MachOObjectFile::getSubFrameworkCommand(const LoadCommandInfo &L) const {4763 return getStruct<MachO::sub_framework_command>(*this, L.Ptr);4764}4765 4766MachO::sub_umbrella_command4767MachOObjectFile::getSubUmbrellaCommand(const LoadCommandInfo &L) const {4768 return getStruct<MachO::sub_umbrella_command>(*this, L.Ptr);4769}4770 4771MachO::sub_library_command4772MachOObjectFile::getSubLibraryCommand(const LoadCommandInfo &L) const {4773 return getStruct<MachO::sub_library_command>(*this, L.Ptr);4774}4775 4776MachO::sub_client_command4777MachOObjectFile::getSubClientCommand(const LoadCommandInfo &L) const {4778 return getStruct<MachO::sub_client_command>(*this, L.Ptr);4779}4780 4781MachO::routines_command4782MachOObjectFile::getRoutinesCommand(const LoadCommandInfo &L) const {4783 return getStruct<MachO::routines_command>(*this, L.Ptr);4784}4785 4786MachO::routines_command_644787MachOObjectFile::getRoutinesCommand64(const LoadCommandInfo &L) const {4788 return getStruct<MachO::routines_command_64>(*this, L.Ptr);4789}4790 4791MachO::thread_command4792MachOObjectFile::getThreadCommand(const LoadCommandInfo &L) const {4793 return getStruct<MachO::thread_command>(*this, L.Ptr);4794}4795 4796MachO::fileset_entry_command4797MachOObjectFile::getFilesetEntryLoadCommand(const LoadCommandInfo &L) const {4798 return getStruct<MachO::fileset_entry_command>(*this, L.Ptr);4799}4800 4801MachO::any_relocation_info4802MachOObjectFile::getRelocation(DataRefImpl Rel) const {4803 uint32_t Offset;4804 if (getHeader().filetype == MachO::MH_OBJECT) {4805 DataRefImpl Sec;4806 Sec.d.a = Rel.d.a;4807 if (is64Bit()) {4808 MachO::section_64 Sect = getSection64(Sec);4809 Offset = Sect.reloff;4810 } else {4811 MachO::section Sect = getSection(Sec);4812 Offset = Sect.reloff;4813 }4814 } else {4815 MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand();4816 if (Rel.d.a == 0)4817 Offset = DysymtabLoadCmd.extreloff; // Offset to the external relocations4818 else4819 Offset = DysymtabLoadCmd.locreloff; // Offset to the local relocations4820 }4821 4822 auto P = reinterpret_cast<const MachO::any_relocation_info *>(4823 getPtr(*this, Offset)) + Rel.d.b;4824 return getStruct<MachO::any_relocation_info>(4825 *this, reinterpret_cast<const char *>(P));4826}4827 4828MachO::data_in_code_entry4829MachOObjectFile::getDice(DataRefImpl Rel) const {4830 const char *P = reinterpret_cast<const char *>(Rel.p);4831 return getStruct<MachO::data_in_code_entry>(*this, P);4832}4833 4834const MachO::mach_header &MachOObjectFile::getHeader() const {4835 return Header;4836}4837 4838const MachO::mach_header_64 &MachOObjectFile::getHeader64() const {4839 assert(is64Bit());4840 return Header64;4841}4842 4843uint32_t MachOObjectFile::getIndirectSymbolTableEntry(4844 const MachO::dysymtab_command &DLC,4845 unsigned Index) const {4846 uint64_t Offset = DLC.indirectsymoff + Index * sizeof(uint32_t);4847 return getStruct<uint32_t>(*this, getPtr(*this, Offset));4848}4849 4850MachO::data_in_code_entry4851MachOObjectFile::getDataInCodeTableEntry(uint32_t DataOffset,4852 unsigned Index) const {4853 uint64_t Offset = DataOffset + Index * sizeof(MachO::data_in_code_entry);4854 return getStruct<MachO::data_in_code_entry>(*this, getPtr(*this, Offset));4855}4856 4857MachO::symtab_command MachOObjectFile::getSymtabLoadCommand() const {4858 if (SymtabLoadCmd)4859 return getStruct<MachO::symtab_command>(*this, SymtabLoadCmd);4860 4861 // If there is no SymtabLoadCmd return a load command with zero'ed fields.4862 MachO::symtab_command Cmd;4863 Cmd.cmd = MachO::LC_SYMTAB;4864 Cmd.cmdsize = sizeof(MachO::symtab_command);4865 Cmd.symoff = 0;4866 Cmd.nsyms = 0;4867 Cmd.stroff = 0;4868 Cmd.strsize = 0;4869 return Cmd;4870}4871 4872MachO::dysymtab_command MachOObjectFile::getDysymtabLoadCommand() const {4873 if (DysymtabLoadCmd)4874 return getStruct<MachO::dysymtab_command>(*this, DysymtabLoadCmd);4875 4876 // If there is no DysymtabLoadCmd return a load command with zero'ed fields.4877 MachO::dysymtab_command Cmd;4878 Cmd.cmd = MachO::LC_DYSYMTAB;4879 Cmd.cmdsize = sizeof(MachO::dysymtab_command);4880 Cmd.ilocalsym = 0;4881 Cmd.nlocalsym = 0;4882 Cmd.iextdefsym = 0;4883 Cmd.nextdefsym = 0;4884 Cmd.iundefsym = 0;4885 Cmd.nundefsym = 0;4886 Cmd.tocoff = 0;4887 Cmd.ntoc = 0;4888 Cmd.modtaboff = 0;4889 Cmd.nmodtab = 0;4890 Cmd.extrefsymoff = 0;4891 Cmd.nextrefsyms = 0;4892 Cmd.indirectsymoff = 0;4893 Cmd.nindirectsyms = 0;4894 Cmd.extreloff = 0;4895 Cmd.nextrel = 0;4896 Cmd.locreloff = 0;4897 Cmd.nlocrel = 0;4898 return Cmd;4899}4900 4901MachO::linkedit_data_command4902MachOObjectFile::getDataInCodeLoadCommand() const {4903 if (DataInCodeLoadCmd)4904 return getStruct<MachO::linkedit_data_command>(*this, DataInCodeLoadCmd);4905 4906 // If there is no DataInCodeLoadCmd return a load command with zero'ed fields.4907 MachO::linkedit_data_command Cmd;4908 Cmd.cmd = MachO::LC_DATA_IN_CODE;4909 Cmd.cmdsize = sizeof(MachO::linkedit_data_command);4910 Cmd.dataoff = 0;4911 Cmd.datasize = 0;4912 return Cmd;4913}4914 4915MachO::linkedit_data_command4916MachOObjectFile::getLinkOptHintsLoadCommand() const {4917 if (LinkOptHintsLoadCmd)4918 return getStruct<MachO::linkedit_data_command>(*this, LinkOptHintsLoadCmd);4919 4920 // If there is no LinkOptHintsLoadCmd return a load command with zero'ed4921 // fields.4922 MachO::linkedit_data_command Cmd;4923 Cmd.cmd = MachO::LC_LINKER_OPTIMIZATION_HINT;4924 Cmd.cmdsize = sizeof(MachO::linkedit_data_command);4925 Cmd.dataoff = 0;4926 Cmd.datasize = 0;4927 return Cmd;4928}4929 4930ArrayRef<uint8_t> MachOObjectFile::getDyldInfoRebaseOpcodes() const {4931 if (!DyldInfoLoadCmd)4932 return {};4933 4934 auto DyldInfoOrErr =4935 getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);4936 if (!DyldInfoOrErr)4937 return {};4938 MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();4939 const uint8_t *Ptr =4940 reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.rebase_off));4941 return ArrayRef(Ptr, DyldInfo.rebase_size);4942}4943 4944ArrayRef<uint8_t> MachOObjectFile::getDyldInfoBindOpcodes() const {4945 if (!DyldInfoLoadCmd)4946 return {};4947 4948 auto DyldInfoOrErr =4949 getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);4950 if (!DyldInfoOrErr)4951 return {};4952 MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();4953 const uint8_t *Ptr =4954 reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.bind_off));4955 return ArrayRef(Ptr, DyldInfo.bind_size);4956}4957 4958ArrayRef<uint8_t> MachOObjectFile::getDyldInfoWeakBindOpcodes() const {4959 if (!DyldInfoLoadCmd)4960 return {};4961 4962 auto DyldInfoOrErr =4963 getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);4964 if (!DyldInfoOrErr)4965 return {};4966 MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();4967 const uint8_t *Ptr =4968 reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.weak_bind_off));4969 return ArrayRef(Ptr, DyldInfo.weak_bind_size);4970}4971 4972ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const {4973 if (!DyldInfoLoadCmd)4974 return {};4975 4976 auto DyldInfoOrErr =4977 getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);4978 if (!DyldInfoOrErr)4979 return {};4980 MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();4981 const uint8_t *Ptr =4982 reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.lazy_bind_off));4983 return ArrayRef(Ptr, DyldInfo.lazy_bind_size);4984}4985 4986ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const {4987 if (!DyldInfoLoadCmd)4988 return {};4989 4990 auto DyldInfoOrErr =4991 getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);4992 if (!DyldInfoOrErr)4993 return {};4994 MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();4995 const uint8_t *Ptr =4996 reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.export_off));4997 return ArrayRef(Ptr, DyldInfo.export_size);4998}4999 5000Expected<std::optional<MachO::linkedit_data_command>>5001MachOObjectFile::getChainedFixupsLoadCommand() const {5002 // Load the dyld chained fixups load command.5003 if (!DyldChainedFixupsLoadCmd)5004 return std::nullopt;5005 auto DyldChainedFixupsOrErr = getStructOrErr<MachO::linkedit_data_command>(5006 *this, DyldChainedFixupsLoadCmd);5007 if (!DyldChainedFixupsOrErr)5008 return DyldChainedFixupsOrErr.takeError();5009 const MachO::linkedit_data_command &DyldChainedFixups =5010 *DyldChainedFixupsOrErr;5011 5012 // If the load command is present but the data offset has been zeroed out,5013 // as is the case for dylib stubs, return std::nullopt (no error).5014 if (!DyldChainedFixups.dataoff)5015 return std::nullopt;5016 return DyldChainedFixups;5017}5018 5019Expected<std::optional<MachO::dyld_chained_fixups_header>>5020MachOObjectFile::getChainedFixupsHeader() const {5021 auto CFOrErr = getChainedFixupsLoadCommand();5022 if (!CFOrErr)5023 return CFOrErr.takeError();5024 if (!CFOrErr->has_value())5025 return std::nullopt;5026 5027 const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr;5028 5029 uint64_t CFHeaderOffset = DyldChainedFixups.dataoff;5030 uint64_t CFSize = DyldChainedFixups.datasize;5031 5032 // Load the dyld chained fixups header.5033 const char *CFHeaderPtr = getPtr(*this, CFHeaderOffset);5034 auto CFHeaderOrErr =5035 getStructOrErr<MachO::dyld_chained_fixups_header>(*this, CFHeaderPtr);5036 if (!CFHeaderOrErr)5037 return CFHeaderOrErr.takeError();5038 MachO::dyld_chained_fixups_header CFHeader = CFHeaderOrErr.get();5039 5040 // Reject unknown chained fixup formats.5041 if (CFHeader.fixups_version != 0)5042 return malformedError(Twine("bad chained fixups: unknown version: ") +5043 Twine(CFHeader.fixups_version));5044 if (CFHeader.imports_format < 1 || CFHeader.imports_format > 3)5045 return malformedError(5046 Twine("bad chained fixups: unknown imports format: ") +5047 Twine(CFHeader.imports_format));5048 5049 // Validate the image format.5050 //5051 // Load the image starts.5052 uint64_t CFImageStartsOffset = (CFHeaderOffset + CFHeader.starts_offset);5053 if (CFHeader.starts_offset < sizeof(MachO::dyld_chained_fixups_header)) {5054 return malformedError(Twine("bad chained fixups: image starts offset ") +5055 Twine(CFHeader.starts_offset) +5056 " overlaps with chained fixups header");5057 }5058 uint32_t EndOffset = CFHeaderOffset + CFSize;5059 if (CFImageStartsOffset + sizeof(MachO::dyld_chained_starts_in_image) >5060 EndOffset) {5061 return malformedError(Twine("bad chained fixups: image starts end ") +5062 Twine(CFImageStartsOffset +5063 sizeof(MachO::dyld_chained_starts_in_image)) +5064 " extends past end " + Twine(EndOffset));5065 }5066 5067 return CFHeader;5068}5069 5070Expected<std::pair<size_t, std::vector<ChainedFixupsSegment>>>5071MachOObjectFile::getChainedFixupsSegments() const {5072 auto CFOrErr = getChainedFixupsLoadCommand();5073 if (!CFOrErr)5074 return CFOrErr.takeError();5075 5076 std::vector<ChainedFixupsSegment> Segments;5077 if (!CFOrErr->has_value())5078 return std::make_pair(0, Segments);5079 5080 const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr;5081 5082 auto HeaderOrErr = getChainedFixupsHeader();5083 if (!HeaderOrErr)5084 return HeaderOrErr.takeError();5085 if (!HeaderOrErr->has_value())5086 return std::make_pair(0, Segments);5087 const MachO::dyld_chained_fixups_header &Header = **HeaderOrErr;5088 5089 const char *Contents = getPtr(*this, DyldChainedFixups.dataoff);5090 5091 auto ImageStartsOrErr = getStructOrErr<MachO::dyld_chained_starts_in_image>(5092 *this, Contents + Header.starts_offset);5093 if (!ImageStartsOrErr)5094 return ImageStartsOrErr.takeError();5095 const MachO::dyld_chained_starts_in_image &ImageStarts = *ImageStartsOrErr;5096 5097 const char *SegOffsPtr =5098 Contents + Header.starts_offset +5099 offsetof(MachO::dyld_chained_starts_in_image, seg_info_offset);5100 const char *SegOffsEnd =5101 SegOffsPtr + ImageStarts.seg_count * sizeof(uint32_t);5102 if (SegOffsEnd > Contents + DyldChainedFixups.datasize)5103 return malformedError(5104 "bad chained fixups: seg_info_offset extends past end");5105 5106 const char *LastSegEnd = nullptr;5107 for (size_t I = 0, N = ImageStarts.seg_count; I < N; ++I) {5108 auto OffOrErr =5109 getStructOrErr<uint32_t>(*this, SegOffsPtr + I * sizeof(uint32_t));5110 if (!OffOrErr)5111 return OffOrErr.takeError();5112 // seg_info_offset == 0 means there is no associated starts_in_segment5113 // entry.5114 if (!*OffOrErr)5115 continue;5116 5117 auto Fail = [&](Twine Message) {5118 return malformedError("bad chained fixups: segment info" + Twine(I) +5119 " at offset " + Twine(*OffOrErr) + Message);5120 };5121 5122 const char *SegPtr = Contents + Header.starts_offset + *OffOrErr;5123 if (LastSegEnd && SegPtr < LastSegEnd)5124 return Fail(" overlaps with previous segment info");5125 5126 auto SegOrErr =5127 getStructOrErr<MachO::dyld_chained_starts_in_segment>(*this, SegPtr);5128 if (!SegOrErr)5129 return SegOrErr.takeError();5130 const MachO::dyld_chained_starts_in_segment &Seg = *SegOrErr;5131 5132 LastSegEnd = SegPtr + Seg.size;5133 if (Seg.pointer_format < 1 || Seg.pointer_format > 12)5134 return Fail(" has unknown pointer format: " + Twine(Seg.pointer_format));5135 5136 const char *PageStart =5137 SegPtr + offsetof(MachO::dyld_chained_starts_in_segment, page_start);5138 const char *PageEnd = PageStart + Seg.page_count * sizeof(uint16_t);5139 if (PageEnd > SegPtr + Seg.size)5140 return Fail(" : page_starts extend past seg_info size");5141 5142 // FIXME: This does not account for multiple offsets on a single page5143 // (DYLD_CHAINED_PTR_START_MULTI; 32-bit only).5144 std::vector<uint16_t> PageStarts;5145 for (size_t PageIdx = 0; PageIdx < Seg.page_count; ++PageIdx) {5146 uint16_t Start;5147 memcpy(&Start, PageStart + PageIdx * sizeof(uint16_t), sizeof(uint16_t));5148 if (isLittleEndian() != sys::IsLittleEndianHost)5149 sys::swapByteOrder(Start);5150 PageStarts.push_back(Start);5151 }5152 5153 Segments.emplace_back(I, *OffOrErr, Seg, std::move(PageStarts));5154 }5155 5156 return std::make_pair(ImageStarts.seg_count, Segments);5157}5158 5159// The special library ordinals have a negative value, but they are encoded in5160// an unsigned bitfield, so we need to sign extend the value.5161template <typename T> static int getEncodedOrdinal(T Value) {5162 if (Value == static_cast<T>(MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE) ||5163 Value == static_cast<T>(MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP) ||5164 Value == static_cast<T>(MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP))5165 return SignExtend32<sizeof(T) * CHAR_BIT>(Value);5166 return Value;5167}5168 5169template <typename T, unsigned N>5170static std::array<T, N> getArray(const MachOObjectFile &O, const void *Ptr) {5171 std::array<T, N> RawValue;5172 memcpy(RawValue.data(), Ptr, N * sizeof(T));5173 if (O.isLittleEndian() != sys::IsLittleEndianHost)5174 for (auto &Element : RawValue)5175 sys::swapByteOrder(Element);5176 return RawValue;5177}5178 5179Expected<std::vector<ChainedFixupTarget>>5180MachOObjectFile::getDyldChainedFixupTargets() const {5181 auto CFOrErr = getChainedFixupsLoadCommand();5182 if (!CFOrErr)5183 return CFOrErr.takeError();5184 5185 std::vector<ChainedFixupTarget> Targets;5186 if (!CFOrErr->has_value())5187 return Targets;5188 5189 const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr;5190 5191 auto CFHeaderOrErr = getChainedFixupsHeader();5192 if (!CFHeaderOrErr)5193 return CFHeaderOrErr.takeError();5194 if (!(*CFHeaderOrErr))5195 return Targets;5196 const MachO::dyld_chained_fixups_header &Header = **CFHeaderOrErr;5197 5198 size_t ImportSize = 0;5199 if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT)5200 ImportSize = sizeof(MachO::dyld_chained_import);5201 else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND)5202 ImportSize = sizeof(MachO::dyld_chained_import_addend);5203 else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND64)5204 ImportSize = sizeof(MachO::dyld_chained_import_addend64);5205 else5206 return malformedError("bad chained fixups: unknown imports format: " +5207 Twine(Header.imports_format));5208 5209 const char *Contents = getPtr(*this, DyldChainedFixups.dataoff);5210 const char *Imports = Contents + Header.imports_offset;5211 size_t ImportsEndOffset =5212 Header.imports_offset + ImportSize * Header.imports_count;5213 const char *ImportsEnd = Contents + ImportsEndOffset;5214 const char *Symbols = Contents + Header.symbols_offset;5215 const char *SymbolsEnd = Contents + DyldChainedFixups.datasize;5216 5217 if (ImportsEnd > Symbols)5218 return malformedError("bad chained fixups: imports end " +5219 Twine(ImportsEndOffset) + " overlaps with symbols");5220 5221 // We use bit manipulation to extract data from the bitfields. This is correct5222 // for both LE and BE hosts, but we assume that the object is little-endian.5223 if (!isLittleEndian())5224 return createError("parsing big-endian chained fixups is not implemented");5225 for (const char *ImportPtr = Imports; ImportPtr < ImportsEnd;5226 ImportPtr += ImportSize) {5227 int LibOrdinal;5228 bool WeakImport;5229 uint32_t NameOffset;5230 uint64_t Addend;5231 if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT) {5232 static_assert(sizeof(uint32_t) == sizeof(MachO::dyld_chained_import));5233 auto RawValue = getArray<uint32_t, 1>(*this, ImportPtr);5234 5235 LibOrdinal = getEncodedOrdinal<uint8_t>(RawValue[0] & 0xFF);5236 WeakImport = (RawValue[0] >> 8) & 1;5237 NameOffset = RawValue[0] >> 9;5238 Addend = 0;5239 } else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND) {5240 static_assert(sizeof(uint64_t) ==5241 sizeof(MachO::dyld_chained_import_addend));5242 auto RawValue = getArray<uint32_t, 2>(*this, ImportPtr);5243 5244 LibOrdinal = getEncodedOrdinal<uint8_t>(RawValue[0] & 0xFF);5245 WeakImport = (RawValue[0] >> 8) & 1;5246 NameOffset = RawValue[0] >> 9;5247 Addend = bit_cast<int32_t>(RawValue[1]);5248 } else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND64) {5249 static_assert(2 * sizeof(uint64_t) ==5250 sizeof(MachO::dyld_chained_import_addend64));5251 auto RawValue = getArray<uint64_t, 2>(*this, ImportPtr);5252 5253 LibOrdinal = getEncodedOrdinal<uint16_t>(RawValue[0] & 0xFFFF);5254 NameOffset = (RawValue[0] >> 16) & 1;5255 WeakImport = RawValue[0] >> 17;5256 Addend = RawValue[1];5257 } else {5258 llvm_unreachable("Import format should have been checked");5259 }5260 5261 const char *Str = Symbols + NameOffset;5262 if (Str >= SymbolsEnd)5263 return malformedError("bad chained fixups: symbol offset " +5264 Twine(NameOffset) + " extends past end " +5265 Twine(DyldChainedFixups.datasize));5266 Targets.emplace_back(LibOrdinal, NameOffset, Str, Addend, WeakImport);5267 }5268 5269 return std::move(Targets);5270}5271 5272ArrayRef<uint8_t> MachOObjectFile::getDyldExportsTrie() const {5273 if (!DyldExportsTrieLoadCmd)5274 return {};5275 5276 auto DyldExportsTrieOrError = getStructOrErr<MachO::linkedit_data_command>(5277 *this, DyldExportsTrieLoadCmd);5278 if (!DyldExportsTrieOrError)5279 return {};5280 MachO::linkedit_data_command DyldExportsTrie = DyldExportsTrieOrError.get();5281 const uint8_t *Ptr =5282 reinterpret_cast<const uint8_t *>(getPtr(*this, DyldExportsTrie.dataoff));5283 return ArrayRef(Ptr, DyldExportsTrie.datasize);5284}5285 5286SmallVector<uint64_t> MachOObjectFile::getFunctionStarts() const {5287 if (!FuncStartsLoadCmd)5288 return {};5289 5290 auto InfoOrErr =5291 getStructOrErr<MachO::linkedit_data_command>(*this, FuncStartsLoadCmd);5292 if (!InfoOrErr)5293 return {};5294 5295 MachO::linkedit_data_command Info = InfoOrErr.get();5296 SmallVector<uint64_t, 8> FunctionStarts;5297 this->ReadULEB128s(Info.dataoff, FunctionStarts);5298 return std::move(FunctionStarts);5299}5300 5301ArrayRef<uint8_t> MachOObjectFile::getUuid() const {5302 if (!UuidLoadCmd)5303 return {};5304 // Returning a pointer is fine as uuid doesn't need endian swapping.5305 const char *Ptr = UuidLoadCmd + offsetof(MachO::uuid_command, uuid);5306 return ArrayRef(reinterpret_cast<const uint8_t *>(Ptr), 16);5307}5308 5309StringRef MachOObjectFile::getStringTableData() const {5310 MachO::symtab_command S = getSymtabLoadCommand();5311 return getData().substr(S.stroff, S.strsize);5312}5313 5314bool MachOObjectFile::is64Bit() const {5315 return getType() == getMachOType(false, true) ||5316 getType() == getMachOType(true, true);5317}5318 5319void MachOObjectFile::ReadULEB128s(uint64_t Index,5320 SmallVectorImpl<uint64_t> &Out) const {5321 DataExtractor extractor(ObjectFile::getData(), true, 0);5322 5323 uint64_t offset = Index;5324 uint64_t data = 0;5325 while (uint64_t delta = extractor.getULEB128(&offset)) {5326 data += delta;5327 Out.push_back(data);5328 }5329}5330 5331bool MachOObjectFile::isRelocatableObject() const {5332 return getHeader().filetype == MachO::MH_OBJECT;5333}5334 5335/// Create a MachOObjectFile instance from a given buffer.5336///5337/// \param Buffer Memory buffer containing the MachO binary data.5338/// \param UniversalCputype CPU type when the MachO part of a universal binary.5339/// \param UniversalIndex Index of the MachO within a universal binary.5340/// \param MachOFilesetEntryOffset Offset of the MachO entry in a fileset MachO.5341/// \returns A std::unique_ptr to a MachOObjectFile instance on success.5342Expected<std::unique_ptr<MachOObjectFile>> ObjectFile::createMachOObjectFile(5343 MemoryBufferRef Buffer, uint32_t UniversalCputype, uint32_t UniversalIndex,5344 size_t MachOFilesetEntryOffset) {5345 StringRef Magic = Buffer.getBuffer().slice(0, 4);5346 if (Magic == "\xFE\xED\xFA\xCE")5347 return MachOObjectFile::create(Buffer, false, false, UniversalCputype,5348 UniversalIndex, MachOFilesetEntryOffset);5349 if (Magic == "\xCE\xFA\xED\xFE")5350 return MachOObjectFile::create(Buffer, true, false, UniversalCputype,5351 UniversalIndex, MachOFilesetEntryOffset);5352 if (Magic == "\xFE\xED\xFA\xCF")5353 return MachOObjectFile::create(Buffer, false, true, UniversalCputype,5354 UniversalIndex, MachOFilesetEntryOffset);5355 if (Magic == "\xCF\xFA\xED\xFE")5356 return MachOObjectFile::create(Buffer, true, true, UniversalCputype,5357 UniversalIndex, MachOFilesetEntryOffset);5358 return make_error<GenericBinaryError>("Unrecognized MachO magic number",5359 object_error::invalid_file_type);5360}5361 5362StringRef MachOObjectFile::mapDebugSectionName(StringRef Name) const {5363 return StringSwitch<StringRef>(Name)5364 .Case("debug_str_offs", "debug_str_offsets")5365 .Default(Name);5366}5367 5368Expected<std::vector<std::string>>5369MachOObjectFile::findDsymObjectMembers(StringRef Path) {5370 SmallString<256> BundlePath(Path);5371 // Normalize input path. This is necessary to accept `bundle.dSYM/`.5372 sys::path::remove_dots(BundlePath);5373 if (!sys::fs::is_directory(BundlePath) ||5374 sys::path::extension(BundlePath) != ".dSYM")5375 return std::vector<std::string>();5376 sys::path::append(BundlePath, "Contents", "Resources", "DWARF");5377 bool IsDir;5378 auto EC = sys::fs::is_directory(BundlePath, IsDir);5379 if (EC == errc::no_such_file_or_directory || (!EC && !IsDir))5380 return createStringError(5381 EC, "%s: expected directory 'Contents/Resources/DWARF' in dSYM bundle",5382 Path.str().c_str());5383 if (EC)5384 return createFileError(BundlePath, errorCodeToError(EC));5385 5386 std::vector<std::string> ObjectPaths;5387 for (sys::fs::directory_iterator Dir(BundlePath, EC), DirEnd;5388 Dir != DirEnd && !EC; Dir.increment(EC)) {5389 StringRef ObjectPath = Dir->path();5390 sys::fs::file_status Status;5391 if (auto EC = sys::fs::status(ObjectPath, Status))5392 return createFileError(ObjectPath, errorCodeToError(EC));5393 switch (Status.type()) {5394 case sys::fs::file_type::regular_file:5395 case sys::fs::file_type::symlink_file:5396 case sys::fs::file_type::type_unknown:5397 ObjectPaths.push_back(ObjectPath.str());5398 break;5399 default: /*ignore*/;5400 }5401 }5402 if (EC)5403 return createFileError(BundlePath, errorCodeToError(EC));5404 if (ObjectPaths.empty())5405 return createStringError(std::error_code(),5406 "%s: no objects found in dSYM bundle",5407 Path.str().c_str());5408 return ObjectPaths;5409}5410 5411llvm::binaryformat::Swift5ReflectionSectionKind5412MachOObjectFile::mapReflectionSectionNameToEnumValue(5413 StringRef SectionName) const {5414#define HANDLE_SWIFT_SECTION(KIND, MACHO, ELF, COFF) \5415 .Case(MACHO, llvm::binaryformat::Swift5ReflectionSectionKind::KIND)5416 return StringSwitch<llvm::binaryformat::Swift5ReflectionSectionKind>(5417 SectionName)5418#include "llvm/BinaryFormat/Swift.def"5419 .Default(llvm::binaryformat::Swift5ReflectionSectionKind::unknown);5420#undef HANDLE_SWIFT_SECTION5421}5422 5423bool MachOObjectFile::isMachOPairedReloc(uint64_t RelocType, uint64_t Arch) {5424 switch (Arch) {5425 case Triple::x86:5426 return RelocType == MachO::GENERIC_RELOC_SECTDIFF ||5427 RelocType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF;5428 case Triple::x86_64:5429 return RelocType == MachO::X86_64_RELOC_SUBTRACTOR;5430 case Triple::arm:5431 case Triple::thumb:5432 return RelocType == MachO::ARM_RELOC_SECTDIFF ||5433 RelocType == MachO::ARM_RELOC_LOCAL_SECTDIFF ||5434 RelocType == MachO::ARM_RELOC_HALF ||5435 RelocType == MachO::ARM_RELOC_HALF_SECTDIFF;5436 case Triple::aarch64:5437 return RelocType == MachO::ARM64_RELOC_SUBTRACTOR;5438 default:5439 return false;5440 }5441}5442