diff options
Diffstat (limited to 'llvm/tools/llvm-objcopy/MachO/MachOReader.cpp')
| -rw-r--r-- | llvm/tools/llvm-objcopy/MachO/MachOReader.cpp | 282 | 
1 files changed, 282 insertions, 0 deletions
| diff --git a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp new file mode 100644 index 000000000000..b48a0d8952d0 --- /dev/null +++ b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp @@ -0,0 +1,282 @@ +//===- MachOReader.cpp ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MachOReader.h" +#include "../llvm-objcopy.h" +#include "Object.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/Object/MachO.h" +#include <memory> + +namespace llvm { +namespace objcopy { +namespace macho { + +void MachOReader::readHeader(Object &O) const { +  O.Header.Magic = MachOObj.getHeader().magic; +  O.Header.CPUType = MachOObj.getHeader().cputype; +  O.Header.CPUSubType = MachOObj.getHeader().cpusubtype; +  O.Header.FileType = MachOObj.getHeader().filetype; +  O.Header.NCmds = MachOObj.getHeader().ncmds; +  O.Header.SizeOfCmds = MachOObj.getHeader().sizeofcmds; +  O.Header.Flags = MachOObj.getHeader().flags; +} + +template <typename SectionType> +Section constructSectionCommon(SectionType Sec) { +  Section S; +  S.Sectname = +      StringRef(Sec.sectname, strnlen(Sec.sectname, sizeof(Sec.sectname))) +          .str(); +  S.Segname = +      StringRef(Sec.segname, strnlen(Sec.segname, sizeof(Sec.sectname))).str(); +  S.Addr = Sec.addr; +  S.Size = Sec.size; +  S.Offset = Sec.offset; +  S.Align = Sec.align; +  S.RelOff = Sec.reloff; +  S.NReloc = Sec.nreloc; +  S.Flags = Sec.flags; +  S.Reserved1 = Sec.reserved1; +  S.Reserved2 = Sec.reserved2; +  S.Reserved3 = 0; +  return S; +} + +template <typename SectionType> Section constructSection(SectionType Sec); + +template <> Section constructSection(MachO::section Sec) { +  return constructSectionCommon(Sec); +} + +template <> Section constructSection(MachO::section_64 Sec) { +  Section S = constructSectionCommon(Sec); +  S.Reserved3 = Sec.reserved3; +  return S; +} + +// TODO: get rid of reportError and make MachOReader return Expected<> instead. +template <typename SectionType, typename SegmentType> +std::vector<Section> +extractSections(const object::MachOObjectFile::LoadCommandInfo &LoadCmd, +                const object::MachOObjectFile &MachOObj, +                size_t &NextSectionIndex) { +  auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize; +  const SectionType *Curr = +      reinterpret_cast<const SectionType *>(LoadCmd.Ptr + sizeof(SegmentType)); +  std::vector<Section> Sections; +  for (; reinterpret_cast<const void *>(Curr) < End; Curr++) { +    if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) { +      SectionType Sec; +      memcpy((void *)&Sec, Curr, sizeof(SectionType)); +      MachO::swapStruct(Sec); +      Sections.push_back(constructSection(Sec)); +    } else { +      Sections.push_back(constructSection(*Curr)); +    } + +    Section &S = Sections.back(); + +    Expected<object::SectionRef> SecRef = +        MachOObj.getSection(NextSectionIndex++); +    if (!SecRef) +      reportError(MachOObj.getFileName(), SecRef.takeError()); + +    if (Expected<ArrayRef<uint8_t>> E = +            MachOObj.getSectionContents(SecRef->getRawDataRefImpl())) +      S.Content = +          StringRef(reinterpret_cast<const char *>(E->data()), E->size()); +    else +      reportError(MachOObj.getFileName(), E.takeError()); + +    S.Relocations.reserve(S.NReloc); +    for (auto RI = MachOObj.section_rel_begin(SecRef->getRawDataRefImpl()), +              RE = MachOObj.section_rel_end(SecRef->getRawDataRefImpl()); +         RI != RE; ++RI) { +      RelocationInfo R; +      R.Symbol = nullptr; // We'll fill this field later. +      R.Info = MachOObj.getRelocation(RI->getRawDataRefImpl()); +      R.Scattered = MachOObj.isRelocationScattered(R.Info); +      S.Relocations.push_back(R); +    } + +    assert(S.NReloc == S.Relocations.size() && +           "Incorrect number of relocations"); +  } +  return Sections; +} + +void MachOReader::readLoadCommands(Object &O) const { +  // For MachO sections indices start from 1. +  size_t NextSectionIndex = 1; +  for (auto LoadCmd : MachOObj.load_commands()) { +    LoadCommand LC; +    switch (LoadCmd.C.cmd) { +    case MachO::LC_SEGMENT: +      LC.Sections = extractSections<MachO::section, MachO::segment_command>( +          LoadCmd, MachOObj, NextSectionIndex); +      break; +    case MachO::LC_SEGMENT_64: +      LC.Sections = +          extractSections<MachO::section_64, MachO::segment_command_64>( +              LoadCmd, MachOObj, NextSectionIndex); +      break; +    case MachO::LC_SYMTAB: +      O.SymTabCommandIndex = O.LoadCommands.size(); +      break; +    case MachO::LC_DYSYMTAB: +      O.DySymTabCommandIndex = O.LoadCommands.size(); +      break; +    case MachO::LC_DYLD_INFO: +    case MachO::LC_DYLD_INFO_ONLY: +      O.DyLdInfoCommandIndex = O.LoadCommands.size(); +      break; +    case MachO::LC_DATA_IN_CODE: +      O.DataInCodeCommandIndex = O.LoadCommands.size(); +      break; +    case MachO::LC_FUNCTION_STARTS: +      O.FunctionStartsCommandIndex = O.LoadCommands.size(); +      break; +    } +#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct)                         \ +  case MachO::LCName:                                                          \ +    memcpy((void *)&(LC.MachOLoadCommand.LCStruct##_data), LoadCmd.Ptr,        \ +           sizeof(MachO::LCStruct));                                           \ +    if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost)                  \ +      MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data);                  \ +    LC.Payload = ArrayRef<uint8_t>(                                            \ +        reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) +         \ +            sizeof(MachO::LCStruct),                                           \ +        LoadCmd.C.cmdsize - sizeof(MachO::LCStruct));                          \ +    break; + +    switch (LoadCmd.C.cmd) { +    default: +      memcpy((void *)&(LC.MachOLoadCommand.load_command_data), LoadCmd.Ptr, +             sizeof(MachO::load_command)); +      if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) +        MachO::swapStruct(LC.MachOLoadCommand.load_command_data); +      LC.Payload = ArrayRef<uint8_t>( +          reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + +              sizeof(MachO::load_command), +          LoadCmd.C.cmdsize - sizeof(MachO::load_command)); +      break; +#include "llvm/BinaryFormat/MachO.def" +    } +    O.LoadCommands.push_back(std::move(LC)); +  } +} + +template <typename nlist_t> +SymbolEntry constructSymbolEntry(StringRef StrTable, const nlist_t &nlist) { +  assert(nlist.n_strx < StrTable.size() && +         "n_strx exceeds the size of the string table"); +  SymbolEntry SE; +  SE.Name = StringRef(StrTable.data() + nlist.n_strx).str(); +  SE.n_type = nlist.n_type; +  SE.n_sect = nlist.n_sect; +  SE.n_desc = nlist.n_desc; +  SE.n_value = nlist.n_value; +  return SE; +} + +void MachOReader::readSymbolTable(Object &O) const { +  StringRef StrTable = MachOObj.getStringTableData(); +  for (auto Symbol : MachOObj.symbols()) { +    SymbolEntry SE = +        (MachOObj.is64Bit() +             ? constructSymbolEntry( +                   StrTable, +                   MachOObj.getSymbol64TableEntry(Symbol.getRawDataRefImpl())) +             : constructSymbolEntry( +                   StrTable, +                   MachOObj.getSymbolTableEntry(Symbol.getRawDataRefImpl()))); + +    O.SymTable.Symbols.push_back(std::make_unique<SymbolEntry>(SE)); +  } +} + +void MachOReader::setSymbolInRelocationInfo(Object &O) const { +  for (auto &LC : O.LoadCommands) +    for (auto &Sec : LC.Sections) +      for (auto &Reloc : Sec.Relocations) +        if (!Reloc.Scattered) { +          auto *Info = reinterpret_cast<MachO::relocation_info *>(&Reloc.Info); +          Reloc.Symbol = O.SymTable.getSymbolByIndex(Info->r_symbolnum); +        } +} + +void MachOReader::readRebaseInfo(Object &O) const { +  O.Rebases.Opcodes = MachOObj.getDyldInfoRebaseOpcodes(); +} + +void MachOReader::readBindInfo(Object &O) const { +  O.Binds.Opcodes = MachOObj.getDyldInfoBindOpcodes(); +} + +void MachOReader::readWeakBindInfo(Object &O) const { +  O.WeakBinds.Opcodes = MachOObj.getDyldInfoWeakBindOpcodes(); +} + +void MachOReader::readLazyBindInfo(Object &O) const { +  O.LazyBinds.Opcodes = MachOObj.getDyldInfoLazyBindOpcodes(); +} + +void MachOReader::readExportInfo(Object &O) const { +  O.Exports.Trie = MachOObj.getDyldInfoExportsTrie(); +} + +void MachOReader::readDataInCodeData(Object &O) const { +  if (!O.DataInCodeCommandIndex) +    return; +  const MachO::linkedit_data_command &LDC = +      O.LoadCommands[*O.DataInCodeCommandIndex] +          .MachOLoadCommand.linkedit_data_command_data; + +  O.DataInCode.Data = arrayRefFromStringRef( +      MachOObj.getData().substr(LDC.dataoff, LDC.datasize)); +} + +void MachOReader::readFunctionStartsData(Object &O) const { +  if (!O.FunctionStartsCommandIndex) +    return; +  const MachO::linkedit_data_command &LDC = +      O.LoadCommands[*O.FunctionStartsCommandIndex] +          .MachOLoadCommand.linkedit_data_command_data; + +  O.FunctionStarts.Data = arrayRefFromStringRef( +      MachOObj.getData().substr(LDC.dataoff, LDC.datasize)); +} + +void MachOReader::readIndirectSymbolTable(Object &O) const { +  MachO::dysymtab_command DySymTab = MachOObj.getDysymtabLoadCommand(); +  for (uint32_t i = 0; i < DySymTab.nindirectsyms; ++i) +    O.IndirectSymTable.Symbols.push_back( +        MachOObj.getIndirectSymbolTableEntry(DySymTab, i)); +} + +std::unique_ptr<Object> MachOReader::create() const { +  auto Obj = std::make_unique<Object>(); +  readHeader(*Obj); +  readLoadCommands(*Obj); +  readSymbolTable(*Obj); +  setSymbolInRelocationInfo(*Obj); +  readRebaseInfo(*Obj); +  readBindInfo(*Obj); +  readWeakBindInfo(*Obj); +  readLazyBindInfo(*Obj); +  readExportInfo(*Obj); +  readDataInCodeData(*Obj); +  readFunctionStartsData(*Obj); +  readIndirectSymbolTable(*Obj); +  return Obj; +} + +} // end namespace macho +} // end namespace objcopy +} // end namespace llvm | 
