blob: 7e2ebdc46b3047df1470df8c03b04d57d7ced7e3 [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();
Seiya Nuta7f19dd12019-10-28 15:40:37 +090038 S.CanonicalName = (Twine(S.Segname) + "," + S.Sectname).str();
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000039 S.Addr = Sec.addr;
40 S.Size = Sec.size;
41 S.Offset = Sec.offset;
42 S.Align = Sec.align;
43 S.RelOff = Sec.reloff;
44 S.NReloc = Sec.nreloc;
45 S.Flags = Sec.flags;
46 S.Reserved1 = Sec.reserved1;
47 S.Reserved2 = Sec.reserved2;
48 S.Reserved3 = 0;
49 return S;
50}
51
52template <typename SectionType> Section constructSection(SectionType Sec);
53
54template <> Section constructSection(MachO::section Sec) {
55 return constructSectionCommon(Sec);
56}
57
58template <> Section constructSection(MachO::section_64 Sec) {
59 Section S = constructSectionCommon(Sec);
60 S.Reserved3 = Sec.reserved3;
61 return S;
62}
63
64// TODO: get rid of reportError and make MachOReader return Expected<> instead.
65template <typename SectionType, typename SegmentType>
66std::vector<Section>
67extractSections(const object::MachOObjectFile::LoadCommandInfo &LoadCmd,
68 const object::MachOObjectFile &MachOObj,
69 size_t &NextSectionIndex) {
70 auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize;
71 const SectionType *Curr =
72 reinterpret_cast<const SectionType *>(LoadCmd.Ptr + sizeof(SegmentType));
73 std::vector<Section> Sections;
74 for (; reinterpret_cast<const void *>(Curr) < End; Curr++) {
75 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) {
76 SectionType Sec;
77 memcpy((void *)&Sec, Curr, sizeof(SectionType));
78 MachO::swapStruct(Sec);
79 Sections.push_back(constructSection(Sec));
80 } else {
81 Sections.push_back(constructSection(*Curr));
82 }
83
84 Section &S = Sections.back();
85
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000086 Expected<object::SectionRef> SecRef =
87 MachOObj.getSection(NextSectionIndex++);
88 if (!SecRef)
89 reportError(MachOObj.getFileName(), SecRef.takeError());
90
Fangrui Songe1cb2c02019-05-14 04:22:51 +000091 if (Expected<ArrayRef<uint8_t>> E =
92 MachOObj.getSectionContents(SecRef->getRawDataRefImpl()))
93 S.Content =
94 StringRef(reinterpret_cast<const char *>(E->data()), E->size());
95 else
96 reportError(MachOObj.getFileName(), E.takeError());
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000097
98 S.Relocations.reserve(S.NReloc);
99 for (auto RI = MachOObj.section_rel_begin(SecRef->getRawDataRefImpl()),
100 RE = MachOObj.section_rel_end(SecRef->getRawDataRefImpl());
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000101 RI != RE; ++RI) {
102 RelocationInfo R;
103 R.Symbol = nullptr; // We'll fill this field later.
104 R.Info = MachOObj.getRelocation(RI->getRawDataRefImpl());
Seiya Nuta323b89f2019-06-24 23:39:01 +0000105 R.Scattered = MachOObj.isRelocationScattered(R.Info);
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000106 S.Relocations.push_back(R);
107 }
108
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000109 assert(S.NReloc == S.Relocations.size() &&
110 "Incorrect number of relocations");
111 }
112 return Sections;
113}
114
115void MachOReader::readLoadCommands(Object &O) const {
116 // For MachO sections indices start from 1.
117 size_t NextSectionIndex = 1;
118 for (auto LoadCmd : MachOObj.load_commands()) {
119 LoadCommand LC;
120 switch (LoadCmd.C.cmd) {
121 case MachO::LC_SEGMENT:
122 LC.Sections = extractSections<MachO::section, MachO::segment_command>(
123 LoadCmd, MachOObj, NextSectionIndex);
124 break;
125 case MachO::LC_SEGMENT_64:
126 LC.Sections =
127 extractSections<MachO::section_64, MachO::segment_command_64>(
128 LoadCmd, MachOObj, NextSectionIndex);
129 break;
130 case MachO::LC_SYMTAB:
131 O.SymTabCommandIndex = O.LoadCommands.size();
132 break;
Seiya Nuta552bcb82019-08-19 21:05:31 +0000133 case MachO::LC_DYSYMTAB:
134 O.DySymTabCommandIndex = O.LoadCommands.size();
135 break;
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000136 case MachO::LC_DYLD_INFO:
137 case MachO::LC_DYLD_INFO_ONLY:
138 O.DyLdInfoCommandIndex = O.LoadCommands.size();
139 break;
Seiya Nuta552bcb82019-08-19 21:05:31 +0000140 case MachO::LC_DATA_IN_CODE:
141 O.DataInCodeCommandIndex = O.LoadCommands.size();
142 break;
143 case MachO::LC_FUNCTION_STARTS:
144 O.FunctionStartsCommandIndex = O.LoadCommands.size();
145 break;
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000146 }
147#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
148 case MachO::LCName: \
149 memcpy((void *)&(LC.MachOLoadCommand.LCStruct##_data), LoadCmd.Ptr, \
150 sizeof(MachO::LCStruct)); \
151 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) \
152 MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data); \
153 LC.Payload = ArrayRef<uint8_t>( \
154 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \
155 sizeof(MachO::LCStruct), \
156 LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \
157 break;
158
159 switch (LoadCmd.C.cmd) {
160 default:
161 memcpy((void *)&(LC.MachOLoadCommand.load_command_data), LoadCmd.Ptr,
162 sizeof(MachO::load_command));
163 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost)
164 MachO::swapStruct(LC.MachOLoadCommand.load_command_data);
165 LC.Payload = ArrayRef<uint8_t>(
166 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) +
167 sizeof(MachO::load_command),
168 LoadCmd.C.cmdsize - sizeof(MachO::load_command));
169 break;
170#include "llvm/BinaryFormat/MachO.def"
171 }
172 O.LoadCommands.push_back(std::move(LC));
173 }
174}
175
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000176template <typename nlist_t>
177SymbolEntry constructSymbolEntry(StringRef StrTable, const nlist_t &nlist) {
178 assert(nlist.n_strx < StrTable.size() &&
179 "n_strx exceeds the size of the string table");
180 SymbolEntry SE;
181 SE.Name = StringRef(StrTable.data() + nlist.n_strx).str();
182 SE.n_type = nlist.n_type;
183 SE.n_sect = nlist.n_sect;
184 SE.n_desc = nlist.n_desc;
185 SE.n_value = nlist.n_value;
186 return SE;
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000187}
188
189void MachOReader::readSymbolTable(Object &O) const {
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000190 StringRef StrTable = MachOObj.getStringTableData();
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000191 for (auto Symbol : MachOObj.symbols()) {
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000192 SymbolEntry SE =
193 (MachOObj.is64Bit()
194 ? constructSymbolEntry(
195 StrTable,
196 MachOObj.getSymbol64TableEntry(Symbol.getRawDataRefImpl()))
197 : constructSymbolEntry(
198 StrTable,
199 MachOObj.getSymbolTableEntry(Symbol.getRawDataRefImpl())));
200
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000201 O.SymTable.Symbols.push_back(std::make_unique<SymbolEntry>(SE));
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000202 }
Clement Courbetbe16b802019-02-04 10:24:42 +0000203}
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000204
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000205void MachOReader::setSymbolInRelocationInfo(Object &O) const {
206 for (auto &LC : O.LoadCommands)
207 for (auto &Sec : LC.Sections)
208 for (auto &Reloc : Sec.Relocations)
209 if (!Reloc.Scattered) {
210 auto *Info = reinterpret_cast<MachO::relocation_info *>(&Reloc.Info);
211 Reloc.Symbol = O.SymTable.getSymbolByIndex(Info->r_symbolnum);
212 }
Clement Courbetbe16b802019-02-04 10:24:42 +0000213}
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000214
215void MachOReader::readRebaseInfo(Object &O) const {
216 O.Rebases.Opcodes = MachOObj.getDyldInfoRebaseOpcodes();
217}
218
219void MachOReader::readBindInfo(Object &O) const {
220 O.Binds.Opcodes = MachOObj.getDyldInfoBindOpcodes();
221}
222
223void MachOReader::readWeakBindInfo(Object &O) const {
224 O.WeakBinds.Opcodes = MachOObj.getDyldInfoWeakBindOpcodes();
225}
226
227void MachOReader::readLazyBindInfo(Object &O) const {
228 O.LazyBinds.Opcodes = MachOObj.getDyldInfoLazyBindOpcodes();
229}
230
231void MachOReader::readExportInfo(Object &O) const {
232 O.Exports.Trie = MachOObj.getDyldInfoExportsTrie();
233}
234
Seiya Nuta552bcb82019-08-19 21:05:31 +0000235void MachOReader::readDataInCodeData(Object &O) const {
236 if (!O.DataInCodeCommandIndex)
237 return;
238 const MachO::linkedit_data_command &LDC =
239 O.LoadCommands[*O.DataInCodeCommandIndex]
240 .MachOLoadCommand.linkedit_data_command_data;
241
242 O.DataInCode.Data = arrayRefFromStringRef(
243 MachOObj.getData().substr(LDC.dataoff, LDC.datasize));
244}
245
246void MachOReader::readFunctionStartsData(Object &O) const {
247 if (!O.FunctionStartsCommandIndex)
248 return;
249 const MachO::linkedit_data_command &LDC =
250 O.LoadCommands[*O.FunctionStartsCommandIndex]
251 .MachOLoadCommand.linkedit_data_command_data;
252
253 O.FunctionStarts.Data = arrayRefFromStringRef(
254 MachOObj.getData().substr(LDC.dataoff, LDC.datasize));
255}
256
257void MachOReader::readIndirectSymbolTable(Object &O) const {
258 MachO::dysymtab_command DySymTab = MachOObj.getDysymtabLoadCommand();
Seiya Nuta1e589f62019-10-30 15:12:17 +0900259 constexpr uint32_t AbsOrLocalMask =
260 MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS;
261 for (uint32_t i = 0; i < DySymTab.nindirectsyms; ++i) {
262 uint32_t Index = MachOObj.getIndirectSymbolTableEntry(DySymTab, i);
263 if ((Index & AbsOrLocalMask) != 0)
264 O.IndirectSymTable.Symbols.emplace_back(Index, None);
265 else
266 O.IndirectSymTable.Symbols.emplace_back(
267 Index, O.SymTable.getSymbolByIndex(Index));
268 }
Seiya Nuta552bcb82019-08-19 21:05:31 +0000269}
270
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000271std::unique_ptr<Object> MachOReader::create() const {
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000272 auto Obj = std::make_unique<Object>();
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000273 readHeader(*Obj);
274 readLoadCommands(*Obj);
275 readSymbolTable(*Obj);
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000276 setSymbolInRelocationInfo(*Obj);
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000277 readRebaseInfo(*Obj);
278 readBindInfo(*Obj);
279 readWeakBindInfo(*Obj);
280 readLazyBindInfo(*Obj);
281 readExportInfo(*Obj);
Seiya Nuta552bcb82019-08-19 21:05:31 +0000282 readDataInCodeData(*Obj);
283 readFunctionStartsData(*Obj);
284 readIndirectSymbolTable(*Obj);
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000285 return Obj;
286}
287
288} // end namespace macho
289} // end namespace objcopy
290} // end namespace llvm