]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm-project / llvm / tools / llvm-objcopy / MachO / MachOReader.cpp
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 //===----------------------------------------------------------------------===//
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
16 namespace llvm {
17 namespace objcopy {
18 namespace macho {
19
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;
28 }
29
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;
49 }
50
51 template <typename SectionType> Section constructSection(SectionType Sec);
52
53 template <> Section constructSection(MachO::section Sec) {
54   return constructSectionCommon(Sec);
55 }
56
57 template <> Section constructSection(MachO::section_64 Sec) {
58   Section S = constructSectionCommon(Sec);
59   S.Reserved3 = Sec.reserved3;
60   return S;
61 }
62
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));
81     }
82
83     Section &S = Sections.back();
84
85     Expected<object::SectionRef> SecRef =
86         MachOObj.getSection(NextSectionIndex++);
87     if (!SecRef)
88       reportError(MachOObj.getFileName(), SecRef.takeError());
89
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());
96
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);
106     }
107
108     assert(S.NReloc == S.Relocations.size() &&
109            "Incorrect number of relocations");
110   }
111   return Sections;
112 }
113
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_DYLD_INFO:
133     case MachO::LC_DYLD_INFO_ONLY:
134       O.DyLdInfoCommandIndex = O.LoadCommands.size();
135       break;
136     }
137 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct)                         \
138   case MachO::LCName:                                                          \
139     memcpy((void *)&(LC.MachOLoadCommand.LCStruct##_data), LoadCmd.Ptr,        \
140            sizeof(MachO::LCStruct));                                           \
141     if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost)                  \
142       MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data);                  \
143     LC.Payload = ArrayRef<uint8_t>(                                            \
144         reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) +         \
145             sizeof(MachO::LCStruct),                                           \
146         LoadCmd.C.cmdsize - sizeof(MachO::LCStruct));                          \
147     break;
148
149     switch (LoadCmd.C.cmd) {
150     default:
151       memcpy((void *)&(LC.MachOLoadCommand.load_command_data), LoadCmd.Ptr,
152              sizeof(MachO::load_command));
153       if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost)
154         MachO::swapStruct(LC.MachOLoadCommand.load_command_data);
155       LC.Payload = ArrayRef<uint8_t>(
156           reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) +
157               sizeof(MachO::load_command),
158           LoadCmd.C.cmdsize - sizeof(MachO::load_command));
159       break;
160 #include "llvm/BinaryFormat/MachO.def"
161     }
162     O.LoadCommands.push_back(std::move(LC));
163   }
164 }
165
166 template <typename nlist_t>
167 SymbolEntry constructSymbolEntry(StringRef StrTable, const nlist_t &nlist) {
168   assert(nlist.n_strx < StrTable.size() &&
169          "n_strx exceeds the size of the string table");
170   SymbolEntry SE;
171   SE.Name = StringRef(StrTable.data() + nlist.n_strx).str();
172   SE.n_type = nlist.n_type;
173   SE.n_sect = nlist.n_sect;
174   SE.n_desc = nlist.n_desc;
175   SE.n_value = nlist.n_value;
176   return SE;
177 }
178
179 void MachOReader::readSymbolTable(Object &O) const {
180   StringRef StrTable = MachOObj.getStringTableData();
181   for (auto Symbol : MachOObj.symbols()) {
182     SymbolEntry SE =
183         (MachOObj.is64Bit()
184              ? constructSymbolEntry(
185                    StrTable,
186                    MachOObj.getSymbol64TableEntry(Symbol.getRawDataRefImpl()))
187              : constructSymbolEntry(
188                    StrTable,
189                    MachOObj.getSymbolTableEntry(Symbol.getRawDataRefImpl())));
190
191     O.SymTable.Symbols.push_back(llvm::make_unique<SymbolEntry>(SE));
192   }
193 }
194
195 void MachOReader::setSymbolInRelocationInfo(Object &O) const {
196   for (auto &LC : O.LoadCommands)
197     for (auto &Sec : LC.Sections)
198       for (auto &Reloc : Sec.Relocations)
199         if (!Reloc.Scattered) {
200           auto *Info = reinterpret_cast<MachO::relocation_info *>(&Reloc.Info);
201           Reloc.Symbol = O.SymTable.getSymbolByIndex(Info->r_symbolnum);
202         }
203 }
204
205 void MachOReader::readRebaseInfo(Object &O) const {
206   O.Rebases.Opcodes = MachOObj.getDyldInfoRebaseOpcodes();
207 }
208
209 void MachOReader::readBindInfo(Object &O) const {
210   O.Binds.Opcodes = MachOObj.getDyldInfoBindOpcodes();
211 }
212
213 void MachOReader::readWeakBindInfo(Object &O) const {
214   O.WeakBinds.Opcodes = MachOObj.getDyldInfoWeakBindOpcodes();
215 }
216
217 void MachOReader::readLazyBindInfo(Object &O) const {
218   O.LazyBinds.Opcodes = MachOObj.getDyldInfoLazyBindOpcodes();
219 }
220
221 void MachOReader::readExportInfo(Object &O) const {
222   O.Exports.Trie = MachOObj.getDyldInfoExportsTrie();
223 }
224
225 std::unique_ptr<Object> MachOReader::create() const {
226   auto Obj = llvm::make_unique<Object>();
227   readHeader(*Obj);
228   readLoadCommands(*Obj);
229   readSymbolTable(*Obj);
230   setSymbolInRelocationInfo(*Obj);
231   readRebaseInfo(*Obj);
232   readBindInfo(*Obj);
233   readWeakBindInfo(*Obj);
234   readLazyBindInfo(*Obj);
235   readExportInfo(*Obj);
236   return Obj;
237 }
238
239 } // end namespace macho
240 } // end namespace objcopy
241 } // end namespace llvm