brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.5 KiB · 6b0f96d Raw
459 lines · cpp
1//===----------------- MachO.cpp - MachO format utilities -----------------===//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#include "llvm/ExecutionEngine/Orc/MachO.h"10 11#include "llvm/ADT/ScopeExit.h"12#include "llvm/BinaryFormat/MachO.h"13#include "llvm/BinaryFormat/Magic.h"14#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"15#include "llvm/ExecutionEngine/Orc/Layer.h"16#include "llvm/Object/MachOUniversal.h"17#include "llvm/Object/TapiUniversal.h"18#include "llvm/Support/FileSystem.h"19 20#define DEBUG_TYPE "orc"21 22namespace llvm {23namespace orc {24 25static std::string objDesc(const MemoryBufferRef &Obj, const Triple &TT,26                           bool ObjIsSlice) {27  std::string Desc;28  if (ObjIsSlice)29    Desc += (TT.getArchName() + " slice of universal binary").str();30  Desc += Obj.getBufferIdentifier();31  return Desc;32}33 34template <typename HeaderType>35static Error checkMachORelocatableObject(MemoryBufferRef Obj,36                                         bool SwapEndianness, const Triple &TT,37                                         bool ObjIsSlice) {38  StringRef Data = Obj.getBuffer();39 40  HeaderType Hdr;41  memcpy(&Hdr, Data.data(), sizeof(HeaderType));42 43  if (SwapEndianness)44    swapStruct(Hdr);45 46  if (Hdr.filetype != MachO::MH_OBJECT)47    return make_error<StringError>(objDesc(Obj, TT, ObjIsSlice) +48                                       " is not a MachO relocatable object",49                                   inconvertibleErrorCode());50 51  auto ObjArch = object::MachOObjectFile::getArch(Hdr.cputype, Hdr.cpusubtype);52  if (ObjArch != TT.getArch())53    return make_error<StringError>(54        objDesc(Obj, TT, ObjIsSlice) + Triple::getArchTypeName(ObjArch) +55            ", cannot be loaded into " + TT.str() + " process",56        inconvertibleErrorCode());57 58  return Error::success();59}60 61Error checkMachORelocatableObject(MemoryBufferRef Obj, const Triple &TT,62                                  bool ObjIsSlice) {63  StringRef Data = Obj.getBuffer();64 65  if (Data.size() < 4)66    return make_error<StringError>(67        objDesc(Obj, TT, ObjIsSlice) +68            " is not a valid MachO relocatable object file (truncated header)",69        inconvertibleErrorCode());70 71  uint32_t Magic;72  memcpy(&Magic, Data.data(), sizeof(uint32_t));73 74  switch (Magic) {75  case MachO::MH_MAGIC:76  case MachO::MH_CIGAM:77    return checkMachORelocatableObject<MachO::mach_header>(78        std::move(Obj), Magic == MachO::MH_CIGAM, TT, ObjIsSlice);79  case MachO::MH_MAGIC_64:80  case MachO::MH_CIGAM_64:81    return checkMachORelocatableObject<MachO::mach_header_64>(82        std::move(Obj), Magic == MachO::MH_CIGAM_64, TT, ObjIsSlice);83  default:84    return make_error<StringError>(85        objDesc(Obj, TT, ObjIsSlice) +86            " is not a valid MachO relocatable object (bad magic value)",87        inconvertibleErrorCode());88  }89}90 91Expected<std::unique_ptr<MemoryBuffer>>92checkMachORelocatableObject(std::unique_ptr<MemoryBuffer> Obj, const Triple &TT,93                            bool ObjIsSlice) {94  if (auto Err =95          checkMachORelocatableObject(Obj->getMemBufferRef(), TT, ObjIsSlice))96    return std::move(Err);97  return std::move(Obj);98}99 100Expected<std::pair<std::unique_ptr<MemoryBuffer>, LinkableFileKind>>101loadMachORelocatableObject(StringRef Path, const Triple &TT, LoadArchives LA,102                           std::optional<StringRef> IdentifierOverride) {103  assert((TT.getObjectFormat() == Triple::UnknownObjectFormat ||104          TT.getObjectFormat() == Triple::MachO) &&105         "TT must specify MachO or Unknown object format");106 107  if (!IdentifierOverride)108    IdentifierOverride = Path;109 110  Expected<sys::fs::file_t> FDOrErr =111      sys::fs::openNativeFileForRead(Path, sys::fs::OF_None);112  if (!FDOrErr)113    return createFileError(Path, FDOrErr.takeError());114  sys::fs::file_t FD = *FDOrErr;115  auto CloseFile = make_scope_exit([&]() { sys::fs::closeFile(FD); });116 117  auto Buf =118      MemoryBuffer::getOpenFile(FD, *IdentifierOverride, /*FileSize=*/-1);119  if (!Buf)120    return make_error<StringError>(121        StringRef("Could not load MachO object at path ") + Path,122        Buf.getError());123 124  switch (identify_magic((*Buf)->getBuffer())) {125  case file_magic::macho_object: {126    auto CheckedObj = checkMachORelocatableObject(std::move(*Buf), TT, false);127    if (!CheckedObj)128      return CheckedObj.takeError();129    return std::make_pair(std::move(*CheckedObj),130                          LinkableFileKind::RelocatableObject);131  }132  case file_magic::macho_universal_binary:133    return loadLinkableSliceFromMachOUniversalBinary(FD, std::move(*Buf), TT,134                                                     LoadArchives::Never, Path,135                                                     *IdentifierOverride);136  default:137    return make_error<StringError>(138        Path + " does not contain a relocatable object file compatible with " +139            TT.str(),140        inconvertibleErrorCode());141  }142}143 144Expected<std::pair<std::unique_ptr<MemoryBuffer>, LinkableFileKind>>145loadLinkableSliceFromMachOUniversalBinary(sys::fs::file_t FD,146                                          std::unique_ptr<MemoryBuffer> UBBuf,147                                          const Triple &TT, LoadArchives LA,148                                          StringRef UBPath,149                                          StringRef Identifier) {150 151  auto UniversalBin =152      object::MachOUniversalBinary::create(UBBuf->getMemBufferRef());153  if (!UniversalBin)154    return UniversalBin.takeError();155 156  auto SliceRange = getMachOSliceRangeForTriple(**UniversalBin, TT);157  if (!SliceRange)158    return SliceRange.takeError();159 160  auto Buf = MemoryBuffer::getOpenFileSlice(FD, Identifier, SliceRange->second,161                                            SliceRange->first);162  if (!Buf)163    return make_error<StringError>(164        "Could not load " + TT.getArchName() +165            " slice of MachO universal binary at path " + UBPath,166        Buf.getError());167 168  switch (identify_magic((*Buf)->getBuffer())) {169  case file_magic::archive:170    if (LA != LoadArchives::Never)171      return std::make_pair(std::move(*Buf), LinkableFileKind::Archive);172    break;173  case file_magic::macho_object: {174    if (LA != LoadArchives::Required) {175      auto CheckedObj = checkMachORelocatableObject(std::move(*Buf), TT, true);176      if (!CheckedObj)177        return CheckedObj.takeError();178      return std::make_pair(std::move(*CheckedObj),179                            LinkableFileKind::RelocatableObject);180    }181    break;182  }183  default:184    break;185  }186 187  auto FT = [&] {188    switch (LA) {189    case LoadArchives::Never:190      return "a mach-o relocatable object file";191    case LoadArchives::Allowed:192      return "a mach-o relocatable object file or archive";193    case LoadArchives::Required:194      return "an archive";195    }196    llvm_unreachable("Unknown LoadArchives enum");197  };198 199  return make_error<StringError>(TT.getArchName() + " slice of " + UBPath +200                                     " does not contain " + FT(),201                                 inconvertibleErrorCode());202}203 204Expected<std::pair<size_t, size_t>>205getMachOSliceRangeForTriple(object::MachOUniversalBinary &UB,206                            const Triple &TT) {207 208  for (const auto &Obj : UB.objects()) {209    auto ObjTT = Obj.getTriple();210    if (ObjTT.getArch() == TT.getArch() &&211        ObjTT.getSubArch() == TT.getSubArch() &&212        (TT.getVendor() == Triple::UnknownVendor ||213         ObjTT.getVendor() == TT.getVendor())) {214      // We found a match. Return the range for the slice.215      return std::make_pair(Obj.getOffset(), Obj.getSize());216    }217  }218 219  return make_error<StringError>(Twine("Universal binary ") + UB.getFileName() +220                                     " does not contain a slice for " +221                                     TT.str(),222                                 inconvertibleErrorCode());223}224 225Expected<std::pair<size_t, size_t>>226getMachOSliceRangeForTriple(MemoryBufferRef UBBuf, const Triple &TT) {227 228  auto UB = object::MachOUniversalBinary::create(UBBuf);229  if (!UB)230    return UB.takeError();231 232  return getMachOSliceRangeForTriple(**UB, TT);233}234 235Expected<bool> ForceLoadMachOArchiveMembers::operator()(236    object::Archive &A, MemoryBufferRef MemberBuf, size_t Index) {237 238  auto LoadMember = [&]() {239    return StaticLibraryDefinitionGenerator::createMemberBuffer(A, MemberBuf,240                                                                Index);241  };242 243  if (!ObjCOnly) {244    // If we're loading all files then just load the buffer immediately. Return245    // false to indicate that there's no further loading to do here.246    if (auto Err = L.add(JD, LoadMember()))247      return Err;248    return false;249  }250 251  // We need to check whether this archive member contains any Objective-C252  // or Swift metadata.253  auto Obj = object::ObjectFile::createObjectFile(MemberBuf);254  if (!Obj) {255    // Invalid files are not loadable, but don't invalidate the archive.256    consumeError(Obj.takeError());257    return false;258  }259 260  if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&**Obj)) {261    // Load the object if any recognized special section is present.262    for (auto Sec : MachOObj->sections()) {263      auto SegName =264          MachOObj->getSectionFinalSegmentName(Sec.getRawDataRefImpl());265      if (auto SecName = Sec.getName()) {266        if (*SecName == "__objc_classlist" || *SecName == "__objc_protolist" ||267            *SecName == "__objc_clsrolist" || *SecName == "__objc_catlist" ||268            *SecName == "__objc_catlist2" || *SecName == "__objc_nlcatlist" ||269            (SegName == "__TEXT" && (*SecName).starts_with("__swift") &&270             *SecName != "__swift_modhash")) {271          if (auto Err = L.add(JD, LoadMember()))272            return Err;273          return false;274        }275      } else276        return SecName.takeError();277    }278  }279 280  // This is an object file but we didn't load it, so return true to indicate281  // that it's still loadable.282  return true;283}284 285SmallVector<std::pair<uint32_t, uint32_t>>286noFallbackArchs(uint32_t CPUType, uint32_t CPUSubType) {287  SmallVector<std::pair<uint32_t, uint32_t>> Result;288  Result.push_back({CPUType, CPUSubType});289  return Result;290}291 292SmallVector<std::pair<uint32_t, uint32_t>>293standardMachOFallbackArchs(uint32_t CPUType, uint32_t CPUSubType) {294  SmallVector<std::pair<uint32_t, uint32_t>> Archs;295 296  // Match given CPU type/subtype first.297  Archs.push_back({CPUType, CPUSubType});298 299  switch (CPUType) {300  case MachO::CPU_TYPE_ARM64:301    // Handle arm64 variants.302    switch (CPUSubType) {303    case MachO::CPU_SUBTYPE_ARM64_ALL:304      Archs.push_back({CPUType, MachO::CPU_SUBTYPE_ARM64E});305      break;306    default:307      break;308    }309    break;310  default:311    break;312  }313 314  return Archs;315}316 317Expected<SymbolNameSet>318getDylibInterfaceFromDylib(ExecutionSession &ES, Twine Path,319                           GetFallbackArchsFn GetFallbackArchs) {320  auto InitCPUType = MachO::getCPUType(ES.getTargetTriple());321  if (!InitCPUType)322    return InitCPUType.takeError();323 324  auto InitCPUSubType = MachO::getCPUSubType(ES.getTargetTriple());325  if (!InitCPUSubType)326    return InitCPUSubType.takeError();327 328  auto Buf = MemoryBuffer::getFile(Path);329  if (!Buf)330    return createFileError(Path, Buf.getError());331 332  auto BinFile = object::createBinary((*Buf)->getMemBufferRef());333  if (!BinFile)334    return BinFile.takeError();335 336  std::unique_ptr<object::MachOObjectFile> MachOFile;337  if (isa<object::MachOObjectFile>(**BinFile)) {338    MachOFile.reset(dyn_cast<object::MachOObjectFile>(BinFile->release()));339 340    // TODO: Check that dylib arch is compatible.341  } else if (auto *MachOUni =342                 dyn_cast<object::MachOUniversalBinary>(BinFile->get())) {343    SmallVector<std::pair<uint32_t, uint32_t>> ArchsToTry;344    if (GetFallbackArchs)345      ArchsToTry = GetFallbackArchs(*InitCPUType, *InitCPUSubType);346    else347      ArchsToTry.push_back({*InitCPUType, *InitCPUSubType});348 349    for (auto &[CPUType, CPUSubType] : ArchsToTry) {350      for (auto &O : MachOUni->objects()) {351        if (O.getCPUType() == CPUType &&352            (O.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) == CPUSubType) {353          if (auto Obj = O.getAsObjectFile())354            MachOFile = std::move(*Obj);355          else356            return Obj.takeError();357          break;358        }359      }360      if (MachOFile) // If found, break out.361        break;362    }363    if (!MachOFile)364      return make_error<StringError>(365          "MachO universal binary at " + Path +366              " does not contain a compatible slice for " +367              ES.getTargetTriple().str(),368          inconvertibleErrorCode());369  } else370    return make_error<StringError>("File at " + Path + " is not a MachO",371                                   inconvertibleErrorCode());372 373  if (MachOFile->getHeader().filetype != MachO::MH_DYLIB)374    return make_error<StringError>("MachO at " + Path + " is not a dylib",375                                   inconvertibleErrorCode());376 377  SymbolNameSet Symbols;378  for (auto &Sym : MachOFile->symbols()) {379    if (auto Name = Sym.getName())380      Symbols.insert(ES.intern(*Name));381    else382      return Name.takeError();383  }384 385  return std::move(Symbols);386}387 388Expected<SymbolNameSet>389getDylibInterfaceFromTapiFile(ExecutionSession &ES, Twine Path,390                              GetFallbackArchsFn GetFallbackArchs) {391  SymbolNameSet Symbols;392 393  auto TapiFileBuffer = MemoryBuffer::getFile(Path);394  if (!TapiFileBuffer)395    return createFileError(Path, TapiFileBuffer.getError());396 397  auto Tapi =398      object::TapiUniversal::create((*TapiFileBuffer)->getMemBufferRef());399  if (!Tapi)400    return Tapi.takeError();401 402  auto InitCPUType = MachO::getCPUType(ES.getTargetTriple());403  if (!InitCPUType)404    return InitCPUType.takeError();405 406  auto InitCPUSubType = MachO::getCPUSubType(ES.getTargetTriple());407  if (!InitCPUSubType)408    return InitCPUSubType.takeError();409 410  SmallVector<std::pair<uint32_t, uint32_t>> ArchsToTry;411  if (GetFallbackArchs)412    ArchsToTry = GetFallbackArchs(*InitCPUType, *InitCPUSubType);413  else414    ArchsToTry.push_back({*InitCPUType, *InitCPUSubType});415 416  auto &IF = (*Tapi)->getInterfaceFile();417 418  auto ArchSet = IF.getArchitectures();419  for (auto [CPUType, CPUSubType] : ArchsToTry) {420    auto A = MachO::getArchitectureFromCpuType(CPUType, CPUSubType);421    if (ArchSet.has(A)) {422      if (auto Interface = IF.extract(A)) {423        for (auto *Sym : (*Interface)->exports())424          Symbols.insert(ES.intern(Sym->getName()));425        return Symbols;426      } else427        return Interface.takeError();428    }429  }430 431  return make_error<StringError>(432      "MachO interface file at " + Path +433          " does not contain a compatible slice for " +434          ES.getTargetTriple().str(),435      inconvertibleErrorCode());436}437 438Expected<SymbolNameSet> getDylibInterface(ExecutionSession &ES, Twine Path,439                                          GetFallbackArchsFn GetFallbackArchs) {440  file_magic Magic;441  if (auto EC = identify_magic(Path, Magic))442    return createFileError(Path, EC);443 444  switch (Magic) {445  case file_magic::macho_universal_binary:446  case file_magic::macho_dynamically_linked_shared_lib:447    return getDylibInterfaceFromDylib(ES, Path, std::move(GetFallbackArchs));448  case file_magic::tapi_file:449    return getDylibInterfaceFromTapiFile(ES, Path, std::move(GetFallbackArchs));450  default:451    return make_error<StringError>("Cannot get interface for " + Path +452                                       " unrecognized file type",453                                   inconvertibleErrorCode());454  }455}456 457} // End namespace orc.458} // End namespace llvm.459