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