[yaml2obj/obj2yaml] - Add support for .stack_sizes sections.
[llvm-complete.git] / tools / llvm-objcopy / MachO / MachOReader.cpp
blobb48a0d8952d0a97ca8e879da6340e91c2255fd7e
1 //===- MachOReader.cpp ------------------------------------------*- C++ -*-===//
2 //
3 // 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
6 //
7 //===----------------------------------------------------------------------===//
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>
16 namespace llvm {
17 namespace objcopy {
18 namespace macho {
20 void 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;
30 template <typename SectionType>
31 Section constructSectionCommon(SectionType Sec) {
32 Section S;
33 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();
38 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;
51 template <typename SectionType> Section constructSection(SectionType Sec);
53 template <> Section constructSection(MachO::section Sec) {
54 return constructSectionCommon(Sec);
57 template <> Section constructSection(MachO::section_64 Sec) {
58 Section S = constructSectionCommon(Sec);
59 S.Reserved3 = Sec.reserved3;
60 return S;
63 // TODO: get rid of reportError and make MachOReader return Expected<> instead.
64 template <typename SectionType, typename SegmentType>
65 std::vector<Section>
66 extractSections(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));
83 Section &S = Sections.back();
85 Expected<object::SectionRef> SecRef =
86 MachOObj.getSection(NextSectionIndex++);
87 if (!SecRef)
88 reportError(MachOObj.getFileName(), SecRef.takeError());
90 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());
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 RelocationInfo R;
102 R.Symbol = nullptr; // We'll fill this field later.
103 R.Info = MachOObj.getRelocation(RI->getRawDataRefImpl());
104 R.Scattered = MachOObj.isRelocationScattered(R.Info);
105 S.Relocations.push_back(R);
108 assert(S.NReloc == S.Relocations.size() &&
109 "Incorrect number of relocations");
111 return Sections;
114 void MachOReader::readLoadCommands(Object &O) const {
115 // For MachO sections indices start from 1.
116 size_t NextSectionIndex = 1;
117 for (auto LoadCmd : MachOObj.load_commands()) {
118 LoadCommand LC;
119 switch (LoadCmd.C.cmd) {
120 case MachO::LC_SEGMENT:
121 LC.Sections = extractSections<MachO::section, MachO::segment_command>(
122 LoadCmd, MachOObj, NextSectionIndex);
123 break;
124 case MachO::LC_SEGMENT_64:
125 LC.Sections =
126 extractSections<MachO::section_64, MachO::segment_command_64>(
127 LoadCmd, MachOObj, NextSectionIndex);
128 break;
129 case MachO::LC_SYMTAB:
130 O.SymTabCommandIndex = O.LoadCommands.size();
131 break;
132 case MachO::LC_DYSYMTAB:
133 O.DySymTabCommandIndex = O.LoadCommands.size();
134 break;
135 case MachO::LC_DYLD_INFO:
136 case MachO::LC_DYLD_INFO_ONLY:
137 O.DyLdInfoCommandIndex = O.LoadCommands.size();
138 break;
139 case MachO::LC_DATA_IN_CODE:
140 O.DataInCodeCommandIndex = O.LoadCommands.size();
141 break;
142 case MachO::LC_FUNCTION_STARTS:
143 O.FunctionStartsCommandIndex = O.LoadCommands.size();
144 break;
146 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
147 case MachO::LCName: \
148 memcpy((void *)&(LC.MachOLoadCommand.LCStruct##_data), LoadCmd.Ptr, \
149 sizeof(MachO::LCStruct)); \
150 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) \
151 MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data); \
152 LC.Payload = ArrayRef<uint8_t>( \
153 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \
154 sizeof(MachO::LCStruct), \
155 LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \
156 break;
158 switch (LoadCmd.C.cmd) {
159 default:
160 memcpy((void *)&(LC.MachOLoadCommand.load_command_data), LoadCmd.Ptr,
161 sizeof(MachO::load_command));
162 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost)
163 MachO::swapStruct(LC.MachOLoadCommand.load_command_data);
164 LC.Payload = ArrayRef<uint8_t>(
165 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) +
166 sizeof(MachO::load_command),
167 LoadCmd.C.cmdsize - sizeof(MachO::load_command));
168 break;
169 #include "llvm/BinaryFormat/MachO.def"
171 O.LoadCommands.push_back(std::move(LC));
175 template <typename nlist_t>
176 SymbolEntry constructSymbolEntry(StringRef StrTable, const nlist_t &nlist) {
177 assert(nlist.n_strx < StrTable.size() &&
178 "n_strx exceeds the size of the string table");
179 SymbolEntry SE;
180 SE.Name = StringRef(StrTable.data() + nlist.n_strx).str();
181 SE.n_type = nlist.n_type;
182 SE.n_sect = nlist.n_sect;
183 SE.n_desc = nlist.n_desc;
184 SE.n_value = nlist.n_value;
185 return SE;
188 void MachOReader::readSymbolTable(Object &O) const {
189 StringRef StrTable = MachOObj.getStringTableData();
190 for (auto Symbol : MachOObj.symbols()) {
191 SymbolEntry SE =
192 (MachOObj.is64Bit()
193 ? constructSymbolEntry(
194 StrTable,
195 MachOObj.getSymbol64TableEntry(Symbol.getRawDataRefImpl()))
196 : constructSymbolEntry(
197 StrTable,
198 MachOObj.getSymbolTableEntry(Symbol.getRawDataRefImpl())));
200 O.SymTable.Symbols.push_back(std::make_unique<SymbolEntry>(SE));
204 void MachOReader::setSymbolInRelocationInfo(Object &O) const {
205 for (auto &LC : O.LoadCommands)
206 for (auto &Sec : LC.Sections)
207 for (auto &Reloc : Sec.Relocations)
208 if (!Reloc.Scattered) {
209 auto *Info = reinterpret_cast<MachO::relocation_info *>(&Reloc.Info);
210 Reloc.Symbol = O.SymTable.getSymbolByIndex(Info->r_symbolnum);
214 void MachOReader::readRebaseInfo(Object &O) const {
215 O.Rebases.Opcodes = MachOObj.getDyldInfoRebaseOpcodes();
218 void MachOReader::readBindInfo(Object &O) const {
219 O.Binds.Opcodes = MachOObj.getDyldInfoBindOpcodes();
222 void MachOReader::readWeakBindInfo(Object &O) const {
223 O.WeakBinds.Opcodes = MachOObj.getDyldInfoWeakBindOpcodes();
226 void MachOReader::readLazyBindInfo(Object &O) const {
227 O.LazyBinds.Opcodes = MachOObj.getDyldInfoLazyBindOpcodes();
230 void MachOReader::readExportInfo(Object &O) const {
231 O.Exports.Trie = MachOObj.getDyldInfoExportsTrie();
234 void MachOReader::readDataInCodeData(Object &O) const {
235 if (!O.DataInCodeCommandIndex)
236 return;
237 const MachO::linkedit_data_command &LDC =
238 O.LoadCommands[*O.DataInCodeCommandIndex]
239 .MachOLoadCommand.linkedit_data_command_data;
241 O.DataInCode.Data = arrayRefFromStringRef(
242 MachOObj.getData().substr(LDC.dataoff, LDC.datasize));
245 void MachOReader::readFunctionStartsData(Object &O) const {
246 if (!O.FunctionStartsCommandIndex)
247 return;
248 const MachO::linkedit_data_command &LDC =
249 O.LoadCommands[*O.FunctionStartsCommandIndex]
250 .MachOLoadCommand.linkedit_data_command_data;
252 O.FunctionStarts.Data = arrayRefFromStringRef(
253 MachOObj.getData().substr(LDC.dataoff, LDC.datasize));
256 void MachOReader::readIndirectSymbolTable(Object &O) const {
257 MachO::dysymtab_command DySymTab = MachOObj.getDysymtabLoadCommand();
258 for (uint32_t i = 0; i < DySymTab.nindirectsyms; ++i)
259 O.IndirectSymTable.Symbols.push_back(
260 MachOObj.getIndirectSymbolTableEntry(DySymTab, i));
263 std::unique_ptr<Object> MachOReader::create() const {
264 auto Obj = std::make_unique<Object>();
265 readHeader(*Obj);
266 readLoadCommands(*Obj);
267 readSymbolTable(*Obj);
268 setSymbolInRelocationInfo(*Obj);
269 readRebaseInfo(*Obj);
270 readBindInfo(*Obj);
271 readWeakBindInfo(*Obj);
272 readLazyBindInfo(*Obj);
273 readExportInfo(*Obj);
274 readDataInCodeData(*Obj);
275 readFunctionStartsData(*Obj);
276 readIndirectSymbolTable(*Obj);
277 return Obj;
280 } // end namespace macho
281 } // end namespace objcopy
282 } // end namespace llvm