blob: 39a8893c1eb1b5040ca9c3c604eb24d2570cec8d [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>
Alexander Shaposhnikovf34fdbc2020-04-22 14:26:28 -070031Section constructSectionCommon(SectionType Sec, uint32_t Index) {
Seiya Nuta9e119ad2019-12-16 14:05:06 +090032 StringRef SegName(Sec.segname, strnlen(Sec.segname, sizeof(Sec.segname)));
33 StringRef SectName(Sec.sectname, strnlen(Sec.sectname, sizeof(Sec.sectname)));
34 Section S(SegName, SectName);
Alexander Shaposhnikovf34fdbc2020-04-22 14:26:28 -070035 S.Index = Index;
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000036 S.Addr = Sec.addr;
37 S.Size = Sec.size;
38 S.Offset = Sec.offset;
39 S.Align = Sec.align;
40 S.RelOff = Sec.reloff;
41 S.NReloc = Sec.nreloc;
42 S.Flags = Sec.flags;
43 S.Reserved1 = Sec.reserved1;
44 S.Reserved2 = Sec.reserved2;
45 S.Reserved3 = 0;
46 return S;
47}
48
Alexander Shaposhnikovf34fdbc2020-04-22 14:26:28 -070049template <typename SectionType>
50Section constructSection(SectionType Sec, uint32_t Index);
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000051
Alexander Shaposhnikovf34fdbc2020-04-22 14:26:28 -070052template <> Section constructSection(MachO::section Sec, uint32_t Index) {
53 return constructSectionCommon(Sec, Index);
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000054}
55
Alexander Shaposhnikovf34fdbc2020-04-22 14:26:28 -070056template <> Section constructSection(MachO::section_64 Sec, uint32_t Index) {
57 Section S = constructSectionCommon(Sec, Index);
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000058 S.Reserved3 = Sec.reserved3;
59 return S;
60}
61
62// TODO: get rid of reportError and make MachOReader return Expected<> instead.
63template <typename SectionType, typename SegmentType>
Alexander Shaposhnikovdc046c72020-02-21 13:18:36 -080064std::vector<std::unique_ptr<Section>>
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000065extractSections(const object::MachOObjectFile::LoadCommandInfo &LoadCmd,
66 const object::MachOObjectFile &MachOObj,
Alexander Shaposhnikovf34fdbc2020-04-22 14:26:28 -070067 uint32_t &NextSectionIndex) {
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000068 auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize;
69 const SectionType *Curr =
70 reinterpret_cast<const SectionType *>(LoadCmd.Ptr + sizeof(SegmentType));
Alexander Shaposhnikovdc046c72020-02-21 13:18:36 -080071 std::vector<std::unique_ptr<Section>> Sections;
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000072 for (; reinterpret_cast<const void *>(Curr) < End; Curr++) {
73 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) {
74 SectionType Sec;
75 memcpy((void *)&Sec, Curr, sizeof(SectionType));
76 MachO::swapStruct(Sec);
Alexander Shaposhnikovf34fdbc2020-04-22 14:26:28 -070077 Sections.push_back(
78 std::make_unique<Section>(constructSection(Sec, NextSectionIndex)));
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000079 } else {
Alexander Shaposhnikovf34fdbc2020-04-22 14:26:28 -070080 Sections.push_back(
81 std::make_unique<Section>(constructSection(*Curr, NextSectionIndex)));
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000082 }
83
Alexander Shaposhnikovdc046c72020-02-21 13:18:36 -080084 Section &S = *Sections.back();
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +000085
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);
Alexander Shaposhnikov0db3a5a2020-04-26 22:39:50 -0700106 R.Extern = !R.Scattered && MachOObj.getPlainRelocationExternal(R.Info);
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000107 S.Relocations.push_back(R);
108 }
109
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000110 assert(S.NReloc == S.Relocations.size() &&
111 "Incorrect number of relocations");
112 }
113 return Sections;
114}
115
116void MachOReader::readLoadCommands(Object &O) const {
117 // For MachO sections indices start from 1.
Alexander Shaposhnikovf34fdbc2020-04-22 14:26:28 -0700118 uint32_t NextSectionIndex = 1;
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000119 for (auto LoadCmd : MachOObj.load_commands()) {
120 LoadCommand LC;
121 switch (LoadCmd.C.cmd) {
122 case MachO::LC_SEGMENT:
123 LC.Sections = extractSections<MachO::section, MachO::segment_command>(
124 LoadCmd, MachOObj, NextSectionIndex);
125 break;
126 case MachO::LC_SEGMENT_64:
127 LC.Sections =
128 extractSections<MachO::section_64, MachO::segment_command_64>(
129 LoadCmd, MachOObj, NextSectionIndex);
130 break;
131 case MachO::LC_SYMTAB:
132 O.SymTabCommandIndex = O.LoadCommands.size();
133 break;
Seiya Nuta552bcb82019-08-19 21:05:31 +0000134 case MachO::LC_DYSYMTAB:
135 O.DySymTabCommandIndex = O.LoadCommands.size();
136 break;
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000137 case MachO::LC_DYLD_INFO:
138 case MachO::LC_DYLD_INFO_ONLY:
139 O.DyLdInfoCommandIndex = O.LoadCommands.size();
140 break;
Seiya Nuta552bcb82019-08-19 21:05:31 +0000141 case MachO::LC_DATA_IN_CODE:
142 O.DataInCodeCommandIndex = O.LoadCommands.size();
143 break;
144 case MachO::LC_FUNCTION_STARTS:
145 O.FunctionStartsCommandIndex = O.LoadCommands.size();
146 break;
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000147 }
148#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
149 case MachO::LCName: \
150 memcpy((void *)&(LC.MachOLoadCommand.LCStruct##_data), LoadCmd.Ptr, \
151 sizeof(MachO::LCStruct)); \
152 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) \
153 MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data); \
Alexander Shaposhnikovc54959c2019-11-19 23:30:52 -0800154 if (LoadCmd.C.cmdsize > sizeof(MachO::LCStruct)) \
155 LC.Payload = ArrayRef<uint8_t>( \
156 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \
157 sizeof(MachO::LCStruct), \
158 LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000159 break;
160
161 switch (LoadCmd.C.cmd) {
162 default:
163 memcpy((void *)&(LC.MachOLoadCommand.load_command_data), LoadCmd.Ptr,
164 sizeof(MachO::load_command));
165 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost)
166 MachO::swapStruct(LC.MachOLoadCommand.load_command_data);
Alexander Shaposhnikovc54959c2019-11-19 23:30:52 -0800167 if (LoadCmd.C.cmdsize > sizeof(MachO::load_command))
168 LC.Payload = ArrayRef<uint8_t>(
169 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) +
170 sizeof(MachO::load_command),
171 LoadCmd.C.cmdsize - sizeof(MachO::load_command));
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000172 break;
173#include "llvm/BinaryFormat/MachO.def"
174 }
175 O.LoadCommands.push_back(std::move(LC));
176 }
177}
178
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000179template <typename nlist_t>
180SymbolEntry constructSymbolEntry(StringRef StrTable, const nlist_t &nlist) {
181 assert(nlist.n_strx < StrTable.size() &&
182 "n_strx exceeds the size of the string table");
183 SymbolEntry SE;
184 SE.Name = StringRef(StrTable.data() + nlist.n_strx).str();
185 SE.n_type = nlist.n_type;
186 SE.n_sect = nlist.n_sect;
187 SE.n_desc = nlist.n_desc;
188 SE.n_value = nlist.n_value;
189 return SE;
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000190}
191
192void MachOReader::readSymbolTable(Object &O) const {
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000193 StringRef StrTable = MachOObj.getStringTableData();
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000194 for (auto Symbol : MachOObj.symbols()) {
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000195 SymbolEntry SE =
196 (MachOObj.is64Bit()
Alexander Shaposhnikovf34fdbc2020-04-22 14:26:28 -0700197 ? constructSymbolEntry(StrTable, MachOObj.getSymbol64TableEntry(
198 Symbol.getRawDataRefImpl()))
199 : constructSymbolEntry(StrTable, MachOObj.getSymbolTableEntry(
200 Symbol.getRawDataRefImpl())));
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000201
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000202 O.SymTable.Symbols.push_back(std::make_unique<SymbolEntry>(SE));
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000203 }
Clement Courbetbe16b802019-02-04 10:24:42 +0000204}
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000205
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000206void MachOReader::setSymbolInRelocationInfo(Object &O) const {
Alexander Shaposhnikov0db3a5a2020-04-26 22:39:50 -0700207 std::vector<const Section *> Sections;
208 for (auto &LC : O.LoadCommands)
209 for (std::unique_ptr<Section> &Sec : LC.Sections)
210 Sections.push_back(Sec.get());
211
Alexander Shaposhnikovdc046c72020-02-21 13:18:36 -0800212 for (LoadCommand &LC : O.LoadCommands)
213 for (std::unique_ptr<Section> &Sec : LC.Sections)
214 for (auto &Reloc : Sec->Relocations)
Alexander Shaposhnikov0db3a5a2020-04-26 22:39:50 -0700215 if (!Reloc.Scattered) {
216 const uint32_t SymbolNum =
217 Reloc.getPlainRelocationSymbolNum(MachOObj.isLittleEndian());
218 if (Reloc.Extern) {
219 Reloc.Symbol = O.SymTable.getSymbolByIndex(SymbolNum);
220 } else {
221 // FIXME: Refactor error handling in MachOReader and report an error
222 // if we encounter an invalid relocation.
223 assert(SymbolNum >= 1 && SymbolNum <= Sections.size() &&
224 "Invalid section index.");
Alexander Shaposhnikov29c6f5c2020-04-27 18:20:01 -0700225 Reloc.Sec = Sections[SymbolNum - 1];
Alexander Shaposhnikov0db3a5a2020-04-26 22:39:50 -0700226 }
227 }
Clement Courbetbe16b802019-02-04 10:24:42 +0000228}
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000229
230void MachOReader::readRebaseInfo(Object &O) const {
231 O.Rebases.Opcodes = MachOObj.getDyldInfoRebaseOpcodes();
232}
233
234void MachOReader::readBindInfo(Object &O) const {
235 O.Binds.Opcodes = MachOObj.getDyldInfoBindOpcodes();
236}
237
238void MachOReader::readWeakBindInfo(Object &O) const {
239 O.WeakBinds.Opcodes = MachOObj.getDyldInfoWeakBindOpcodes();
240}
241
242void MachOReader::readLazyBindInfo(Object &O) const {
243 O.LazyBinds.Opcodes = MachOObj.getDyldInfoLazyBindOpcodes();
244}
245
246void MachOReader::readExportInfo(Object &O) const {
247 O.Exports.Trie = MachOObj.getDyldInfoExportsTrie();
248}
249
Seiya Nuta552bcb82019-08-19 21:05:31 +0000250void MachOReader::readDataInCodeData(Object &O) const {
251 if (!O.DataInCodeCommandIndex)
252 return;
253 const MachO::linkedit_data_command &LDC =
254 O.LoadCommands[*O.DataInCodeCommandIndex]
255 .MachOLoadCommand.linkedit_data_command_data;
256
257 O.DataInCode.Data = arrayRefFromStringRef(
258 MachOObj.getData().substr(LDC.dataoff, LDC.datasize));
259}
260
261void MachOReader::readFunctionStartsData(Object &O) const {
262 if (!O.FunctionStartsCommandIndex)
263 return;
264 const MachO::linkedit_data_command &LDC =
265 O.LoadCommands[*O.FunctionStartsCommandIndex]
266 .MachOLoadCommand.linkedit_data_command_data;
267
268 O.FunctionStarts.Data = arrayRefFromStringRef(
269 MachOObj.getData().substr(LDC.dataoff, LDC.datasize));
270}
271
272void MachOReader::readIndirectSymbolTable(Object &O) const {
273 MachO::dysymtab_command DySymTab = MachOObj.getDysymtabLoadCommand();
Seiya Nuta1e589f62019-10-30 15:12:17 +0900274 constexpr uint32_t AbsOrLocalMask =
275 MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS;
276 for (uint32_t i = 0; i < DySymTab.nindirectsyms; ++i) {
277 uint32_t Index = MachOObj.getIndirectSymbolTableEntry(DySymTab, i);
278 if ((Index & AbsOrLocalMask) != 0)
279 O.IndirectSymTable.Symbols.emplace_back(Index, None);
280 else
281 O.IndirectSymTable.Symbols.emplace_back(
282 Index, O.SymTable.getSymbolByIndex(Index));
283 }
Seiya Nuta552bcb82019-08-19 21:05:31 +0000284}
285
Alexander Shaposhnikov842a8cc2020-05-26 16:49:56 -0700286void MachOReader::readSwiftVersion(Object &O) const {
287 struct ObjCImageInfo {
288 uint32_t Version;
289 uint32_t Flags;
290 } ImageInfo;
291
292 for (const LoadCommand &LC : O.LoadCommands)
293 for (const std::unique_ptr<Section> &Sec : LC.Sections)
294 if (Sec->Sectname == "__objc_imageinfo" &&
295 (Sec->Segname == "__DATA" || Sec->Segname == "__DATA_CONST" ||
296 Sec->Segname == "__DATA_DIRTY") &&
297 Sec->Content.size() >= sizeof(ObjCImageInfo)) {
298 memcpy(&ImageInfo, Sec->Content.data(), sizeof(ObjCImageInfo));
299 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) {
300 sys::swapByteOrder(ImageInfo.Version);
301 sys::swapByteOrder(ImageInfo.Flags);
302 }
303 O.SwiftVersion = (ImageInfo.Flags >> 8) & 0xff;
304 return;
305 }
306}
307
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000308std::unique_ptr<Object> MachOReader::create() const {
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000309 auto Obj = std::make_unique<Object>();
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000310 readHeader(*Obj);
311 readLoadCommands(*Obj);
312 readSymbolTable(*Obj);
Seiya Nutaf923d9b2019-06-21 00:21:50 +0000313 setSymbolInRelocationInfo(*Obj);
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000314 readRebaseInfo(*Obj);
315 readBindInfo(*Obj);
316 readWeakBindInfo(*Obj);
317 readLazyBindInfo(*Obj);
318 readExportInfo(*Obj);
Seiya Nuta552bcb82019-08-19 21:05:31 +0000319 readDataInCodeData(*Obj);
320 readFunctionStartsData(*Obj);
321 readIndirectSymbolTable(*Obj);
Alexander Shaposhnikov842a8cc2020-05-26 16:49:56 -0700322 readSwiftVersion(*Obj);
Alexander Shaposhnikovd911ed12019-02-02 00:38:07 +0000323 return Obj;
324}
325
326} // end namespace macho
327} // end namespace objcopy
328} // end namespace llvm