blob: cc0e5380eac3917f28d664df378b99c65c93c025 [file] [log] [blame]
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +00001//===- MachOReader.cpp ------------------------------------------*- C++ -*-===//
2//
Chandler Carruth127252b2019-02-11 08:25:19 +00003// 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-exception
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "MachOReader.h"
10#include "../llvm-objcopy.h"
11#include "Object.h"
12#include "llvm/BinaryFormat/MachO.h"
13#include "llvm/Object/MachO.h"
14#include <memory>
15
16namespace llvm {
17namespace objcopy {
18namespace macho {
19
20void MachOReader::readHeader(Object &O) const {
21 O.Header.Magic = MachOObj.getHeader().magic;
22 O.Header.CPUType = MachOObj.getHeader().cputype;
23 O.Header.CPUSubType = MachOObj.getHeader().cpusubtype;
24 O.Header.FileType = MachOObj.getHeader().filetype;
25 O.Header.NCmds = MachOObj.getHeader().ncmds;
26 O.Header.SizeOfCmds = MachOObj.getHeader().sizeofcmds;
27 O.Header.Flags = MachOObj.getHeader().flags;
28}
29
30template <typename SectionType>
31Section constructSectionCommon(SectionType Sec) {
32 Section S;
Seiya Nutab728e532019-06-08 01:22:54 +000033 S.Sectname =
34 StringRef(Sec.sectname, strnlen(Sec.sectname, sizeof(Sec.sectname)))
35 .str();
36 S.Segname =
37 StringRef(Sec.segname, strnlen(Sec.segname, sizeof(Sec.sectname))).str();
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000038 S.Addr = Sec.addr;
39 S.Size = Sec.size;
40 S.Offset = Sec.offset;
41 S.Align = Sec.align;
42 S.RelOff = Sec.reloff;
43 S.NReloc = Sec.nreloc;
44 S.Flags = Sec.flags;
45 S.Reserved1 = Sec.reserved1;
46 S.Reserved2 = Sec.reserved2;
47 S.Reserved3 = 0;
48 return S;
49}
50
51template <typename SectionType> Section constructSection(SectionType Sec);
52
53template <> Section constructSection(MachO::section Sec) {
54 return constructSectionCommon(Sec);
55}
56
57template <> Section constructSection(MachO::section_64 Sec) {
58 Section S = constructSectionCommon(Sec);
59 S.Reserved3 = Sec.reserved3;
60 return S;
61}
62
63// TODO: get rid of reportError and make MachOReader return Expected<> instead.
64template <typename SectionType, typename SegmentType>
65std::vector<Section>
66extractSections(const object::MachOObjectFile::LoadCommandInfo &LoadCmd,
67 const object::MachOObjectFile &MachOObj,
68 size_t &NextSectionIndex) {
69 auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize;
70 const SectionType *Curr =
71 reinterpret_cast<const SectionType *>(LoadCmd.Ptr + sizeof(SegmentType));
72 std::vector<Section> Sections;
73 for (; reinterpret_cast<const void *>(Curr) < End; Curr++) {
74 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) {
75 SectionType Sec;
76 memcpy((void *)&Sec, Curr, sizeof(SectionType));
77 MachO::swapStruct(Sec);
78 Sections.push_back(constructSection(Sec));
79 } else {
80 Sections.push_back(constructSection(*Curr));
81 }
82
83 Section &S = Sections.back();
84
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000085 Expected<object::SectionRef> SecRef =
86 MachOObj.getSection(NextSectionIndex++);
87 if (!SecRef)
88 reportError(MachOObj.getFileName(), SecRef.takeError());
89
Fangrui Songe1cb2c02019-05-14 04:22:51 +000090 if (Expected<ArrayRef<uint8_t>> E =
91 MachOObj.getSectionContents(SecRef->getRawDataRefImpl()))
92 S.Content =
93 StringRef(reinterpret_cast<const char *>(E->data()), E->size());
94 else
95 reportError(MachOObj.getFileName(), E.takeError());
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000096
97 S.Relocations.reserve(S.NReloc);
98 for (auto RI = MachOObj.section_rel_begin(SecRef->getRawDataRefImpl()),
99 RE = MachOObj.section_rel_end(SecRef->getRawDataRefImpl());
100 RI != RE; ++RI)
101 S.Relocations.push_back(MachOObj.getRelocation(RI->getRawDataRefImpl()));
102 assert(S.NReloc == S.Relocations.size() &&
103 "Incorrect number of relocations");
104 }
105 return Sections;
106}
107
108void MachOReader::readLoadCommands(Object &O) const {
109 // For MachO sections indices start from 1.
110 size_t NextSectionIndex = 1;
111 for (auto LoadCmd : MachOObj.load_commands()) {
112 LoadCommand LC;
113 switch (LoadCmd.C.cmd) {
114 case MachO::LC_SEGMENT:
115 LC.Sections = extractSections<MachO::section, MachO::segment_command>(
116 LoadCmd, MachOObj, NextSectionIndex);
117 break;
118 case MachO::LC_SEGMENT_64:
119 LC.Sections =
120 extractSections<MachO::section_64, MachO::segment_command_64>(
121 LoadCmd, MachOObj, NextSectionIndex);
122 break;
123 case MachO::LC_SYMTAB:
124 O.SymTabCommandIndex = O.LoadCommands.size();
125 break;
126 case MachO::LC_DYLD_INFO:
127 case MachO::LC_DYLD_INFO_ONLY:
128 O.DyLdInfoCommandIndex = O.LoadCommands.size();
129 break;
130 }
131#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
132 case MachO::LCName: \
133 memcpy((void *)&(LC.MachOLoadCommand.LCStruct##_data), LoadCmd.Ptr, \
134 sizeof(MachO::LCStruct)); \
135 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) \
136 MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data); \
137 LC.Payload = ArrayRef<uint8_t>( \
138 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \
139 sizeof(MachO::LCStruct), \
140 LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \
141 break;
142
143 switch (LoadCmd.C.cmd) {
144 default:
145 memcpy((void *)&(LC.MachOLoadCommand.load_command_data), LoadCmd.Ptr,
146 sizeof(MachO::load_command));
147 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost)
148 MachO::swapStruct(LC.MachOLoadCommand.load_command_data);
149 LC.Payload = ArrayRef<uint8_t>(
150 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) +
151 sizeof(MachO::load_command),
152 LoadCmd.C.cmdsize - sizeof(MachO::load_command));
153 break;
154#include "llvm/BinaryFormat/MachO.def"
155 }
156 O.LoadCommands.push_back(std::move(LC));
157 }
158}
159
160template <typename nlist_t> NListEntry constructNameList(const nlist_t &nlist) {
161 NListEntry NL;
162 NL.n_strx = nlist.n_strx;
163 NL.n_type = nlist.n_type;
164 NL.n_sect = nlist.n_sect;
165 NL.n_desc = nlist.n_desc;
166 NL.n_value = nlist.n_value;
167 return NL;
168}
169
170void MachOReader::readSymbolTable(Object &O) const {
171 for (auto Symbol : MachOObj.symbols()) {
172 NListEntry NLE =
173 MachOObj.is64Bit()
174 ? constructNameList<MachO::nlist_64>(
175 MachOObj.getSymbol64TableEntry(Symbol.getRawDataRefImpl()))
176 : constructNameList<MachO::nlist>(
177 MachOObj.getSymbolTableEntry(Symbol.getRawDataRefImpl()));
178 O.SymTable.NameList.push_back(NLE);
179 }
Clement Courbetbe16b802019-02-04 10:24:42 +0000180}
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000181
182void MachOReader::readStringTable(Object &O) const {
183 StringRef Data = MachOObj.getStringTableData();
184 SmallVector<StringRef, 10> Strs;
185 Data.split(Strs, '\0');
186 O.StrTable.Strings.reserve(Strs.size());
187 for (auto S : Strs)
188 O.StrTable.Strings.push_back(S.str());
Clement Courbetbe16b802019-02-04 10:24:42 +0000189}
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000190
191void MachOReader::readRebaseInfo(Object &O) const {
192 O.Rebases.Opcodes = MachOObj.getDyldInfoRebaseOpcodes();
193}
194
195void MachOReader::readBindInfo(Object &O) const {
196 O.Binds.Opcodes = MachOObj.getDyldInfoBindOpcodes();
197}
198
199void MachOReader::readWeakBindInfo(Object &O) const {
200 O.WeakBinds.Opcodes = MachOObj.getDyldInfoWeakBindOpcodes();
201}
202
203void MachOReader::readLazyBindInfo(Object &O) const {
204 O.LazyBinds.Opcodes = MachOObj.getDyldInfoLazyBindOpcodes();
205}
206
207void MachOReader::readExportInfo(Object &O) const {
208 O.Exports.Trie = MachOObj.getDyldInfoExportsTrie();
209}
210
211std::unique_ptr<Object> MachOReader::create() const {
212 auto Obj = llvm::make_unique<Object>();
213 readHeader(*Obj);
214 readLoadCommands(*Obj);
215 readSymbolTable(*Obj);
216 readStringTable(*Obj);
217 readRebaseInfo(*Obj);
218 readBindInfo(*Obj);
219 readWeakBindInfo(*Obj);
220 readLazyBindInfo(*Obj);
221 readExportInfo(*Obj);
222 return Obj;
223}
224
225} // end namespace macho
226} // end namespace objcopy
227} // end namespace llvm