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