1 | //===- MachOObjectFile.cpp - Mach-O object file binding -------------------===// |
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 | // This file defines the MachOObjectFile class, which binds the MachOObject |
10 | // class to the generic ObjectFile wrapper. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "llvm/ADT/ArrayRef.h" |
15 | #include "llvm/ADT/STLExtras.h" |
16 | #include "llvm/ADT/SmallVector.h" |
17 | #include "llvm/ADT/StringRef.h" |
18 | #include "llvm/ADT/StringSwitch.h" |
19 | #include "llvm/ADT/Twine.h" |
20 | #include "llvm/ADT/bit.h" |
21 | #include "llvm/BinaryFormat/MachO.h" |
22 | #include "llvm/BinaryFormat/Swift.h" |
23 | #include "llvm/Object/Error.h" |
24 | #include "llvm/Object/MachO.h" |
25 | #include "llvm/Object/ObjectFile.h" |
26 | #include "llvm/Object/SymbolicFile.h" |
27 | #include "llvm/Support/DataExtractor.h" |
28 | #include "llvm/Support/Debug.h" |
29 | #include "llvm/Support/Errc.h" |
30 | #include "llvm/Support/Error.h" |
31 | #include "llvm/Support/ErrorHandling.h" |
32 | #include "llvm/Support/FileSystem.h" |
33 | #include "llvm/Support/Format.h" |
34 | #include "llvm/Support/LEB128.h" |
35 | #include "llvm/Support/MemoryBufferRef.h" |
36 | #include "llvm/Support/Path.h" |
37 | #include "llvm/Support/SwapByteOrder.h" |
38 | #include "llvm/Support/raw_ostream.h" |
39 | #include "llvm/TargetParser/Host.h" |
40 | #include "llvm/TargetParser/Triple.h" |
41 | #include <algorithm> |
42 | #include <cassert> |
43 | #include <cstddef> |
44 | #include <cstdint> |
45 | #include <cstring> |
46 | #include <limits> |
47 | #include <list> |
48 | #include <memory> |
49 | #include <system_error> |
50 | |
51 | using namespace llvm; |
52 | using namespace object; |
53 | |
54 | namespace { |
55 | |
56 | struct section_base { |
57 | char sectname[16]; |
58 | char segname[16]; |
59 | }; |
60 | |
61 | } // end anonymous namespace |
62 | |
63 | static Error malformedError(const Twine &Msg) { |
64 | return make_error<GenericBinaryError>(Args: "truncated or malformed object (" + |
65 | Msg + ")" , |
66 | Args: object_error::parse_failed); |
67 | } |
68 | |
69 | // FIXME: Replace all uses of this function with getStructOrErr. |
70 | template <typename T> |
71 | static T getStruct(const MachOObjectFile &O, const char *P) { |
72 | // Don't read before the beginning or past the end of the file |
73 | if (P < O.getData().begin() || P + sizeof(T) > O.getData().end()) |
74 | report_fatal_error(reason: "Malformed MachO file." ); |
75 | |
76 | T Cmd; |
77 | memcpy(&Cmd, P, sizeof(T)); |
78 | if (O.isLittleEndian() != sys::IsLittleEndianHost) |
79 | MachO::swapStruct(Cmd); |
80 | return Cmd; |
81 | } |
82 | |
83 | template <typename T> |
84 | static Expected<T> getStructOrErr(const MachOObjectFile &O, const char *P) { |
85 | // Don't read before the beginning or past the end of the file |
86 | if (P < O.getData().begin() || P + sizeof(T) > O.getData().end()) |
87 | return malformedError(Msg: "Structure read out-of-range" ); |
88 | |
89 | T Cmd; |
90 | memcpy(&Cmd, P, sizeof(T)); |
91 | if (O.isLittleEndian() != sys::IsLittleEndianHost) |
92 | MachO::swapStruct(Cmd); |
93 | return Cmd; |
94 | } |
95 | |
96 | static const char * |
97 | getSectionPtr(const MachOObjectFile &O, MachOObjectFile::LoadCommandInfo L, |
98 | unsigned Sec) { |
99 | uintptr_t CommandAddr = reinterpret_cast<uintptr_t>(L.Ptr); |
100 | |
101 | bool Is64 = O.is64Bit(); |
102 | unsigned SegmentLoadSize = Is64 ? sizeof(MachO::segment_command_64) : |
103 | sizeof(MachO::segment_command); |
104 | unsigned SectionSize = Is64 ? sizeof(MachO::section_64) : |
105 | sizeof(MachO::section); |
106 | |
107 | uintptr_t SectionAddr = CommandAddr + SegmentLoadSize + Sec * SectionSize; |
108 | return reinterpret_cast<const char*>(SectionAddr); |
109 | } |
110 | |
111 | static const char *getPtr(const MachOObjectFile &O, size_t Offset, |
112 | size_t MachOFilesetEntryOffset = 0) { |
113 | assert(Offset <= O.getData().size() && |
114 | MachOFilesetEntryOffset <= O.getData().size()); |
115 | return O.getData().data() + Offset + MachOFilesetEntryOffset; |
116 | } |
117 | |
118 | static MachO::nlist_base |
119 | getSymbolTableEntryBase(const MachOObjectFile &O, DataRefImpl DRI) { |
120 | const char *P = reinterpret_cast<const char *>(DRI.p); |
121 | return getStruct<MachO::nlist_base>(O, P); |
122 | } |
123 | |
124 | static StringRef parseSegmentOrSectionName(const char *P) { |
125 | if (P[15] == 0) |
126 | // Null terminated. |
127 | return P; |
128 | // Not null terminated, so this is a 16 char string. |
129 | return StringRef(P, 16); |
130 | } |
131 | |
132 | static unsigned getCPUType(const MachOObjectFile &O) { |
133 | return O.getHeader().cputype; |
134 | } |
135 | |
136 | static unsigned getCPUSubType(const MachOObjectFile &O) { |
137 | return O.getHeader().cpusubtype; |
138 | } |
139 | |
140 | static uint32_t |
141 | getPlainRelocationAddress(const MachO::any_relocation_info &RE) { |
142 | return RE.r_word0; |
143 | } |
144 | |
145 | static unsigned |
146 | getScatteredRelocationAddress(const MachO::any_relocation_info &RE) { |
147 | return RE.r_word0 & 0xffffff; |
148 | } |
149 | |
150 | static bool getPlainRelocationPCRel(const MachOObjectFile &O, |
151 | const MachO::any_relocation_info &RE) { |
152 | if (O.isLittleEndian()) |
153 | return (RE.r_word1 >> 24) & 1; |
154 | return (RE.r_word1 >> 7) & 1; |
155 | } |
156 | |
157 | static bool |
158 | getScatteredRelocationPCRel(const MachO::any_relocation_info &RE) { |
159 | return (RE.r_word0 >> 30) & 1; |
160 | } |
161 | |
162 | static unsigned getPlainRelocationLength(const MachOObjectFile &O, |
163 | const MachO::any_relocation_info &RE) { |
164 | if (O.isLittleEndian()) |
165 | return (RE.r_word1 >> 25) & 3; |
166 | return (RE.r_word1 >> 5) & 3; |
167 | } |
168 | |
169 | static unsigned |
170 | getScatteredRelocationLength(const MachO::any_relocation_info &RE) { |
171 | return (RE.r_word0 >> 28) & 3; |
172 | } |
173 | |
174 | static unsigned getPlainRelocationType(const MachOObjectFile &O, |
175 | const MachO::any_relocation_info &RE) { |
176 | if (O.isLittleEndian()) |
177 | return RE.r_word1 >> 28; |
178 | return RE.r_word1 & 0xf; |
179 | } |
180 | |
181 | static uint32_t getSectionFlags(const MachOObjectFile &O, |
182 | DataRefImpl Sec) { |
183 | if (O.is64Bit()) { |
184 | MachO::section_64 Sect = O.getSection64(DRI: Sec); |
185 | return Sect.flags; |
186 | } |
187 | MachO::section Sect = O.getSection(DRI: Sec); |
188 | return Sect.flags; |
189 | } |
190 | |
191 | static Expected<MachOObjectFile::LoadCommandInfo> |
192 | getLoadCommandInfo(const MachOObjectFile &Obj, const char *Ptr, |
193 | uint32_t LoadCommandIndex) { |
194 | if (auto CmdOrErr = getStructOrErr<MachO::load_command>(O: Obj, P: Ptr)) { |
195 | if (CmdOrErr->cmdsize + Ptr > Obj.getData().end()) |
196 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
197 | " extends past end of file" ); |
198 | if (CmdOrErr->cmdsize < 8) |
199 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
200 | " with size less than 8 bytes" ); |
201 | return MachOObjectFile::LoadCommandInfo({.Ptr: Ptr, .C: *CmdOrErr}); |
202 | } else |
203 | return CmdOrErr.takeError(); |
204 | } |
205 | |
206 | static Expected<MachOObjectFile::LoadCommandInfo> |
207 | getFirstLoadCommandInfo(const MachOObjectFile &Obj) { |
208 | unsigned = Obj.is64Bit() ? sizeof(MachO::mach_header_64) |
209 | : sizeof(MachO::mach_header); |
210 | if (sizeof(MachO::load_command) > Obj.getHeader().sizeofcmds) |
211 | return malformedError(Msg: "load command 0 extends past the end all load " |
212 | "commands in the file" ); |
213 | return getLoadCommandInfo( |
214 | Obj, Ptr: getPtr(O: Obj, Offset: HeaderSize, MachOFilesetEntryOffset: Obj.getMachOFilesetEntryOffset()), LoadCommandIndex: 0); |
215 | } |
216 | |
217 | static Expected<MachOObjectFile::LoadCommandInfo> |
218 | getNextLoadCommandInfo(const MachOObjectFile &Obj, uint32_t LoadCommandIndex, |
219 | const MachOObjectFile::LoadCommandInfo &L) { |
220 | unsigned = Obj.is64Bit() ? sizeof(MachO::mach_header_64) |
221 | : sizeof(MachO::mach_header); |
222 | if (L.Ptr + L.C.cmdsize + sizeof(MachO::load_command) > |
223 | Obj.getData().data() + Obj.getMachOFilesetEntryOffset() + HeaderSize + |
224 | Obj.getHeader().sizeofcmds) |
225 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex + 1) + |
226 | " extends past the end all load commands in the file" ); |
227 | return getLoadCommandInfo(Obj, Ptr: L.Ptr + L.C.cmdsize, LoadCommandIndex: LoadCommandIndex + 1); |
228 | } |
229 | |
230 | template <typename T> |
231 | static void (const MachOObjectFile &Obj, T &, |
232 | Error &Err) { |
233 | if (sizeof(T) > Obj.getData().size()) { |
234 | Err = malformedError(Msg: "the mach header extends past the end of the " |
235 | "file" ); |
236 | return; |
237 | } |
238 | if (auto = getStructOrErr<T>( |
239 | Obj, getPtr(O: Obj, Offset: 0, MachOFilesetEntryOffset: Obj.getMachOFilesetEntryOffset()))) |
240 | Header = *HeaderOrErr; |
241 | else |
242 | Err = HeaderOrErr.takeError(); |
243 | } |
244 | |
245 | // This is used to check for overlapping of Mach-O elements. |
246 | struct MachOElement { |
247 | uint64_t Offset; |
248 | uint64_t Size; |
249 | const char *Name; |
250 | }; |
251 | |
252 | static Error checkOverlappingElement(std::list<MachOElement> &Elements, |
253 | uint64_t Offset, uint64_t Size, |
254 | const char *Name) { |
255 | if (Size == 0) |
256 | return Error::success(); |
257 | |
258 | for (auto it = Elements.begin(); it != Elements.end(); ++it) { |
259 | const auto &E = *it; |
260 | if ((Offset >= E.Offset && Offset < E.Offset + E.Size) || |
261 | (Offset + Size > E.Offset && Offset + Size < E.Offset + E.Size) || |
262 | (Offset <= E.Offset && Offset + Size >= E.Offset + E.Size)) |
263 | return malformedError(Msg: Twine(Name) + " at offset " + Twine(Offset) + |
264 | " with a size of " + Twine(Size) + ", overlaps " + |
265 | E.Name + " at offset " + Twine(E.Offset) + " with " |
266 | "a size of " + Twine(E.Size)); |
267 | auto nt = it; |
268 | nt++; |
269 | if (nt != Elements.end()) { |
270 | const auto &N = *nt; |
271 | if (Offset + Size <= N.Offset) { |
272 | Elements.insert(position: nt, x: {.Offset: Offset, .Size: Size, .Name: Name}); |
273 | return Error::success(); |
274 | } |
275 | } |
276 | } |
277 | Elements.push_back(x: {.Offset: Offset, .Size: Size, .Name: Name}); |
278 | return Error::success(); |
279 | } |
280 | |
281 | // Parses LC_SEGMENT or LC_SEGMENT_64 load command, adds addresses of all |
282 | // sections to \param Sections, and optionally sets |
283 | // \param IsPageZeroSegment to true. |
284 | template <typename Segment, typename Section> |
285 | static Error parseSegmentLoadCommand( |
286 | const MachOObjectFile &Obj, const MachOObjectFile::LoadCommandInfo &Load, |
287 | SmallVectorImpl<const char *> &Sections, bool &IsPageZeroSegment, |
288 | uint32_t LoadCommandIndex, const char *CmdName, uint64_t , |
289 | std::list<MachOElement> &Elements) { |
290 | const unsigned SegmentLoadSize = sizeof(Segment); |
291 | if (Load.C.cmdsize < SegmentLoadSize) |
292 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
293 | " " + CmdName + " cmdsize too small" ); |
294 | if (auto SegOrErr = getStructOrErr<Segment>(Obj, Load.Ptr)) { |
295 | Segment S = SegOrErr.get(); |
296 | const unsigned SectionSize = sizeof(Section); |
297 | uint64_t FileSize = Obj.getData().size(); |
298 | if (S.nsects > std::numeric_limits<uint32_t>::max() / SectionSize || |
299 | S.nsects * SectionSize > Load.C.cmdsize - SegmentLoadSize) |
300 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
301 | " inconsistent cmdsize in " + CmdName + |
302 | " for the number of sections" ); |
303 | for (unsigned J = 0; J < S.nsects; ++J) { |
304 | const char *Sec = getSectionPtr(O: Obj, L: Load, Sec: J); |
305 | Sections.push_back(Elt: Sec); |
306 | auto SectionOrErr = getStructOrErr<Section>(Obj, Sec); |
307 | if (!SectionOrErr) |
308 | return SectionOrErr.takeError(); |
309 | Section s = SectionOrErr.get(); |
310 | if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB && |
311 | Obj.getHeader().filetype != MachO::MH_DSYM && |
312 | s.flags != MachO::S_ZEROFILL && |
313 | s.flags != MachO::S_THREAD_LOCAL_ZEROFILL && |
314 | s.offset > FileSize) |
315 | return malformedError(Msg: "offset field of section " + Twine(J) + " in " + |
316 | CmdName + " command " + Twine(LoadCommandIndex) + |
317 | " extends past the end of the file" ); |
318 | if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB && |
319 | Obj.getHeader().filetype != MachO::MH_DSYM && |
320 | s.flags != MachO::S_ZEROFILL && |
321 | s.flags != MachO::S_THREAD_LOCAL_ZEROFILL && S.fileoff == 0 && |
322 | s.offset < SizeOfHeaders && s.size != 0) |
323 | return malformedError(Msg: "offset field of section " + Twine(J) + " in " + |
324 | CmdName + " command " + Twine(LoadCommandIndex) + |
325 | " not past the headers of the file" ); |
326 | uint64_t BigSize = s.offset; |
327 | BigSize += s.size; |
328 | if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB && |
329 | Obj.getHeader().filetype != MachO::MH_DSYM && |
330 | s.flags != MachO::S_ZEROFILL && |
331 | s.flags != MachO::S_THREAD_LOCAL_ZEROFILL && |
332 | BigSize > FileSize) |
333 | return malformedError(Msg: "offset field plus size field of section " + |
334 | Twine(J) + " in " + CmdName + " command " + |
335 | Twine(LoadCommandIndex) + |
336 | " extends past the end of the file" ); |
337 | if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB && |
338 | Obj.getHeader().filetype != MachO::MH_DSYM && |
339 | s.flags != MachO::S_ZEROFILL && |
340 | s.flags != MachO::S_THREAD_LOCAL_ZEROFILL && |
341 | s.size > S.filesize) |
342 | return malformedError(Msg: "size field of section " + |
343 | Twine(J) + " in " + CmdName + " command " + |
344 | Twine(LoadCommandIndex) + |
345 | " greater than the segment" ); |
346 | if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB && |
347 | Obj.getHeader().filetype != MachO::MH_DSYM && s.size != 0 && |
348 | s.addr < S.vmaddr) |
349 | return malformedError(Msg: "addr field of section " + Twine(J) + " in " + |
350 | CmdName + " command " + Twine(LoadCommandIndex) + |
351 | " less than the segment's vmaddr" ); |
352 | BigSize = s.addr; |
353 | BigSize += s.size; |
354 | uint64_t BigEnd = S.vmaddr; |
355 | BigEnd += S.vmsize; |
356 | if (S.vmsize != 0 && s.size != 0 && BigSize > BigEnd) |
357 | return malformedError(Msg: "addr field plus size of section " + Twine(J) + |
358 | " in " + CmdName + " command " + |
359 | Twine(LoadCommandIndex) + |
360 | " greater than than " |
361 | "the segment's vmaddr plus vmsize" ); |
362 | if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB && |
363 | Obj.getHeader().filetype != MachO::MH_DSYM && |
364 | s.flags != MachO::S_ZEROFILL && |
365 | s.flags != MachO::S_THREAD_LOCAL_ZEROFILL) |
366 | if (Error Err = checkOverlappingElement(Elements, s.offset, s.size, |
367 | "section contents" )) |
368 | return Err; |
369 | if (s.reloff > FileSize) |
370 | return malformedError(Msg: "reloff field of section " + Twine(J) + " in " + |
371 | CmdName + " command " + Twine(LoadCommandIndex) + |
372 | " extends past the end of the file" ); |
373 | BigSize = s.nreloc; |
374 | BigSize *= sizeof(struct MachO::relocation_info); |
375 | BigSize += s.reloff; |
376 | if (BigSize > FileSize) |
377 | return malformedError(Msg: "reloff field plus nreloc field times sizeof(" |
378 | "struct relocation_info) of section " + |
379 | Twine(J) + " in " + CmdName + " command " + |
380 | Twine(LoadCommandIndex) + |
381 | " extends past the end of the file" ); |
382 | if (Error Err = checkOverlappingElement(Elements, s.reloff, s.nreloc * |
383 | sizeof(struct |
384 | MachO::relocation_info), |
385 | "section relocation entries" )) |
386 | return Err; |
387 | } |
388 | if (S.fileoff > FileSize) |
389 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
390 | " fileoff field in " + CmdName + |
391 | " extends past the end of the file" ); |
392 | uint64_t BigSize = S.fileoff; |
393 | BigSize += S.filesize; |
394 | if (BigSize > FileSize) |
395 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
396 | " fileoff field plus filesize field in " + |
397 | CmdName + " extends past the end of the file" ); |
398 | if (S.vmsize != 0 && S.filesize > S.vmsize) |
399 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
400 | " filesize field in " + CmdName + |
401 | " greater than vmsize field" ); |
402 | IsPageZeroSegment |= StringRef("__PAGEZERO" ) == S.segname; |
403 | } else |
404 | return SegOrErr.takeError(); |
405 | |
406 | return Error::success(); |
407 | } |
408 | |
409 | static Error checkSymtabCommand(const MachOObjectFile &Obj, |
410 | const MachOObjectFile::LoadCommandInfo &Load, |
411 | uint32_t LoadCommandIndex, |
412 | const char **SymtabLoadCmd, |
413 | std::list<MachOElement> &Elements) { |
414 | if (Load.C.cmdsize < sizeof(MachO::symtab_command)) |
415 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
416 | " LC_SYMTAB cmdsize too small" ); |
417 | if (*SymtabLoadCmd != nullptr) |
418 | return malformedError(Msg: "more than one LC_SYMTAB command" ); |
419 | auto SymtabOrErr = getStructOrErr<MachO::symtab_command>(O: Obj, P: Load.Ptr); |
420 | if (!SymtabOrErr) |
421 | return SymtabOrErr.takeError(); |
422 | MachO::symtab_command Symtab = SymtabOrErr.get(); |
423 | if (Symtab.cmdsize != sizeof(MachO::symtab_command)) |
424 | return malformedError(Msg: "LC_SYMTAB command " + Twine(LoadCommandIndex) + |
425 | " has incorrect cmdsize" ); |
426 | uint64_t FileSize = Obj.getData().size(); |
427 | if (Symtab.symoff > FileSize) |
428 | return malformedError(Msg: "symoff field of LC_SYMTAB command " + |
429 | Twine(LoadCommandIndex) + " extends past the end " |
430 | "of the file" ); |
431 | uint64_t SymtabSize = Symtab.nsyms; |
432 | const char *struct_nlist_name; |
433 | if (Obj.is64Bit()) { |
434 | SymtabSize *= sizeof(MachO::nlist_64); |
435 | struct_nlist_name = "struct nlist_64" ; |
436 | } else { |
437 | SymtabSize *= sizeof(MachO::nlist); |
438 | struct_nlist_name = "struct nlist" ; |
439 | } |
440 | uint64_t BigSize = SymtabSize; |
441 | BigSize += Symtab.symoff; |
442 | if (BigSize > FileSize) |
443 | return malformedError(Msg: "symoff field plus nsyms field times sizeof(" + |
444 | Twine(struct_nlist_name) + ") of LC_SYMTAB command " + |
445 | Twine(LoadCommandIndex) + " extends past the end " |
446 | "of the file" ); |
447 | if (Error Err = checkOverlappingElement(Elements, Offset: Symtab.symoff, Size: SymtabSize, |
448 | Name: "symbol table" )) |
449 | return Err; |
450 | if (Symtab.stroff > FileSize) |
451 | return malformedError(Msg: "stroff field of LC_SYMTAB command " + |
452 | Twine(LoadCommandIndex) + " extends past the end " |
453 | "of the file" ); |
454 | BigSize = Symtab.stroff; |
455 | BigSize += Symtab.strsize; |
456 | if (BigSize > FileSize) |
457 | return malformedError(Msg: "stroff field plus strsize field of LC_SYMTAB " |
458 | "command " + Twine(LoadCommandIndex) + " extends " |
459 | "past the end of the file" ); |
460 | if (Error Err = checkOverlappingElement(Elements, Offset: Symtab.stroff, |
461 | Size: Symtab.strsize, Name: "string table" )) |
462 | return Err; |
463 | *SymtabLoadCmd = Load.Ptr; |
464 | return Error::success(); |
465 | } |
466 | |
467 | static Error checkDysymtabCommand(const MachOObjectFile &Obj, |
468 | const MachOObjectFile::LoadCommandInfo &Load, |
469 | uint32_t LoadCommandIndex, |
470 | const char **DysymtabLoadCmd, |
471 | std::list<MachOElement> &Elements) { |
472 | if (Load.C.cmdsize < sizeof(MachO::dysymtab_command)) |
473 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
474 | " LC_DYSYMTAB cmdsize too small" ); |
475 | if (*DysymtabLoadCmd != nullptr) |
476 | return malformedError(Msg: "more than one LC_DYSYMTAB command" ); |
477 | auto DysymtabOrErr = |
478 | getStructOrErr<MachO::dysymtab_command>(O: Obj, P: Load.Ptr); |
479 | if (!DysymtabOrErr) |
480 | return DysymtabOrErr.takeError(); |
481 | MachO::dysymtab_command Dysymtab = DysymtabOrErr.get(); |
482 | if (Dysymtab.cmdsize != sizeof(MachO::dysymtab_command)) |
483 | return malformedError(Msg: "LC_DYSYMTAB command " + Twine(LoadCommandIndex) + |
484 | " has incorrect cmdsize" ); |
485 | uint64_t FileSize = Obj.getData().size(); |
486 | if (Dysymtab.tocoff > FileSize) |
487 | return malformedError(Msg: "tocoff field of LC_DYSYMTAB command " + |
488 | Twine(LoadCommandIndex) + " extends past the end of " |
489 | "the file" ); |
490 | uint64_t BigSize = Dysymtab.ntoc; |
491 | BigSize *= sizeof(MachO::dylib_table_of_contents); |
492 | BigSize += Dysymtab.tocoff; |
493 | if (BigSize > FileSize) |
494 | return malformedError(Msg: "tocoff field plus ntoc field times sizeof(struct " |
495 | "dylib_table_of_contents) of LC_DYSYMTAB command " + |
496 | Twine(LoadCommandIndex) + " extends past the end of " |
497 | "the file" ); |
498 | if (Error Err = checkOverlappingElement(Elements, Offset: Dysymtab.tocoff, |
499 | Size: Dysymtab.ntoc * sizeof(struct |
500 | MachO::dylib_table_of_contents), |
501 | Name: "table of contents" )) |
502 | return Err; |
503 | if (Dysymtab.modtaboff > FileSize) |
504 | return malformedError(Msg: "modtaboff field of LC_DYSYMTAB command " + |
505 | Twine(LoadCommandIndex) + " extends past the end of " |
506 | "the file" ); |
507 | BigSize = Dysymtab.nmodtab; |
508 | const char *struct_dylib_module_name; |
509 | uint64_t sizeof_modtab; |
510 | if (Obj.is64Bit()) { |
511 | sizeof_modtab = sizeof(MachO::dylib_module_64); |
512 | struct_dylib_module_name = "struct dylib_module_64" ; |
513 | } else { |
514 | sizeof_modtab = sizeof(MachO::dylib_module); |
515 | struct_dylib_module_name = "struct dylib_module" ; |
516 | } |
517 | BigSize *= sizeof_modtab; |
518 | BigSize += Dysymtab.modtaboff; |
519 | if (BigSize > FileSize) |
520 | return malformedError(Msg: "modtaboff field plus nmodtab field times sizeof(" + |
521 | Twine(struct_dylib_module_name) + ") of LC_DYSYMTAB " |
522 | "command " + Twine(LoadCommandIndex) + " extends " |
523 | "past the end of the file" ); |
524 | if (Error Err = checkOverlappingElement(Elements, Offset: Dysymtab.modtaboff, |
525 | Size: Dysymtab.nmodtab * sizeof_modtab, |
526 | Name: "module table" )) |
527 | return Err; |
528 | if (Dysymtab.extrefsymoff > FileSize) |
529 | return malformedError(Msg: "extrefsymoff field of LC_DYSYMTAB command " + |
530 | Twine(LoadCommandIndex) + " extends past the end of " |
531 | "the file" ); |
532 | BigSize = Dysymtab.nextrefsyms; |
533 | BigSize *= sizeof(MachO::dylib_reference); |
534 | BigSize += Dysymtab.extrefsymoff; |
535 | if (BigSize > FileSize) |
536 | return malformedError(Msg: "extrefsymoff field plus nextrefsyms field times " |
537 | "sizeof(struct dylib_reference) of LC_DYSYMTAB " |
538 | "command " + Twine(LoadCommandIndex) + " extends " |
539 | "past the end of the file" ); |
540 | if (Error Err = checkOverlappingElement(Elements, Offset: Dysymtab.extrefsymoff, |
541 | Size: Dysymtab.nextrefsyms * |
542 | sizeof(MachO::dylib_reference), |
543 | Name: "reference table" )) |
544 | return Err; |
545 | if (Dysymtab.indirectsymoff > FileSize) |
546 | return malformedError(Msg: "indirectsymoff field of LC_DYSYMTAB command " + |
547 | Twine(LoadCommandIndex) + " extends past the end of " |
548 | "the file" ); |
549 | BigSize = Dysymtab.nindirectsyms; |
550 | BigSize *= sizeof(uint32_t); |
551 | BigSize += Dysymtab.indirectsymoff; |
552 | if (BigSize > FileSize) |
553 | return malformedError(Msg: "indirectsymoff field plus nindirectsyms field times " |
554 | "sizeof(uint32_t) of LC_DYSYMTAB command " + |
555 | Twine(LoadCommandIndex) + " extends past the end of " |
556 | "the file" ); |
557 | if (Error Err = checkOverlappingElement(Elements, Offset: Dysymtab.indirectsymoff, |
558 | Size: Dysymtab.nindirectsyms * |
559 | sizeof(uint32_t), |
560 | Name: "indirect table" )) |
561 | return Err; |
562 | if (Dysymtab.extreloff > FileSize) |
563 | return malformedError(Msg: "extreloff field of LC_DYSYMTAB command " + |
564 | Twine(LoadCommandIndex) + " extends past the end of " |
565 | "the file" ); |
566 | BigSize = Dysymtab.nextrel; |
567 | BigSize *= sizeof(MachO::relocation_info); |
568 | BigSize += Dysymtab.extreloff; |
569 | if (BigSize > FileSize) |
570 | return malformedError(Msg: "extreloff field plus nextrel field times sizeof" |
571 | "(struct relocation_info) of LC_DYSYMTAB command " + |
572 | Twine(LoadCommandIndex) + " extends past the end of " |
573 | "the file" ); |
574 | if (Error Err = checkOverlappingElement(Elements, Offset: Dysymtab.extreloff, |
575 | Size: Dysymtab.nextrel * |
576 | sizeof(MachO::relocation_info), |
577 | Name: "external relocation table" )) |
578 | return Err; |
579 | if (Dysymtab.locreloff > FileSize) |
580 | return malformedError(Msg: "locreloff field of LC_DYSYMTAB command " + |
581 | Twine(LoadCommandIndex) + " extends past the end of " |
582 | "the file" ); |
583 | BigSize = Dysymtab.nlocrel; |
584 | BigSize *= sizeof(MachO::relocation_info); |
585 | BigSize += Dysymtab.locreloff; |
586 | if (BigSize > FileSize) |
587 | return malformedError(Msg: "locreloff field plus nlocrel field times sizeof" |
588 | "(struct relocation_info) of LC_DYSYMTAB command " + |
589 | Twine(LoadCommandIndex) + " extends past the end of " |
590 | "the file" ); |
591 | if (Error Err = checkOverlappingElement(Elements, Offset: Dysymtab.locreloff, |
592 | Size: Dysymtab.nlocrel * |
593 | sizeof(MachO::relocation_info), |
594 | Name: "local relocation table" )) |
595 | return Err; |
596 | *DysymtabLoadCmd = Load.Ptr; |
597 | return Error::success(); |
598 | } |
599 | |
600 | static Error checkLinkeditDataCommand(const MachOObjectFile &Obj, |
601 | const MachOObjectFile::LoadCommandInfo &Load, |
602 | uint32_t LoadCommandIndex, |
603 | const char **LoadCmd, const char *CmdName, |
604 | std::list<MachOElement> &Elements, |
605 | const char *ElementName) { |
606 | if (Load.C.cmdsize < sizeof(MachO::linkedit_data_command)) |
607 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + " " + |
608 | CmdName + " cmdsize too small" ); |
609 | if (*LoadCmd != nullptr) |
610 | return malformedError(Msg: "more than one " + Twine(CmdName) + " command" ); |
611 | auto LinkDataOrError = |
612 | getStructOrErr<MachO::linkedit_data_command>(O: Obj, P: Load.Ptr); |
613 | if (!LinkDataOrError) |
614 | return LinkDataOrError.takeError(); |
615 | MachO::linkedit_data_command LinkData = LinkDataOrError.get(); |
616 | if (LinkData.cmdsize != sizeof(MachO::linkedit_data_command)) |
617 | return malformedError(Msg: Twine(CmdName) + " command " + |
618 | Twine(LoadCommandIndex) + " has incorrect cmdsize" ); |
619 | uint64_t FileSize = Obj.getData().size(); |
620 | if (LinkData.dataoff > FileSize) |
621 | return malformedError(Msg: "dataoff field of " + Twine(CmdName) + " command " + |
622 | Twine(LoadCommandIndex) + " extends past the end of " |
623 | "the file" ); |
624 | uint64_t BigSize = LinkData.dataoff; |
625 | BigSize += LinkData.datasize; |
626 | if (BigSize > FileSize) |
627 | return malformedError(Msg: "dataoff field plus datasize field of " + |
628 | Twine(CmdName) + " command " + |
629 | Twine(LoadCommandIndex) + " extends past the end of " |
630 | "the file" ); |
631 | if (Error Err = checkOverlappingElement(Elements, Offset: LinkData.dataoff, |
632 | Size: LinkData.datasize, Name: ElementName)) |
633 | return Err; |
634 | *LoadCmd = Load.Ptr; |
635 | return Error::success(); |
636 | } |
637 | |
638 | static Error checkDyldInfoCommand(const MachOObjectFile &Obj, |
639 | const MachOObjectFile::LoadCommandInfo &Load, |
640 | uint32_t LoadCommandIndex, |
641 | const char **LoadCmd, const char *CmdName, |
642 | std::list<MachOElement> &Elements) { |
643 | if (Load.C.cmdsize < sizeof(MachO::dyld_info_command)) |
644 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + " " + |
645 | CmdName + " cmdsize too small" ); |
646 | if (*LoadCmd != nullptr) |
647 | return malformedError(Msg: "more than one LC_DYLD_INFO and or LC_DYLD_INFO_ONLY " |
648 | "command" ); |
649 | auto DyldInfoOrErr = |
650 | getStructOrErr<MachO::dyld_info_command>(O: Obj, P: Load.Ptr); |
651 | if (!DyldInfoOrErr) |
652 | return DyldInfoOrErr.takeError(); |
653 | MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); |
654 | if (DyldInfo.cmdsize != sizeof(MachO::dyld_info_command)) |
655 | return malformedError(Msg: Twine(CmdName) + " command " + |
656 | Twine(LoadCommandIndex) + " has incorrect cmdsize" ); |
657 | uint64_t FileSize = Obj.getData().size(); |
658 | if (DyldInfo.rebase_off > FileSize) |
659 | return malformedError(Msg: "rebase_off field of " + Twine(CmdName) + |
660 | " command " + Twine(LoadCommandIndex) + " extends " |
661 | "past the end of the file" ); |
662 | uint64_t BigSize = DyldInfo.rebase_off; |
663 | BigSize += DyldInfo.rebase_size; |
664 | if (BigSize > FileSize) |
665 | return malformedError(Msg: "rebase_off field plus rebase_size field of " + |
666 | Twine(CmdName) + " command " + |
667 | Twine(LoadCommandIndex) + " extends past the end of " |
668 | "the file" ); |
669 | if (Error Err = checkOverlappingElement(Elements, Offset: DyldInfo.rebase_off, |
670 | Size: DyldInfo.rebase_size, |
671 | Name: "dyld rebase info" )) |
672 | return Err; |
673 | if (DyldInfo.bind_off > FileSize) |
674 | return malformedError(Msg: "bind_off field of " + Twine(CmdName) + |
675 | " command " + Twine(LoadCommandIndex) + " extends " |
676 | "past the end of the file" ); |
677 | BigSize = DyldInfo.bind_off; |
678 | BigSize += DyldInfo.bind_size; |
679 | if (BigSize > FileSize) |
680 | return malformedError(Msg: "bind_off field plus bind_size field of " + |
681 | Twine(CmdName) + " command " + |
682 | Twine(LoadCommandIndex) + " extends past the end of " |
683 | "the file" ); |
684 | if (Error Err = checkOverlappingElement(Elements, Offset: DyldInfo.bind_off, |
685 | Size: DyldInfo.bind_size, |
686 | Name: "dyld bind info" )) |
687 | return Err; |
688 | if (DyldInfo.weak_bind_off > FileSize) |
689 | return malformedError(Msg: "weak_bind_off field of " + Twine(CmdName) + |
690 | " command " + Twine(LoadCommandIndex) + " extends " |
691 | "past the end of the file" ); |
692 | BigSize = DyldInfo.weak_bind_off; |
693 | BigSize += DyldInfo.weak_bind_size; |
694 | if (BigSize > FileSize) |
695 | return malformedError(Msg: "weak_bind_off field plus weak_bind_size field of " + |
696 | Twine(CmdName) + " command " + |
697 | Twine(LoadCommandIndex) + " extends past the end of " |
698 | "the file" ); |
699 | if (Error Err = checkOverlappingElement(Elements, Offset: DyldInfo.weak_bind_off, |
700 | Size: DyldInfo.weak_bind_size, |
701 | Name: "dyld weak bind info" )) |
702 | return Err; |
703 | if (DyldInfo.lazy_bind_off > FileSize) |
704 | return malformedError(Msg: "lazy_bind_off field of " + Twine(CmdName) + |
705 | " command " + Twine(LoadCommandIndex) + " extends " |
706 | "past the end of the file" ); |
707 | BigSize = DyldInfo.lazy_bind_off; |
708 | BigSize += DyldInfo.lazy_bind_size; |
709 | if (BigSize > FileSize) |
710 | return malformedError(Msg: "lazy_bind_off field plus lazy_bind_size field of " + |
711 | Twine(CmdName) + " command " + |
712 | Twine(LoadCommandIndex) + " extends past the end of " |
713 | "the file" ); |
714 | if (Error Err = checkOverlappingElement(Elements, Offset: DyldInfo.lazy_bind_off, |
715 | Size: DyldInfo.lazy_bind_size, |
716 | Name: "dyld lazy bind info" )) |
717 | return Err; |
718 | if (DyldInfo.export_off > FileSize) |
719 | return malformedError(Msg: "export_off field of " + Twine(CmdName) + |
720 | " command " + Twine(LoadCommandIndex) + " extends " |
721 | "past the end of the file" ); |
722 | BigSize = DyldInfo.export_off; |
723 | BigSize += DyldInfo.export_size; |
724 | if (BigSize > FileSize) |
725 | return malformedError(Msg: "export_off field plus export_size field of " + |
726 | Twine(CmdName) + " command " + |
727 | Twine(LoadCommandIndex) + " extends past the end of " |
728 | "the file" ); |
729 | if (Error Err = checkOverlappingElement(Elements, Offset: DyldInfo.export_off, |
730 | Size: DyldInfo.export_size, |
731 | Name: "dyld export info" )) |
732 | return Err; |
733 | *LoadCmd = Load.Ptr; |
734 | return Error::success(); |
735 | } |
736 | |
737 | static Error checkDylibCommand(const MachOObjectFile &Obj, |
738 | const MachOObjectFile::LoadCommandInfo &Load, |
739 | uint32_t LoadCommandIndex, const char *CmdName) { |
740 | if (Load.C.cmdsize < sizeof(MachO::dylib_command)) |
741 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + " " + |
742 | CmdName + " cmdsize too small" ); |
743 | auto CommandOrErr = getStructOrErr<MachO::dylib_command>(O: Obj, P: Load.Ptr); |
744 | if (!CommandOrErr) |
745 | return CommandOrErr.takeError(); |
746 | MachO::dylib_command D = CommandOrErr.get(); |
747 | if (D.dylib.name < sizeof(MachO::dylib_command)) |
748 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + " " + |
749 | CmdName + " name.offset field too small, not past " |
750 | "the end of the dylib_command struct" ); |
751 | if (D.dylib.name >= D.cmdsize) |
752 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + " " + |
753 | CmdName + " name.offset field extends past the end " |
754 | "of the load command" ); |
755 | // Make sure there is a null between the starting offset of the name and |
756 | // the end of the load command. |
757 | uint32_t i; |
758 | const char *P = (const char *)Load.Ptr; |
759 | for (i = D.dylib.name; i < D.cmdsize; i++) |
760 | if (P[i] == '\0') |
761 | break; |
762 | if (i >= D.cmdsize) |
763 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + " " + |
764 | CmdName + " library name extends past the end of the " |
765 | "load command" ); |
766 | return Error::success(); |
767 | } |
768 | |
769 | static Error checkDylibIdCommand(const MachOObjectFile &Obj, |
770 | const MachOObjectFile::LoadCommandInfo &Load, |
771 | uint32_t LoadCommandIndex, |
772 | const char **LoadCmd) { |
773 | if (Error Err = checkDylibCommand(Obj, Load, LoadCommandIndex, |
774 | CmdName: "LC_ID_DYLIB" )) |
775 | return Err; |
776 | if (*LoadCmd != nullptr) |
777 | return malformedError(Msg: "more than one LC_ID_DYLIB command" ); |
778 | if (Obj.getHeader().filetype != MachO::MH_DYLIB && |
779 | Obj.getHeader().filetype != MachO::MH_DYLIB_STUB) |
780 | return malformedError(Msg: "LC_ID_DYLIB load command in non-dynamic library " |
781 | "file type" ); |
782 | *LoadCmd = Load.Ptr; |
783 | return Error::success(); |
784 | } |
785 | |
786 | static Error checkDyldCommand(const MachOObjectFile &Obj, |
787 | const MachOObjectFile::LoadCommandInfo &Load, |
788 | uint32_t LoadCommandIndex, const char *CmdName) { |
789 | if (Load.C.cmdsize < sizeof(MachO::dylinker_command)) |
790 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + " " + |
791 | CmdName + " cmdsize too small" ); |
792 | auto CommandOrErr = getStructOrErr<MachO::dylinker_command>(O: Obj, P: Load.Ptr); |
793 | if (!CommandOrErr) |
794 | return CommandOrErr.takeError(); |
795 | MachO::dylinker_command D = CommandOrErr.get(); |
796 | if (D.name < sizeof(MachO::dylinker_command)) |
797 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + " " + |
798 | CmdName + " name.offset field too small, not past " |
799 | "the end of the dylinker_command struct" ); |
800 | if (D.name >= D.cmdsize) |
801 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + " " + |
802 | CmdName + " name.offset field extends past the end " |
803 | "of the load command" ); |
804 | // Make sure there is a null between the starting offset of the name and |
805 | // the end of the load command. |
806 | uint32_t i; |
807 | const char *P = (const char *)Load.Ptr; |
808 | for (i = D.name; i < D.cmdsize; i++) |
809 | if (P[i] == '\0') |
810 | break; |
811 | if (i >= D.cmdsize) |
812 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + " " + |
813 | CmdName + " dyld name extends past the end of the " |
814 | "load command" ); |
815 | return Error::success(); |
816 | } |
817 | |
818 | static Error checkVersCommand(const MachOObjectFile &Obj, |
819 | const MachOObjectFile::LoadCommandInfo &Load, |
820 | uint32_t LoadCommandIndex, |
821 | const char **LoadCmd, const char *CmdName) { |
822 | if (Load.C.cmdsize != sizeof(MachO::version_min_command)) |
823 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + " " + |
824 | CmdName + " has incorrect cmdsize" ); |
825 | if (*LoadCmd != nullptr) |
826 | return malformedError(Msg: "more than one LC_VERSION_MIN_MACOSX, " |
827 | "LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_TVOS or " |
828 | "LC_VERSION_MIN_WATCHOS command" ); |
829 | *LoadCmd = Load.Ptr; |
830 | return Error::success(); |
831 | } |
832 | |
833 | static Error checkNoteCommand(const MachOObjectFile &Obj, |
834 | const MachOObjectFile::LoadCommandInfo &Load, |
835 | uint32_t LoadCommandIndex, |
836 | std::list<MachOElement> &Elements) { |
837 | if (Load.C.cmdsize != sizeof(MachO::note_command)) |
838 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
839 | " LC_NOTE has incorrect cmdsize" ); |
840 | auto NoteCmdOrErr = getStructOrErr<MachO::note_command>(O: Obj, P: Load.Ptr); |
841 | if (!NoteCmdOrErr) |
842 | return NoteCmdOrErr.takeError(); |
843 | MachO::note_command Nt = NoteCmdOrErr.get(); |
844 | uint64_t FileSize = Obj.getData().size(); |
845 | if (Nt.offset > FileSize) |
846 | return malformedError(Msg: "offset field of LC_NOTE command " + |
847 | Twine(LoadCommandIndex) + " extends " |
848 | "past the end of the file" ); |
849 | uint64_t BigSize = Nt.offset; |
850 | BigSize += Nt.size; |
851 | if (BigSize > FileSize) |
852 | return malformedError(Msg: "size field plus offset field of LC_NOTE command " + |
853 | Twine(LoadCommandIndex) + " extends past the end of " |
854 | "the file" ); |
855 | if (Error Err = checkOverlappingElement(Elements, Offset: Nt.offset, Size: Nt.size, |
856 | Name: "LC_NOTE data" )) |
857 | return Err; |
858 | return Error::success(); |
859 | } |
860 | |
861 | static Error |
862 | parseBuildVersionCommand(const MachOObjectFile &Obj, |
863 | const MachOObjectFile::LoadCommandInfo &Load, |
864 | SmallVectorImpl<const char*> &BuildTools, |
865 | uint32_t LoadCommandIndex) { |
866 | auto BVCOrErr = |
867 | getStructOrErr<MachO::build_version_command>(O: Obj, P: Load.Ptr); |
868 | if (!BVCOrErr) |
869 | return BVCOrErr.takeError(); |
870 | MachO::build_version_command BVC = BVCOrErr.get(); |
871 | if (Load.C.cmdsize != |
872 | sizeof(MachO::build_version_command) + |
873 | BVC.ntools * sizeof(MachO::build_tool_version)) |
874 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
875 | " LC_BUILD_VERSION_COMMAND has incorrect cmdsize" ); |
876 | |
877 | auto Start = Load.Ptr + sizeof(MachO::build_version_command); |
878 | BuildTools.resize(N: BVC.ntools); |
879 | for (unsigned i = 0; i < BVC.ntools; ++i) |
880 | BuildTools[i] = Start + i * sizeof(MachO::build_tool_version); |
881 | |
882 | return Error::success(); |
883 | } |
884 | |
885 | static Error checkRpathCommand(const MachOObjectFile &Obj, |
886 | const MachOObjectFile::LoadCommandInfo &Load, |
887 | uint32_t LoadCommandIndex) { |
888 | if (Load.C.cmdsize < sizeof(MachO::rpath_command)) |
889 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
890 | " LC_RPATH cmdsize too small" ); |
891 | auto ROrErr = getStructOrErr<MachO::rpath_command>(O: Obj, P: Load.Ptr); |
892 | if (!ROrErr) |
893 | return ROrErr.takeError(); |
894 | MachO::rpath_command R = ROrErr.get(); |
895 | if (R.path < sizeof(MachO::rpath_command)) |
896 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
897 | " LC_RPATH path.offset field too small, not past " |
898 | "the end of the rpath_command struct" ); |
899 | if (R.path >= R.cmdsize) |
900 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
901 | " LC_RPATH path.offset field extends past the end " |
902 | "of the load command" ); |
903 | // Make sure there is a null between the starting offset of the path and |
904 | // the end of the load command. |
905 | uint32_t i; |
906 | const char *P = (const char *)Load.Ptr; |
907 | for (i = R.path; i < R.cmdsize; i++) |
908 | if (P[i] == '\0') |
909 | break; |
910 | if (i >= R.cmdsize) |
911 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
912 | " LC_RPATH library name extends past the end of the " |
913 | "load command" ); |
914 | return Error::success(); |
915 | } |
916 | |
917 | static Error checkEncryptCommand(const MachOObjectFile &Obj, |
918 | const MachOObjectFile::LoadCommandInfo &Load, |
919 | uint32_t LoadCommandIndex, |
920 | uint64_t cryptoff, uint64_t cryptsize, |
921 | const char **LoadCmd, const char *CmdName) { |
922 | if (*LoadCmd != nullptr) |
923 | return malformedError(Msg: "more than one LC_ENCRYPTION_INFO and or " |
924 | "LC_ENCRYPTION_INFO_64 command" ); |
925 | uint64_t FileSize = Obj.getData().size(); |
926 | if (cryptoff > FileSize) |
927 | return malformedError(Msg: "cryptoff field of " + Twine(CmdName) + |
928 | " command " + Twine(LoadCommandIndex) + " extends " |
929 | "past the end of the file" ); |
930 | uint64_t BigSize = cryptoff; |
931 | BigSize += cryptsize; |
932 | if (BigSize > FileSize) |
933 | return malformedError(Msg: "cryptoff field plus cryptsize field of " + |
934 | Twine(CmdName) + " command " + |
935 | Twine(LoadCommandIndex) + " extends past the end of " |
936 | "the file" ); |
937 | *LoadCmd = Load.Ptr; |
938 | return Error::success(); |
939 | } |
940 | |
941 | static Error checkLinkerOptCommand(const MachOObjectFile &Obj, |
942 | const MachOObjectFile::LoadCommandInfo &Load, |
943 | uint32_t LoadCommandIndex) { |
944 | if (Load.C.cmdsize < sizeof(MachO::linker_option_command)) |
945 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
946 | " LC_LINKER_OPTION cmdsize too small" ); |
947 | auto LinkOptionOrErr = |
948 | getStructOrErr<MachO::linker_option_command>(O: Obj, P: Load.Ptr); |
949 | if (!LinkOptionOrErr) |
950 | return LinkOptionOrErr.takeError(); |
951 | MachO::linker_option_command L = LinkOptionOrErr.get(); |
952 | // Make sure the count of strings is correct. |
953 | const char *string = (const char *)Load.Ptr + |
954 | sizeof(struct MachO::linker_option_command); |
955 | uint32_t left = L.cmdsize - sizeof(struct MachO::linker_option_command); |
956 | uint32_t i = 0; |
957 | while (left > 0) { |
958 | while (*string == '\0' && left > 0) { |
959 | string++; |
960 | left--; |
961 | } |
962 | if (left > 0) { |
963 | i++; |
964 | uint32_t NullPos = StringRef(string, left).find(C: '\0'); |
965 | if (0xffffffff == NullPos) |
966 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
967 | " LC_LINKER_OPTION string #" + Twine(i) + |
968 | " is not NULL terminated" ); |
969 | uint32_t len = std::min(a: NullPos, b: left) + 1; |
970 | string += len; |
971 | left -= len; |
972 | } |
973 | } |
974 | if (L.count != i) |
975 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
976 | " LC_LINKER_OPTION string count " + Twine(L.count) + |
977 | " does not match number of strings" ); |
978 | return Error::success(); |
979 | } |
980 | |
981 | static Error checkSubCommand(const MachOObjectFile &Obj, |
982 | const MachOObjectFile::LoadCommandInfo &Load, |
983 | uint32_t LoadCommandIndex, const char *CmdName, |
984 | size_t SizeOfCmd, const char *CmdStructName, |
985 | uint32_t PathOffset, const char *PathFieldName) { |
986 | if (PathOffset < SizeOfCmd) |
987 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + " " + |
988 | CmdName + " " + PathFieldName + ".offset field too " |
989 | "small, not past the end of the " + CmdStructName); |
990 | if (PathOffset >= Load.C.cmdsize) |
991 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + " " + |
992 | CmdName + " " + PathFieldName + ".offset field " |
993 | "extends past the end of the load command" ); |
994 | // Make sure there is a null between the starting offset of the path and |
995 | // the end of the load command. |
996 | uint32_t i; |
997 | const char *P = (const char *)Load.Ptr; |
998 | for (i = PathOffset; i < Load.C.cmdsize; i++) |
999 | if (P[i] == '\0') |
1000 | break; |
1001 | if (i >= Load.C.cmdsize) |
1002 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + " " + |
1003 | CmdName + " " + PathFieldName + " name extends past " |
1004 | "the end of the load command" ); |
1005 | return Error::success(); |
1006 | } |
1007 | |
1008 | static Error checkThreadCommand(const MachOObjectFile &Obj, |
1009 | const MachOObjectFile::LoadCommandInfo &Load, |
1010 | uint32_t LoadCommandIndex, |
1011 | const char *CmdName) { |
1012 | if (Load.C.cmdsize < sizeof(MachO::thread_command)) |
1013 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1014 | CmdName + " cmdsize too small" ); |
1015 | auto ThreadCommandOrErr = |
1016 | getStructOrErr<MachO::thread_command>(O: Obj, P: Load.Ptr); |
1017 | if (!ThreadCommandOrErr) |
1018 | return ThreadCommandOrErr.takeError(); |
1019 | MachO::thread_command T = ThreadCommandOrErr.get(); |
1020 | const char *state = Load.Ptr + sizeof(MachO::thread_command); |
1021 | const char *end = Load.Ptr + T.cmdsize; |
1022 | uint32_t nflavor = 0; |
1023 | uint32_t cputype = getCPUType(O: Obj); |
1024 | while (state < end) { |
1025 | if(state + sizeof(uint32_t) > end) |
1026 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1027 | "flavor in " + CmdName + " extends past end of " |
1028 | "command" ); |
1029 | uint32_t flavor; |
1030 | memcpy(dest: &flavor, src: state, n: sizeof(uint32_t)); |
1031 | if (Obj.isLittleEndian() != sys::IsLittleEndianHost) |
1032 | sys::swapByteOrder(Value&: flavor); |
1033 | state += sizeof(uint32_t); |
1034 | |
1035 | if(state + sizeof(uint32_t) > end) |
1036 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1037 | " count in " + CmdName + " extends past end of " |
1038 | "command" ); |
1039 | uint32_t count; |
1040 | memcpy(dest: &count, src: state, n: sizeof(uint32_t)); |
1041 | if (Obj.isLittleEndian() != sys::IsLittleEndianHost) |
1042 | sys::swapByteOrder(Value&: count); |
1043 | state += sizeof(uint32_t); |
1044 | |
1045 | if (cputype == MachO::CPU_TYPE_I386) { |
1046 | if (flavor == MachO::x86_THREAD_STATE32) { |
1047 | if (count != MachO::x86_THREAD_STATE32_COUNT) |
1048 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1049 | " count not x86_THREAD_STATE32_COUNT for " |
1050 | "flavor number " + Twine(nflavor) + " which is " |
1051 | "a x86_THREAD_STATE32 flavor in " + CmdName + |
1052 | " command" ); |
1053 | if (state + sizeof(MachO::x86_thread_state32_t) > end) |
1054 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1055 | " x86_THREAD_STATE32 extends past end of " |
1056 | "command in " + CmdName + " command" ); |
1057 | state += sizeof(MachO::x86_thread_state32_t); |
1058 | } else { |
1059 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1060 | " unknown flavor (" + Twine(flavor) + ") for " |
1061 | "flavor number " + Twine(nflavor) + " in " + |
1062 | CmdName + " command" ); |
1063 | } |
1064 | } else if (cputype == MachO::CPU_TYPE_X86_64) { |
1065 | if (flavor == MachO::x86_THREAD_STATE) { |
1066 | if (count != MachO::x86_THREAD_STATE_COUNT) |
1067 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1068 | " count not x86_THREAD_STATE_COUNT for " |
1069 | "flavor number " + Twine(nflavor) + " which is " |
1070 | "a x86_THREAD_STATE flavor in " + CmdName + |
1071 | " command" ); |
1072 | if (state + sizeof(MachO::x86_thread_state_t) > end) |
1073 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1074 | " x86_THREAD_STATE extends past end of " |
1075 | "command in " + CmdName + " command" ); |
1076 | state += sizeof(MachO::x86_thread_state_t); |
1077 | } else if (flavor == MachO::x86_FLOAT_STATE) { |
1078 | if (count != MachO::x86_FLOAT_STATE_COUNT) |
1079 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1080 | " count not x86_FLOAT_STATE_COUNT for " |
1081 | "flavor number " + Twine(nflavor) + " which is " |
1082 | "a x86_FLOAT_STATE flavor in " + CmdName + |
1083 | " command" ); |
1084 | if (state + sizeof(MachO::x86_float_state_t) > end) |
1085 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1086 | " x86_FLOAT_STATE extends past end of " |
1087 | "command in " + CmdName + " command" ); |
1088 | state += sizeof(MachO::x86_float_state_t); |
1089 | } else if (flavor == MachO::x86_EXCEPTION_STATE) { |
1090 | if (count != MachO::x86_EXCEPTION_STATE_COUNT) |
1091 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1092 | " count not x86_EXCEPTION_STATE_COUNT for " |
1093 | "flavor number " + Twine(nflavor) + " which is " |
1094 | "a x86_EXCEPTION_STATE flavor in " + CmdName + |
1095 | " command" ); |
1096 | if (state + sizeof(MachO::x86_exception_state_t) > end) |
1097 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1098 | " x86_EXCEPTION_STATE extends past end of " |
1099 | "command in " + CmdName + " command" ); |
1100 | state += sizeof(MachO::x86_exception_state_t); |
1101 | } else if (flavor == MachO::x86_THREAD_STATE64) { |
1102 | if (count != MachO::x86_THREAD_STATE64_COUNT) |
1103 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1104 | " count not x86_THREAD_STATE64_COUNT for " |
1105 | "flavor number " + Twine(nflavor) + " which is " |
1106 | "a x86_THREAD_STATE64 flavor in " + CmdName + |
1107 | " command" ); |
1108 | if (state + sizeof(MachO::x86_thread_state64_t) > end) |
1109 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1110 | " x86_THREAD_STATE64 extends past end of " |
1111 | "command in " + CmdName + " command" ); |
1112 | state += sizeof(MachO::x86_thread_state64_t); |
1113 | } else if (flavor == MachO::x86_EXCEPTION_STATE64) { |
1114 | if (count != MachO::x86_EXCEPTION_STATE64_COUNT) |
1115 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1116 | " count not x86_EXCEPTION_STATE64_COUNT for " |
1117 | "flavor number " + Twine(nflavor) + " which is " |
1118 | "a x86_EXCEPTION_STATE64 flavor in " + CmdName + |
1119 | " command" ); |
1120 | if (state + sizeof(MachO::x86_exception_state64_t) > end) |
1121 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1122 | " x86_EXCEPTION_STATE64 extends past end of " |
1123 | "command in " + CmdName + " command" ); |
1124 | state += sizeof(MachO::x86_exception_state64_t); |
1125 | } else { |
1126 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1127 | " unknown flavor (" + Twine(flavor) + ") for " |
1128 | "flavor number " + Twine(nflavor) + " in " + |
1129 | CmdName + " command" ); |
1130 | } |
1131 | } else if (cputype == MachO::CPU_TYPE_ARM) { |
1132 | if (flavor == MachO::ARM_THREAD_STATE) { |
1133 | if (count != MachO::ARM_THREAD_STATE_COUNT) |
1134 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1135 | " count not ARM_THREAD_STATE_COUNT for " |
1136 | "flavor number " + Twine(nflavor) + " which is " |
1137 | "a ARM_THREAD_STATE flavor in " + CmdName + |
1138 | " command" ); |
1139 | if (state + sizeof(MachO::arm_thread_state32_t) > end) |
1140 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1141 | " ARM_THREAD_STATE extends past end of " |
1142 | "command in " + CmdName + " command" ); |
1143 | state += sizeof(MachO::arm_thread_state32_t); |
1144 | } else { |
1145 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1146 | " unknown flavor (" + Twine(flavor) + ") for " |
1147 | "flavor number " + Twine(nflavor) + " in " + |
1148 | CmdName + " command" ); |
1149 | } |
1150 | } else if (cputype == MachO::CPU_TYPE_ARM64 || |
1151 | cputype == MachO::CPU_TYPE_ARM64_32) { |
1152 | if (flavor == MachO::ARM_THREAD_STATE64) { |
1153 | if (count != MachO::ARM_THREAD_STATE64_COUNT) |
1154 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1155 | " count not ARM_THREAD_STATE64_COUNT for " |
1156 | "flavor number " + Twine(nflavor) + " which is " |
1157 | "a ARM_THREAD_STATE64 flavor in " + CmdName + |
1158 | " command" ); |
1159 | if (state + sizeof(MachO::arm_thread_state64_t) > end) |
1160 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1161 | " ARM_THREAD_STATE64 extends past end of " |
1162 | "command in " + CmdName + " command" ); |
1163 | state += sizeof(MachO::arm_thread_state64_t); |
1164 | } else { |
1165 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1166 | " unknown flavor (" + Twine(flavor) + ") for " |
1167 | "flavor number " + Twine(nflavor) + " in " + |
1168 | CmdName + " command" ); |
1169 | } |
1170 | } else if (cputype == MachO::CPU_TYPE_POWERPC) { |
1171 | if (flavor == MachO::PPC_THREAD_STATE) { |
1172 | if (count != MachO::PPC_THREAD_STATE_COUNT) |
1173 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1174 | " count not PPC_THREAD_STATE_COUNT for " |
1175 | "flavor number " + Twine(nflavor) + " which is " |
1176 | "a PPC_THREAD_STATE flavor in " + CmdName + |
1177 | " command" ); |
1178 | if (state + sizeof(MachO::ppc_thread_state32_t) > end) |
1179 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1180 | " PPC_THREAD_STATE extends past end of " |
1181 | "command in " + CmdName + " command" ); |
1182 | state += sizeof(MachO::ppc_thread_state32_t); |
1183 | } else { |
1184 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1185 | " unknown flavor (" + Twine(flavor) + ") for " |
1186 | "flavor number " + Twine(nflavor) + " in " + |
1187 | CmdName + " command" ); |
1188 | } |
1189 | } else { |
1190 | return malformedError(Msg: "unknown cputype (" + Twine(cputype) + ") load " |
1191 | "command " + Twine(LoadCommandIndex) + " for " + |
1192 | CmdName + " command can't be checked" ); |
1193 | } |
1194 | nflavor++; |
1195 | } |
1196 | return Error::success(); |
1197 | } |
1198 | |
1199 | static Error checkTwoLevelHintsCommand(const MachOObjectFile &Obj, |
1200 | const MachOObjectFile::LoadCommandInfo |
1201 | &Load, |
1202 | uint32_t LoadCommandIndex, |
1203 | const char **LoadCmd, |
1204 | std::list<MachOElement> &Elements) { |
1205 | if (Load.C.cmdsize != sizeof(MachO::twolevel_hints_command)) |
1206 | return malformedError(Msg: "load command " + Twine(LoadCommandIndex) + |
1207 | " LC_TWOLEVEL_HINTS has incorrect cmdsize" ); |
1208 | if (*LoadCmd != nullptr) |
1209 | return malformedError(Msg: "more than one LC_TWOLEVEL_HINTS command" ); |
1210 | auto HintsOrErr = getStructOrErr<MachO::twolevel_hints_command>(O: Obj, P: Load.Ptr); |
1211 | if(!HintsOrErr) |
1212 | return HintsOrErr.takeError(); |
1213 | MachO::twolevel_hints_command Hints = HintsOrErr.get(); |
1214 | uint64_t FileSize = Obj.getData().size(); |
1215 | if (Hints.offset > FileSize) |
1216 | return malformedError(Msg: "offset field of LC_TWOLEVEL_HINTS command " + |
1217 | Twine(LoadCommandIndex) + " extends past the end of " |
1218 | "the file" ); |
1219 | uint64_t BigSize = Hints.nhints; |
1220 | BigSize *= sizeof(MachO::twolevel_hint); |
1221 | BigSize += Hints.offset; |
1222 | if (BigSize > FileSize) |
1223 | return malformedError(Msg: "offset field plus nhints times sizeof(struct " |
1224 | "twolevel_hint) field of LC_TWOLEVEL_HINTS command " + |
1225 | Twine(LoadCommandIndex) + " extends past the end of " |
1226 | "the file" ); |
1227 | if (Error Err = checkOverlappingElement(Elements, Offset: Hints.offset, Size: Hints.nhints * |
1228 | sizeof(MachO::twolevel_hint), |
1229 | Name: "two level hints" )) |
1230 | return Err; |
1231 | *LoadCmd = Load.Ptr; |
1232 | return Error::success(); |
1233 | } |
1234 | |
1235 | // Returns true if the libObject code does not support the load command and its |
1236 | // contents. The cmd value it is treated as an unknown load command but with |
1237 | // an error message that says the cmd value is obsolete. |
1238 | static bool isLoadCommandObsolete(uint32_t cmd) { |
1239 | if (cmd == MachO::LC_SYMSEG || |
1240 | cmd == MachO::LC_LOADFVMLIB || |
1241 | cmd == MachO::LC_IDFVMLIB || |
1242 | cmd == MachO::LC_IDENT || |
1243 | cmd == MachO::LC_FVMFILE || |
1244 | cmd == MachO::LC_PREPAGE || |
1245 | cmd == MachO::LC_PREBOUND_DYLIB || |
1246 | cmd == MachO::LC_TWOLEVEL_HINTS || |
1247 | cmd == MachO::LC_PREBIND_CKSUM) |
1248 | return true; |
1249 | return false; |
1250 | } |
1251 | |
1252 | Expected<std::unique_ptr<MachOObjectFile>> |
1253 | MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian, |
1254 | bool Is64Bits, uint32_t UniversalCputype, |
1255 | uint32_t UniversalIndex, |
1256 | size_t MachOFilesetEntryOffset) { |
1257 | Error Err = Error::success(); |
1258 | std::unique_ptr<MachOObjectFile> Obj(new MachOObjectFile( |
1259 | std::move(Object), IsLittleEndian, Is64Bits, Err, UniversalCputype, |
1260 | UniversalIndex, MachOFilesetEntryOffset)); |
1261 | if (Err) |
1262 | return std::move(Err); |
1263 | return std::move(Obj); |
1264 | } |
1265 | |
1266 | MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, |
1267 | bool Is64bits, Error &Err, |
1268 | uint32_t UniversalCputype, |
1269 | uint32_t UniversalIndex, |
1270 | size_t MachOFilesetEntryOffset) |
1271 | : ObjectFile(getMachOType(isLE: IsLittleEndian, is64Bits: Is64bits), Object), |
1272 | MachOFilesetEntryOffset(MachOFilesetEntryOffset) { |
1273 | ErrorAsOutParameter ErrAsOutParam(&Err); |
1274 | uint64_t ; |
1275 | uint32_t cputype; |
1276 | if (is64Bit()) { |
1277 | parseHeader(Obj: *this, Header&: Header64, Err); |
1278 | SizeOfHeaders = sizeof(MachO::mach_header_64); |
1279 | cputype = Header64.cputype; |
1280 | } else { |
1281 | parseHeader(Obj: *this, Header&: Header, Err); |
1282 | SizeOfHeaders = sizeof(MachO::mach_header); |
1283 | cputype = Header.cputype; |
1284 | } |
1285 | if (Err) |
1286 | return; |
1287 | SizeOfHeaders += getHeader().sizeofcmds; |
1288 | if (getData().data() + SizeOfHeaders > getData().end()) { |
1289 | Err = malformedError(Msg: "load commands extend past the end of the file" ); |
1290 | return; |
1291 | } |
1292 | if (UniversalCputype != 0 && cputype != UniversalCputype) { |
1293 | Err = malformedError(Msg: "universal header architecture: " + |
1294 | Twine(UniversalIndex) + "'s cputype does not match " |
1295 | "object file's mach header" ); |
1296 | return; |
1297 | } |
1298 | std::list<MachOElement> Elements; |
1299 | Elements.push_back(x: {.Offset: 0, .Size: SizeOfHeaders, .Name: "Mach-O headers" }); |
1300 | |
1301 | uint32_t LoadCommandCount = getHeader().ncmds; |
1302 | LoadCommandInfo Load; |
1303 | if (LoadCommandCount != 0) { |
1304 | if (auto LoadOrErr = getFirstLoadCommandInfo(Obj: *this)) |
1305 | Load = *LoadOrErr; |
1306 | else { |
1307 | Err = LoadOrErr.takeError(); |
1308 | return; |
1309 | } |
1310 | } |
1311 | |
1312 | const char *DyldIdLoadCmd = nullptr; |
1313 | const char *SplitInfoLoadCmd = nullptr; |
1314 | const char *CodeSignDrsLoadCmd = nullptr; |
1315 | const char *CodeSignLoadCmd = nullptr; |
1316 | const char *VersLoadCmd = nullptr; |
1317 | const char *SourceLoadCmd = nullptr; |
1318 | const char *EntryPointLoadCmd = nullptr; |
1319 | const char *EncryptLoadCmd = nullptr; |
1320 | const char *RoutinesLoadCmd = nullptr; |
1321 | const char *UnixThreadLoadCmd = nullptr; |
1322 | const char *TwoLevelHintsLoadCmd = nullptr; |
1323 | for (unsigned I = 0; I < LoadCommandCount; ++I) { |
1324 | if (is64Bit()) { |
1325 | if (Load.C.cmdsize % 8 != 0) { |
1326 | // We have a hack here to allow 64-bit Mach-O core files to have |
1327 | // LC_THREAD commands that are only a multiple of 4 and not 8 to be |
1328 | // allowed since the macOS kernel produces them. |
1329 | if (getHeader().filetype != MachO::MH_CORE || |
1330 | Load.C.cmd != MachO::LC_THREAD || Load.C.cmdsize % 4) { |
1331 | Err = malformedError(Msg: "load command " + Twine(I) + " cmdsize not a " |
1332 | "multiple of 8" ); |
1333 | return; |
1334 | } |
1335 | } |
1336 | } else { |
1337 | if (Load.C.cmdsize % 4 != 0) { |
1338 | Err = malformedError(Msg: "load command " + Twine(I) + " cmdsize not a " |
1339 | "multiple of 4" ); |
1340 | return; |
1341 | } |
1342 | } |
1343 | LoadCommands.push_back(Elt: Load); |
1344 | if (Load.C.cmd == MachO::LC_SYMTAB) { |
1345 | if ((Err = checkSymtabCommand(Obj: *this, Load, LoadCommandIndex: I, SymtabLoadCmd: &SymtabLoadCmd, Elements))) |
1346 | return; |
1347 | } else if (Load.C.cmd == MachO::LC_DYSYMTAB) { |
1348 | if ((Err = checkDysymtabCommand(Obj: *this, Load, LoadCommandIndex: I, DysymtabLoadCmd: &DysymtabLoadCmd, |
1349 | Elements))) |
1350 | return; |
1351 | } else if (Load.C.cmd == MachO::LC_DATA_IN_CODE) { |
1352 | if ((Err = checkLinkeditDataCommand(Obj: *this, Load, LoadCommandIndex: I, LoadCmd: &DataInCodeLoadCmd, |
1353 | CmdName: "LC_DATA_IN_CODE" , Elements, |
1354 | ElementName: "data in code info" ))) |
1355 | return; |
1356 | } else if (Load.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT) { |
1357 | if ((Err = checkLinkeditDataCommand(Obj: *this, Load, LoadCommandIndex: I, LoadCmd: &LinkOptHintsLoadCmd, |
1358 | CmdName: "LC_LINKER_OPTIMIZATION_HINT" , |
1359 | Elements, ElementName: "linker optimization " |
1360 | "hints" ))) |
1361 | return; |
1362 | } else if (Load.C.cmd == MachO::LC_FUNCTION_STARTS) { |
1363 | if ((Err = checkLinkeditDataCommand(Obj: *this, Load, LoadCommandIndex: I, LoadCmd: &FuncStartsLoadCmd, |
1364 | CmdName: "LC_FUNCTION_STARTS" , Elements, |
1365 | ElementName: "function starts data" ))) |
1366 | return; |
1367 | } else if (Load.C.cmd == MachO::LC_SEGMENT_SPLIT_INFO) { |
1368 | if ((Err = checkLinkeditDataCommand(Obj: *this, Load, LoadCommandIndex: I, LoadCmd: &SplitInfoLoadCmd, |
1369 | CmdName: "LC_SEGMENT_SPLIT_INFO" , Elements, |
1370 | ElementName: "split info data" ))) |
1371 | return; |
1372 | } else if (Load.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS) { |
1373 | if ((Err = checkLinkeditDataCommand(Obj: *this, Load, LoadCommandIndex: I, LoadCmd: &CodeSignDrsLoadCmd, |
1374 | CmdName: "LC_DYLIB_CODE_SIGN_DRS" , Elements, |
1375 | ElementName: "code signing RDs data" ))) |
1376 | return; |
1377 | } else if (Load.C.cmd == MachO::LC_CODE_SIGNATURE) { |
1378 | if ((Err = checkLinkeditDataCommand(Obj: *this, Load, LoadCommandIndex: I, LoadCmd: &CodeSignLoadCmd, |
1379 | CmdName: "LC_CODE_SIGNATURE" , Elements, |
1380 | ElementName: "code signature data" ))) |
1381 | return; |
1382 | } else if (Load.C.cmd == MachO::LC_DYLD_INFO) { |
1383 | if ((Err = checkDyldInfoCommand(Obj: *this, Load, LoadCommandIndex: I, LoadCmd: &DyldInfoLoadCmd, |
1384 | CmdName: "LC_DYLD_INFO" , Elements))) |
1385 | return; |
1386 | } else if (Load.C.cmd == MachO::LC_DYLD_INFO_ONLY) { |
1387 | if ((Err = checkDyldInfoCommand(Obj: *this, Load, LoadCommandIndex: I, LoadCmd: &DyldInfoLoadCmd, |
1388 | CmdName: "LC_DYLD_INFO_ONLY" , Elements))) |
1389 | return; |
1390 | } else if (Load.C.cmd == MachO::LC_DYLD_CHAINED_FIXUPS) { |
1391 | if ((Err = checkLinkeditDataCommand( |
1392 | Obj: *this, Load, LoadCommandIndex: I, LoadCmd: &DyldChainedFixupsLoadCmd, |
1393 | CmdName: "LC_DYLD_CHAINED_FIXUPS" , Elements, ElementName: "chained fixups" ))) |
1394 | return; |
1395 | } else if (Load.C.cmd == MachO::LC_DYLD_EXPORTS_TRIE) { |
1396 | if ((Err = checkLinkeditDataCommand( |
1397 | Obj: *this, Load, LoadCommandIndex: I, LoadCmd: &DyldExportsTrieLoadCmd, CmdName: "LC_DYLD_EXPORTS_TRIE" , |
1398 | Elements, ElementName: "exports trie" ))) |
1399 | return; |
1400 | } else if (Load.C.cmd == MachO::LC_UUID) { |
1401 | if (Load.C.cmdsize != sizeof(MachO::uuid_command)) { |
1402 | Err = malformedError(Msg: "LC_UUID command " + Twine(I) + " has incorrect " |
1403 | "cmdsize" ); |
1404 | return; |
1405 | } |
1406 | if (UuidLoadCmd) { |
1407 | Err = malformedError(Msg: "more than one LC_UUID command" ); |
1408 | return; |
1409 | } |
1410 | UuidLoadCmd = Load.Ptr; |
1411 | } else if (Load.C.cmd == MachO::LC_SEGMENT_64) { |
1412 | if ((Err = parseSegmentLoadCommand<MachO::segment_command_64, |
1413 | MachO::section_64>( |
1414 | Obj: *this, Load, Sections, IsPageZeroSegment&: HasPageZeroSegment, LoadCommandIndex: I, |
1415 | CmdName: "LC_SEGMENT_64" , SizeOfHeaders, Elements))) |
1416 | return; |
1417 | } else if (Load.C.cmd == MachO::LC_SEGMENT) { |
1418 | if ((Err = parseSegmentLoadCommand<MachO::segment_command, |
1419 | MachO::section>( |
1420 | Obj: *this, Load, Sections, IsPageZeroSegment&: HasPageZeroSegment, LoadCommandIndex: I, |
1421 | CmdName: "LC_SEGMENT" , SizeOfHeaders, Elements))) |
1422 | return; |
1423 | } else if (Load.C.cmd == MachO::LC_ID_DYLIB) { |
1424 | if ((Err = checkDylibIdCommand(Obj: *this, Load, LoadCommandIndex: I, LoadCmd: &DyldIdLoadCmd))) |
1425 | return; |
1426 | } else if (Load.C.cmd == MachO::LC_LOAD_DYLIB) { |
1427 | if ((Err = checkDylibCommand(Obj: *this, Load, LoadCommandIndex: I, CmdName: "LC_LOAD_DYLIB" ))) |
1428 | return; |
1429 | Libraries.push_back(Elt: Load.Ptr); |
1430 | } else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB) { |
1431 | if ((Err = checkDylibCommand(Obj: *this, Load, LoadCommandIndex: I, CmdName: "LC_LOAD_WEAK_DYLIB" ))) |
1432 | return; |
1433 | Libraries.push_back(Elt: Load.Ptr); |
1434 | } else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB) { |
1435 | if ((Err = checkDylibCommand(Obj: *this, Load, LoadCommandIndex: I, CmdName: "LC_LAZY_LOAD_DYLIB" ))) |
1436 | return; |
1437 | Libraries.push_back(Elt: Load.Ptr); |
1438 | } else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB) { |
1439 | if ((Err = checkDylibCommand(Obj: *this, Load, LoadCommandIndex: I, CmdName: "LC_REEXPORT_DYLIB" ))) |
1440 | return; |
1441 | Libraries.push_back(Elt: Load.Ptr); |
1442 | } else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) { |
1443 | if ((Err = checkDylibCommand(Obj: *this, Load, LoadCommandIndex: I, CmdName: "LC_LOAD_UPWARD_DYLIB" ))) |
1444 | return; |
1445 | Libraries.push_back(Elt: Load.Ptr); |
1446 | } else if (Load.C.cmd == MachO::LC_ID_DYLINKER) { |
1447 | if ((Err = checkDyldCommand(Obj: *this, Load, LoadCommandIndex: I, CmdName: "LC_ID_DYLINKER" ))) |
1448 | return; |
1449 | } else if (Load.C.cmd == MachO::LC_LOAD_DYLINKER) { |
1450 | if ((Err = checkDyldCommand(Obj: *this, Load, LoadCommandIndex: I, CmdName: "LC_LOAD_DYLINKER" ))) |
1451 | return; |
1452 | } else if (Load.C.cmd == MachO::LC_DYLD_ENVIRONMENT) { |
1453 | if ((Err = checkDyldCommand(Obj: *this, Load, LoadCommandIndex: I, CmdName: "LC_DYLD_ENVIRONMENT" ))) |
1454 | return; |
1455 | } else if (Load.C.cmd == MachO::LC_VERSION_MIN_MACOSX) { |
1456 | if ((Err = checkVersCommand(Obj: *this, Load, LoadCommandIndex: I, LoadCmd: &VersLoadCmd, |
1457 | CmdName: "LC_VERSION_MIN_MACOSX" ))) |
1458 | return; |
1459 | } else if (Load.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS) { |
1460 | if ((Err = checkVersCommand(Obj: *this, Load, LoadCommandIndex: I, LoadCmd: &VersLoadCmd, |
1461 | CmdName: "LC_VERSION_MIN_IPHONEOS" ))) |
1462 | return; |
1463 | } else if (Load.C.cmd == MachO::LC_VERSION_MIN_TVOS) { |
1464 | if ((Err = checkVersCommand(Obj: *this, Load, LoadCommandIndex: I, LoadCmd: &VersLoadCmd, |
1465 | CmdName: "LC_VERSION_MIN_TVOS" ))) |
1466 | return; |
1467 | } else if (Load.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) { |
1468 | if ((Err = checkVersCommand(Obj: *this, Load, LoadCommandIndex: I, LoadCmd: &VersLoadCmd, |
1469 | CmdName: "LC_VERSION_MIN_WATCHOS" ))) |
1470 | return; |
1471 | } else if (Load.C.cmd == MachO::LC_NOTE) { |
1472 | if ((Err = checkNoteCommand(Obj: *this, Load, LoadCommandIndex: I, Elements))) |
1473 | return; |
1474 | } else if (Load.C.cmd == MachO::LC_BUILD_VERSION) { |
1475 | if ((Err = parseBuildVersionCommand(Obj: *this, Load, BuildTools, LoadCommandIndex: I))) |
1476 | return; |
1477 | } else if (Load.C.cmd == MachO::LC_RPATH) { |
1478 | if ((Err = checkRpathCommand(Obj: *this, Load, LoadCommandIndex: I))) |
1479 | return; |
1480 | } else if (Load.C.cmd == MachO::LC_SOURCE_VERSION) { |
1481 | if (Load.C.cmdsize != sizeof(MachO::source_version_command)) { |
1482 | Err = malformedError(Msg: "LC_SOURCE_VERSION command " + Twine(I) + |
1483 | " has incorrect cmdsize" ); |
1484 | return; |
1485 | } |
1486 | if (SourceLoadCmd) { |
1487 | Err = malformedError(Msg: "more than one LC_SOURCE_VERSION command" ); |
1488 | return; |
1489 | } |
1490 | SourceLoadCmd = Load.Ptr; |
1491 | } else if (Load.C.cmd == MachO::LC_MAIN) { |
1492 | if (Load.C.cmdsize != sizeof(MachO::entry_point_command)) { |
1493 | Err = malformedError(Msg: "LC_MAIN command " + Twine(I) + |
1494 | " has incorrect cmdsize" ); |
1495 | return; |
1496 | } |
1497 | if (EntryPointLoadCmd) { |
1498 | Err = malformedError(Msg: "more than one LC_MAIN command" ); |
1499 | return; |
1500 | } |
1501 | EntryPointLoadCmd = Load.Ptr; |
1502 | } else if (Load.C.cmd == MachO::LC_ENCRYPTION_INFO) { |
1503 | if (Load.C.cmdsize != sizeof(MachO::encryption_info_command)) { |
1504 | Err = malformedError(Msg: "LC_ENCRYPTION_INFO command " + Twine(I) + |
1505 | " has incorrect cmdsize" ); |
1506 | return; |
1507 | } |
1508 | MachO::encryption_info_command E = |
1509 | getStruct<MachO::encryption_info_command>(O: *this, P: Load.Ptr); |
1510 | if ((Err = checkEncryptCommand(Obj: *this, Load, LoadCommandIndex: I, cryptoff: E.cryptoff, cryptsize: E.cryptsize, |
1511 | LoadCmd: &EncryptLoadCmd, CmdName: "LC_ENCRYPTION_INFO" ))) |
1512 | return; |
1513 | } else if (Load.C.cmd == MachO::LC_ENCRYPTION_INFO_64) { |
1514 | if (Load.C.cmdsize != sizeof(MachO::encryption_info_command_64)) { |
1515 | Err = malformedError(Msg: "LC_ENCRYPTION_INFO_64 command " + Twine(I) + |
1516 | " has incorrect cmdsize" ); |
1517 | return; |
1518 | } |
1519 | MachO::encryption_info_command_64 E = |
1520 | getStruct<MachO::encryption_info_command_64>(O: *this, P: Load.Ptr); |
1521 | if ((Err = checkEncryptCommand(Obj: *this, Load, LoadCommandIndex: I, cryptoff: E.cryptoff, cryptsize: E.cryptsize, |
1522 | LoadCmd: &EncryptLoadCmd, CmdName: "LC_ENCRYPTION_INFO_64" ))) |
1523 | return; |
1524 | } else if (Load.C.cmd == MachO::LC_LINKER_OPTION) { |
1525 | if ((Err = checkLinkerOptCommand(Obj: *this, Load, LoadCommandIndex: I))) |
1526 | return; |
1527 | } else if (Load.C.cmd == MachO::LC_SUB_FRAMEWORK) { |
1528 | if (Load.C.cmdsize < sizeof(MachO::sub_framework_command)) { |
1529 | Err = malformedError(Msg: "load command " + Twine(I) + |
1530 | " LC_SUB_FRAMEWORK cmdsize too small" ); |
1531 | return; |
1532 | } |
1533 | MachO::sub_framework_command S = |
1534 | getStruct<MachO::sub_framework_command>(O: *this, P: Load.Ptr); |
1535 | if ((Err = checkSubCommand(Obj: *this, Load, LoadCommandIndex: I, CmdName: "LC_SUB_FRAMEWORK" , |
1536 | SizeOfCmd: sizeof(MachO::sub_framework_command), |
1537 | CmdStructName: "sub_framework_command" , PathOffset: S.umbrella, |
1538 | PathFieldName: "umbrella" ))) |
1539 | return; |
1540 | } else if (Load.C.cmd == MachO::LC_SUB_UMBRELLA) { |
1541 | if (Load.C.cmdsize < sizeof(MachO::sub_umbrella_command)) { |
1542 | Err = malformedError(Msg: "load command " + Twine(I) + |
1543 | " LC_SUB_UMBRELLA cmdsize too small" ); |
1544 | return; |
1545 | } |
1546 | MachO::sub_umbrella_command S = |
1547 | getStruct<MachO::sub_umbrella_command>(O: *this, P: Load.Ptr); |
1548 | if ((Err = checkSubCommand(Obj: *this, Load, LoadCommandIndex: I, CmdName: "LC_SUB_UMBRELLA" , |
1549 | SizeOfCmd: sizeof(MachO::sub_umbrella_command), |
1550 | CmdStructName: "sub_umbrella_command" , PathOffset: S.sub_umbrella, |
1551 | PathFieldName: "sub_umbrella" ))) |
1552 | return; |
1553 | } else if (Load.C.cmd == MachO::LC_SUB_LIBRARY) { |
1554 | if (Load.C.cmdsize < sizeof(MachO::sub_library_command)) { |
1555 | Err = malformedError(Msg: "load command " + Twine(I) + |
1556 | " LC_SUB_LIBRARY cmdsize too small" ); |
1557 | return; |
1558 | } |
1559 | MachO::sub_library_command S = |
1560 | getStruct<MachO::sub_library_command>(O: *this, P: Load.Ptr); |
1561 | if ((Err = checkSubCommand(Obj: *this, Load, LoadCommandIndex: I, CmdName: "LC_SUB_LIBRARY" , |
1562 | SizeOfCmd: sizeof(MachO::sub_library_command), |
1563 | CmdStructName: "sub_library_command" , PathOffset: S.sub_library, |
1564 | PathFieldName: "sub_library" ))) |
1565 | return; |
1566 | } else if (Load.C.cmd == MachO::LC_SUB_CLIENT) { |
1567 | if (Load.C.cmdsize < sizeof(MachO::sub_client_command)) { |
1568 | Err = malformedError(Msg: "load command " + Twine(I) + |
1569 | " LC_SUB_CLIENT cmdsize too small" ); |
1570 | return; |
1571 | } |
1572 | MachO::sub_client_command S = |
1573 | getStruct<MachO::sub_client_command>(O: *this, P: Load.Ptr); |
1574 | if ((Err = checkSubCommand(Obj: *this, Load, LoadCommandIndex: I, CmdName: "LC_SUB_CLIENT" , |
1575 | SizeOfCmd: sizeof(MachO::sub_client_command), |
1576 | CmdStructName: "sub_client_command" , PathOffset: S.client, PathFieldName: "client" ))) |
1577 | return; |
1578 | } else if (Load.C.cmd == MachO::LC_ROUTINES) { |
1579 | if (Load.C.cmdsize != sizeof(MachO::routines_command)) { |
1580 | Err = malformedError(Msg: "LC_ROUTINES command " + Twine(I) + |
1581 | " has incorrect cmdsize" ); |
1582 | return; |
1583 | } |
1584 | if (RoutinesLoadCmd) { |
1585 | Err = malformedError(Msg: "more than one LC_ROUTINES and or LC_ROUTINES_64 " |
1586 | "command" ); |
1587 | return; |
1588 | } |
1589 | RoutinesLoadCmd = Load.Ptr; |
1590 | } else if (Load.C.cmd == MachO::LC_ROUTINES_64) { |
1591 | if (Load.C.cmdsize != sizeof(MachO::routines_command_64)) { |
1592 | Err = malformedError(Msg: "LC_ROUTINES_64 command " + Twine(I) + |
1593 | " has incorrect cmdsize" ); |
1594 | return; |
1595 | } |
1596 | if (RoutinesLoadCmd) { |
1597 | Err = malformedError(Msg: "more than one LC_ROUTINES_64 and or LC_ROUTINES " |
1598 | "command" ); |
1599 | return; |
1600 | } |
1601 | RoutinesLoadCmd = Load.Ptr; |
1602 | } else if (Load.C.cmd == MachO::LC_UNIXTHREAD) { |
1603 | if ((Err = checkThreadCommand(Obj: *this, Load, LoadCommandIndex: I, CmdName: "LC_UNIXTHREAD" ))) |
1604 | return; |
1605 | if (UnixThreadLoadCmd) { |
1606 | Err = malformedError(Msg: "more than one LC_UNIXTHREAD command" ); |
1607 | return; |
1608 | } |
1609 | UnixThreadLoadCmd = Load.Ptr; |
1610 | } else if (Load.C.cmd == MachO::LC_THREAD) { |
1611 | if ((Err = checkThreadCommand(Obj: *this, Load, LoadCommandIndex: I, CmdName: "LC_THREAD" ))) |
1612 | return; |
1613 | // Note: LC_TWOLEVEL_HINTS is really obsolete and is not supported. |
1614 | } else if (Load.C.cmd == MachO::LC_TWOLEVEL_HINTS) { |
1615 | if ((Err = checkTwoLevelHintsCommand(Obj: *this, Load, LoadCommandIndex: I, |
1616 | LoadCmd: &TwoLevelHintsLoadCmd, Elements))) |
1617 | return; |
1618 | } else if (Load.C.cmd == MachO::LC_IDENT) { |
1619 | // Note: LC_IDENT is ignored. |
1620 | continue; |
1621 | } else if (isLoadCommandObsolete(cmd: Load.C.cmd)) { |
1622 | Err = malformedError(Msg: "load command " + Twine(I) + " for cmd value of: " + |
1623 | Twine(Load.C.cmd) + " is obsolete and not " |
1624 | "supported" ); |
1625 | return; |
1626 | } |
1627 | // TODO: generate a error for unknown load commands by default. But still |
1628 | // need work out an approach to allow or not allow unknown values like this |
1629 | // as an option for some uses like lldb. |
1630 | if (I < LoadCommandCount - 1) { |
1631 | if (auto LoadOrErr = getNextLoadCommandInfo(Obj: *this, LoadCommandIndex: I, L: Load)) |
1632 | Load = *LoadOrErr; |
1633 | else { |
1634 | Err = LoadOrErr.takeError(); |
1635 | return; |
1636 | } |
1637 | } |
1638 | } |
1639 | if (!SymtabLoadCmd) { |
1640 | if (DysymtabLoadCmd) { |
1641 | Err = malformedError(Msg: "contains LC_DYSYMTAB load command without a " |
1642 | "LC_SYMTAB load command" ); |
1643 | return; |
1644 | } |
1645 | } else if (DysymtabLoadCmd) { |
1646 | MachO::symtab_command Symtab = |
1647 | getStruct<MachO::symtab_command>(O: *this, P: SymtabLoadCmd); |
1648 | MachO::dysymtab_command Dysymtab = |
1649 | getStruct<MachO::dysymtab_command>(O: *this, P: DysymtabLoadCmd); |
1650 | if (Dysymtab.nlocalsym != 0 && Dysymtab.ilocalsym > Symtab.nsyms) { |
1651 | Err = malformedError(Msg: "ilocalsym in LC_DYSYMTAB load command " |
1652 | "extends past the end of the symbol table" ); |
1653 | return; |
1654 | } |
1655 | uint64_t BigSize = Dysymtab.ilocalsym; |
1656 | BigSize += Dysymtab.nlocalsym; |
1657 | if (Dysymtab.nlocalsym != 0 && BigSize > Symtab.nsyms) { |
1658 | Err = malformedError(Msg: "ilocalsym plus nlocalsym in LC_DYSYMTAB load " |
1659 | "command extends past the end of the symbol table" ); |
1660 | return; |
1661 | } |
1662 | if (Dysymtab.nextdefsym != 0 && Dysymtab.iextdefsym > Symtab.nsyms) { |
1663 | Err = malformedError(Msg: "iextdefsym in LC_DYSYMTAB load command " |
1664 | "extends past the end of the symbol table" ); |
1665 | return; |
1666 | } |
1667 | BigSize = Dysymtab.iextdefsym; |
1668 | BigSize += Dysymtab.nextdefsym; |
1669 | if (Dysymtab.nextdefsym != 0 && BigSize > Symtab.nsyms) { |
1670 | Err = malformedError(Msg: "iextdefsym plus nextdefsym in LC_DYSYMTAB " |
1671 | "load command extends past the end of the symbol " |
1672 | "table" ); |
1673 | return; |
1674 | } |
1675 | if (Dysymtab.nundefsym != 0 && Dysymtab.iundefsym > Symtab.nsyms) { |
1676 | Err = malformedError(Msg: "iundefsym in LC_DYSYMTAB load command " |
1677 | "extends past the end of the symbol table" ); |
1678 | return; |
1679 | } |
1680 | BigSize = Dysymtab.iundefsym; |
1681 | BigSize += Dysymtab.nundefsym; |
1682 | if (Dysymtab.nundefsym != 0 && BigSize > Symtab.nsyms) { |
1683 | Err = malformedError(Msg: "iundefsym plus nundefsym in LC_DYSYMTAB load " |
1684 | " command extends past the end of the symbol table" ); |
1685 | return; |
1686 | } |
1687 | } |
1688 | if ((getHeader().filetype == MachO::MH_DYLIB || |
1689 | getHeader().filetype == MachO::MH_DYLIB_STUB) && |
1690 | DyldIdLoadCmd == nullptr) { |
1691 | Err = malformedError(Msg: "no LC_ID_DYLIB load command in dynamic library " |
1692 | "filetype" ); |
1693 | return; |
1694 | } |
1695 | assert(LoadCommands.size() == LoadCommandCount); |
1696 | |
1697 | Err = Error::success(); |
1698 | } |
1699 | |
1700 | Error MachOObjectFile::checkSymbolTable() const { |
1701 | uint32_t Flags = 0; |
1702 | if (is64Bit()) { |
1703 | MachO::mach_header_64 H_64 = MachOObjectFile::getHeader64(); |
1704 | Flags = H_64.flags; |
1705 | } else { |
1706 | MachO::mach_header H = MachOObjectFile::getHeader(); |
1707 | Flags = H.flags; |
1708 | } |
1709 | uint8_t NType = 0; |
1710 | uint8_t NSect = 0; |
1711 | uint16_t NDesc = 0; |
1712 | uint32_t NStrx = 0; |
1713 | uint64_t NValue = 0; |
1714 | uint32_t SymbolIndex = 0; |
1715 | MachO::symtab_command S = getSymtabLoadCommand(); |
1716 | for (const SymbolRef &Symbol : symbols()) { |
1717 | DataRefImpl SymDRI = Symbol.getRawDataRefImpl(); |
1718 | if (is64Bit()) { |
1719 | MachO::nlist_64 STE_64 = getSymbol64TableEntry(DRI: SymDRI); |
1720 | NType = STE_64.n_type; |
1721 | NSect = STE_64.n_sect; |
1722 | NDesc = STE_64.n_desc; |
1723 | NStrx = STE_64.n_strx; |
1724 | NValue = STE_64.n_value; |
1725 | } else { |
1726 | MachO::nlist STE = getSymbolTableEntry(DRI: SymDRI); |
1727 | NType = STE.n_type; |
1728 | NSect = STE.n_sect; |
1729 | NDesc = STE.n_desc; |
1730 | NStrx = STE.n_strx; |
1731 | NValue = STE.n_value; |
1732 | } |
1733 | if ((NType & MachO::N_STAB) == 0) { |
1734 | if ((NType & MachO::N_TYPE) == MachO::N_SECT) { |
1735 | if (NSect == 0 || NSect > Sections.size()) |
1736 | return malformedError(Msg: "bad section index: " + Twine((int)NSect) + |
1737 | " for symbol at index " + Twine(SymbolIndex)); |
1738 | } |
1739 | if ((NType & MachO::N_TYPE) == MachO::N_INDR) { |
1740 | if (NValue >= S.strsize) |
1741 | return malformedError(Msg: "bad n_value: " + Twine((int)NValue) + " past " |
1742 | "the end of string table, for N_INDR symbol at " |
1743 | "index " + Twine(SymbolIndex)); |
1744 | } |
1745 | if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL && |
1746 | (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) || |
1747 | (NType & MachO::N_TYPE) == MachO::N_PBUD)) { |
1748 | uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(n_desc: NDesc); |
1749 | if (LibraryOrdinal != 0 && |
1750 | LibraryOrdinal != MachO::EXECUTABLE_ORDINAL && |
1751 | LibraryOrdinal != MachO::DYNAMIC_LOOKUP_ORDINAL && |
1752 | LibraryOrdinal - 1 >= Libraries.size() ) { |
1753 | return malformedError(Msg: "bad library ordinal: " + Twine(LibraryOrdinal) + |
1754 | " for symbol at index " + Twine(SymbolIndex)); |
1755 | } |
1756 | } |
1757 | } |
1758 | if (NStrx >= S.strsize) |
1759 | return malformedError(Msg: "bad string table index: " + Twine((int)NStrx) + |
1760 | " past the end of string table, for symbol at " |
1761 | "index " + Twine(SymbolIndex)); |
1762 | SymbolIndex++; |
1763 | } |
1764 | return Error::success(); |
1765 | } |
1766 | |
1767 | void MachOObjectFile::moveSymbolNext(DataRefImpl &Symb) const { |
1768 | unsigned SymbolTableEntrySize = is64Bit() ? |
1769 | sizeof(MachO::nlist_64) : |
1770 | sizeof(MachO::nlist); |
1771 | Symb.p += SymbolTableEntrySize; |
1772 | } |
1773 | |
1774 | Expected<StringRef> MachOObjectFile::getSymbolName(DataRefImpl Symb) const { |
1775 | StringRef StringTable = getStringTableData(); |
1776 | MachO::nlist_base Entry = getSymbolTableEntryBase(O: *this, DRI: Symb); |
1777 | if (Entry.n_strx == 0) |
1778 | // A n_strx value of 0 indicates that no name is associated with a |
1779 | // particular symbol table entry. |
1780 | return StringRef(); |
1781 | const char *Start = &StringTable.data()[Entry.n_strx]; |
1782 | if (Start < getData().begin() || Start >= getData().end()) { |
1783 | return malformedError(Msg: "bad string index: " + Twine(Entry.n_strx) + |
1784 | " for symbol at index " + Twine(getSymbolIndex(Symb))); |
1785 | } |
1786 | return StringRef(Start); |
1787 | } |
1788 | |
1789 | unsigned MachOObjectFile::getSectionType(SectionRef Sec) const { |
1790 | DataRefImpl DRI = Sec.getRawDataRefImpl(); |
1791 | uint32_t Flags = getSectionFlags(O: *this, Sec: DRI); |
1792 | return Flags & MachO::SECTION_TYPE; |
1793 | } |
1794 | |
1795 | uint64_t MachOObjectFile::getNValue(DataRefImpl Sym) const { |
1796 | if (is64Bit()) { |
1797 | MachO::nlist_64 Entry = getSymbol64TableEntry(DRI: Sym); |
1798 | return Entry.n_value; |
1799 | } |
1800 | MachO::nlist Entry = getSymbolTableEntry(DRI: Sym); |
1801 | return Entry.n_value; |
1802 | } |
1803 | |
1804 | // getIndirectName() returns the name of the alias'ed symbol who's string table |
1805 | // index is in the n_value field. |
1806 | std::error_code MachOObjectFile::getIndirectName(DataRefImpl Symb, |
1807 | StringRef &Res) const { |
1808 | StringRef StringTable = getStringTableData(); |
1809 | MachO::nlist_base Entry = getSymbolTableEntryBase(O: *this, DRI: Symb); |
1810 | if ((Entry.n_type & MachO::N_TYPE) != MachO::N_INDR) |
1811 | return object_error::parse_failed; |
1812 | uint64_t NValue = getNValue(Sym: Symb); |
1813 | if (NValue >= StringTable.size()) |
1814 | return object_error::parse_failed; |
1815 | const char *Start = &StringTable.data()[NValue]; |
1816 | Res = StringRef(Start); |
1817 | return std::error_code(); |
1818 | } |
1819 | |
1820 | uint64_t MachOObjectFile::getSymbolValueImpl(DataRefImpl Sym) const { |
1821 | return getNValue(Sym); |
1822 | } |
1823 | |
1824 | Expected<uint64_t> MachOObjectFile::getSymbolAddress(DataRefImpl Sym) const { |
1825 | return getSymbolValue(Symb: Sym); |
1826 | } |
1827 | |
1828 | uint32_t MachOObjectFile::getSymbolAlignment(DataRefImpl DRI) const { |
1829 | uint32_t Flags = cantFail(ValOrErr: getSymbolFlags(Symb: DRI)); |
1830 | if (Flags & SymbolRef::SF_Common) { |
1831 | MachO::nlist_base Entry = getSymbolTableEntryBase(O: *this, DRI); |
1832 | return 1 << MachO::GET_COMM_ALIGN(n_desc: Entry.n_desc); |
1833 | } |
1834 | return 0; |
1835 | } |
1836 | |
1837 | uint64_t MachOObjectFile::getCommonSymbolSizeImpl(DataRefImpl DRI) const { |
1838 | return getNValue(Sym: DRI); |
1839 | } |
1840 | |
1841 | Expected<SymbolRef::Type> |
1842 | MachOObjectFile::getSymbolType(DataRefImpl Symb) const { |
1843 | MachO::nlist_base Entry = getSymbolTableEntryBase(O: *this, DRI: Symb); |
1844 | uint8_t n_type = Entry.n_type; |
1845 | |
1846 | // If this is a STAB debugging symbol, we can do nothing more. |
1847 | if (n_type & MachO::N_STAB) |
1848 | return SymbolRef::ST_Debug; |
1849 | |
1850 | switch (n_type & MachO::N_TYPE) { |
1851 | case MachO::N_UNDF : |
1852 | return SymbolRef::ST_Unknown; |
1853 | case MachO::N_SECT : |
1854 | Expected<section_iterator> SecOrError = getSymbolSection(Symb); |
1855 | if (!SecOrError) |
1856 | return SecOrError.takeError(); |
1857 | section_iterator Sec = *SecOrError; |
1858 | if (Sec == section_end()) |
1859 | return SymbolRef::ST_Other; |
1860 | if (Sec->isData() || Sec->isBSS()) |
1861 | return SymbolRef::ST_Data; |
1862 | return SymbolRef::ST_Function; |
1863 | } |
1864 | return SymbolRef::ST_Other; |
1865 | } |
1866 | |
1867 | Expected<uint32_t> MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const { |
1868 | MachO::nlist_base Entry = getSymbolTableEntryBase(O: *this, DRI); |
1869 | |
1870 | uint8_t MachOType = Entry.n_type; |
1871 | uint16_t MachOFlags = Entry.n_desc; |
1872 | |
1873 | uint32_t Result = SymbolRef::SF_None; |
1874 | |
1875 | if ((MachOType & MachO::N_TYPE) == MachO::N_INDR) |
1876 | Result |= SymbolRef::SF_Indirect; |
1877 | |
1878 | if (MachOType & MachO::N_STAB) |
1879 | Result |= SymbolRef::SF_FormatSpecific; |
1880 | |
1881 | if (MachOType & MachO::N_EXT) { |
1882 | Result |= SymbolRef::SF_Global; |
1883 | if ((MachOType & MachO::N_TYPE) == MachO::N_UNDF) { |
1884 | if (getNValue(Sym: DRI)) |
1885 | Result |= SymbolRef::SF_Common; |
1886 | else |
1887 | Result |= SymbolRef::SF_Undefined; |
1888 | } |
1889 | |
1890 | if (MachOType & MachO::N_PEXT) |
1891 | Result |= SymbolRef::SF_Hidden; |
1892 | else |
1893 | Result |= SymbolRef::SF_Exported; |
1894 | |
1895 | } else if (MachOType & MachO::N_PEXT) |
1896 | Result |= SymbolRef::SF_Hidden; |
1897 | |
1898 | if (MachOFlags & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF)) |
1899 | Result |= SymbolRef::SF_Weak; |
1900 | |
1901 | if (MachOFlags & (MachO::N_ARM_THUMB_DEF)) |
1902 | Result |= SymbolRef::SF_Thumb; |
1903 | |
1904 | if ((MachOType & MachO::N_TYPE) == MachO::N_ABS) |
1905 | Result |= SymbolRef::SF_Absolute; |
1906 | |
1907 | return Result; |
1908 | } |
1909 | |
1910 | Expected<section_iterator> |
1911 | MachOObjectFile::getSymbolSection(DataRefImpl Symb) const { |
1912 | MachO::nlist_base Entry = getSymbolTableEntryBase(O: *this, DRI: Symb); |
1913 | uint8_t index = Entry.n_sect; |
1914 | |
1915 | if (index == 0) |
1916 | return section_end(); |
1917 | DataRefImpl DRI; |
1918 | DRI.d.a = index - 1; |
1919 | if (DRI.d.a >= Sections.size()){ |
1920 | return malformedError(Msg: "bad section index: " + Twine((int)index) + |
1921 | " for symbol at index " + Twine(getSymbolIndex(Symb))); |
1922 | } |
1923 | return section_iterator(SectionRef(DRI, this)); |
1924 | } |
1925 | |
1926 | unsigned MachOObjectFile::getSymbolSectionID(SymbolRef Sym) const { |
1927 | MachO::nlist_base Entry = |
1928 | getSymbolTableEntryBase(O: *this, DRI: Sym.getRawDataRefImpl()); |
1929 | return Entry.n_sect - 1; |
1930 | } |
1931 | |
1932 | void MachOObjectFile::moveSectionNext(DataRefImpl &Sec) const { |
1933 | Sec.d.a++; |
1934 | } |
1935 | |
1936 | Expected<StringRef> MachOObjectFile::getSectionName(DataRefImpl Sec) const { |
1937 | ArrayRef<char> Raw = getSectionRawName(Sec); |
1938 | return parseSegmentOrSectionName(P: Raw.data()); |
1939 | } |
1940 | |
1941 | uint64_t MachOObjectFile::getSectionAddress(DataRefImpl Sec) const { |
1942 | if (is64Bit()) |
1943 | return getSection64(DRI: Sec).addr; |
1944 | return getSection(DRI: Sec).addr; |
1945 | } |
1946 | |
1947 | uint64_t MachOObjectFile::getSectionIndex(DataRefImpl Sec) const { |
1948 | return Sec.d.a; |
1949 | } |
1950 | |
1951 | uint64_t MachOObjectFile::getSectionSize(DataRefImpl Sec) const { |
1952 | // In the case if a malformed Mach-O file where the section offset is past |
1953 | // the end of the file or some part of the section size is past the end of |
1954 | // the file return a size of zero or a size that covers the rest of the file |
1955 | // but does not extend past the end of the file. |
1956 | uint32_t SectOffset, SectType; |
1957 | uint64_t SectSize; |
1958 | |
1959 | if (is64Bit()) { |
1960 | MachO::section_64 Sect = getSection64(DRI: Sec); |
1961 | SectOffset = Sect.offset; |
1962 | SectSize = Sect.size; |
1963 | SectType = Sect.flags & MachO::SECTION_TYPE; |
1964 | } else { |
1965 | MachO::section Sect = getSection(DRI: Sec); |
1966 | SectOffset = Sect.offset; |
1967 | SectSize = Sect.size; |
1968 | SectType = Sect.flags & MachO::SECTION_TYPE; |
1969 | } |
1970 | if (SectType == MachO::S_ZEROFILL || SectType == MachO::S_GB_ZEROFILL) |
1971 | return SectSize; |
1972 | uint64_t FileSize = getData().size(); |
1973 | if (SectOffset > FileSize) |
1974 | return 0; |
1975 | if (FileSize - SectOffset < SectSize) |
1976 | return FileSize - SectOffset; |
1977 | return SectSize; |
1978 | } |
1979 | |
1980 | ArrayRef<uint8_t> MachOObjectFile::getSectionContents(uint32_t Offset, |
1981 | uint64_t Size) const { |
1982 | return arrayRefFromStringRef(Input: getData().substr(Start: Offset, N: Size)); |
1983 | } |
1984 | |
1985 | Expected<ArrayRef<uint8_t>> |
1986 | MachOObjectFile::getSectionContents(DataRefImpl Sec) const { |
1987 | uint32_t Offset; |
1988 | uint64_t Size; |
1989 | |
1990 | if (is64Bit()) { |
1991 | MachO::section_64 Sect = getSection64(DRI: Sec); |
1992 | Offset = Sect.offset; |
1993 | Size = Sect.size; |
1994 | } else { |
1995 | MachO::section Sect = getSection(DRI: Sec); |
1996 | Offset = Sect.offset; |
1997 | Size = Sect.size; |
1998 | } |
1999 | |
2000 | return getSectionContents(Offset, Size); |
2001 | } |
2002 | |
2003 | uint64_t MachOObjectFile::getSectionAlignment(DataRefImpl Sec) const { |
2004 | uint32_t Align; |
2005 | if (is64Bit()) { |
2006 | MachO::section_64 Sect = getSection64(DRI: Sec); |
2007 | Align = Sect.align; |
2008 | } else { |
2009 | MachO::section Sect = getSection(DRI: Sec); |
2010 | Align = Sect.align; |
2011 | } |
2012 | |
2013 | return uint64_t(1) << Align; |
2014 | } |
2015 | |
2016 | Expected<SectionRef> MachOObjectFile::getSection(unsigned SectionIndex) const { |
2017 | if (SectionIndex < 1 || SectionIndex > Sections.size()) |
2018 | return malformedError(Msg: "bad section index: " + Twine((int)SectionIndex)); |
2019 | |
2020 | DataRefImpl DRI; |
2021 | DRI.d.a = SectionIndex - 1; |
2022 | return SectionRef(DRI, this); |
2023 | } |
2024 | |
2025 | Expected<SectionRef> MachOObjectFile::getSection(StringRef SectionName) const { |
2026 | for (const SectionRef &Section : sections()) { |
2027 | auto NameOrErr = Section.getName(); |
2028 | if (!NameOrErr) |
2029 | return NameOrErr.takeError(); |
2030 | if (*NameOrErr == SectionName) |
2031 | return Section; |
2032 | } |
2033 | return errorCodeToError(EC: object_error::parse_failed); |
2034 | } |
2035 | |
2036 | bool MachOObjectFile::isSectionCompressed(DataRefImpl Sec) const { |
2037 | return false; |
2038 | } |
2039 | |
2040 | bool MachOObjectFile::isSectionText(DataRefImpl Sec) const { |
2041 | uint32_t Flags = getSectionFlags(O: *this, Sec); |
2042 | return Flags & MachO::S_ATTR_PURE_INSTRUCTIONS; |
2043 | } |
2044 | |
2045 | bool MachOObjectFile::isSectionData(DataRefImpl Sec) const { |
2046 | uint32_t Flags = getSectionFlags(O: *this, Sec); |
2047 | unsigned SectionType = Flags & MachO::SECTION_TYPE; |
2048 | return !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) && |
2049 | !(SectionType == MachO::S_ZEROFILL || |
2050 | SectionType == MachO::S_GB_ZEROFILL); |
2051 | } |
2052 | |
2053 | bool MachOObjectFile::isSectionBSS(DataRefImpl Sec) const { |
2054 | uint32_t Flags = getSectionFlags(O: *this, Sec); |
2055 | unsigned SectionType = Flags & MachO::SECTION_TYPE; |
2056 | return !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) && |
2057 | (SectionType == MachO::S_ZEROFILL || |
2058 | SectionType == MachO::S_GB_ZEROFILL); |
2059 | } |
2060 | |
2061 | bool MachOObjectFile::isDebugSection(DataRefImpl Sec) const { |
2062 | Expected<StringRef> SectionNameOrErr = getSectionName(Sec); |
2063 | if (!SectionNameOrErr) { |
2064 | // TODO: Report the error message properly. |
2065 | consumeError(Err: SectionNameOrErr.takeError()); |
2066 | return false; |
2067 | } |
2068 | StringRef SectionName = SectionNameOrErr.get(); |
2069 | return SectionName.starts_with(Prefix: "__debug" ) || |
2070 | SectionName.starts_with(Prefix: "__zdebug" ) || |
2071 | SectionName.starts_with(Prefix: "__apple" ) || SectionName == "__gdb_index" || |
2072 | SectionName == "__swift_ast" ; |
2073 | } |
2074 | |
2075 | namespace { |
2076 | template <typename LoadCommandType> |
2077 | ArrayRef<uint8_t> getSegmentContents(const MachOObjectFile &Obj, |
2078 | MachOObjectFile::LoadCommandInfo LoadCmd, |
2079 | StringRef SegmentName) { |
2080 | auto SegmentOrErr = getStructOrErr<LoadCommandType>(Obj, LoadCmd.Ptr); |
2081 | if (!SegmentOrErr) { |
2082 | consumeError(SegmentOrErr.takeError()); |
2083 | return {}; |
2084 | } |
2085 | auto &Segment = SegmentOrErr.get(); |
2086 | if (StringRef(Segment.segname, 16).starts_with(Prefix: SegmentName)) |
2087 | return arrayRefFromStringRef(Obj.getData().slice( |
2088 | Start: Segment.fileoff, End: Segment.fileoff + Segment.filesize)); |
2089 | return {}; |
2090 | } |
2091 | |
2092 | template <typename LoadCommandType> |
2093 | ArrayRef<uint8_t> getSegmentContents(const MachOObjectFile &Obj, |
2094 | MachOObjectFile::LoadCommandInfo LoadCmd) { |
2095 | auto SegmentOrErr = getStructOrErr<LoadCommandType>(Obj, LoadCmd.Ptr); |
2096 | if (!SegmentOrErr) { |
2097 | consumeError(SegmentOrErr.takeError()); |
2098 | return {}; |
2099 | } |
2100 | auto &Segment = SegmentOrErr.get(); |
2101 | return arrayRefFromStringRef( |
2102 | Obj.getData().slice(Start: Segment.fileoff, End: Segment.fileoff + Segment.filesize)); |
2103 | } |
2104 | } // namespace |
2105 | |
2106 | ArrayRef<uint8_t> |
2107 | MachOObjectFile::getSegmentContents(StringRef SegmentName) const { |
2108 | for (auto LoadCmd : load_commands()) { |
2109 | ArrayRef<uint8_t> Contents; |
2110 | switch (LoadCmd.C.cmd) { |
2111 | case MachO::LC_SEGMENT: |
2112 | Contents = ::getSegmentContents<MachO::segment_command>(Obj: *this, LoadCmd, |
2113 | SegmentName); |
2114 | break; |
2115 | case MachO::LC_SEGMENT_64: |
2116 | Contents = ::getSegmentContents<MachO::segment_command_64>(Obj: *this, LoadCmd, |
2117 | SegmentName); |
2118 | break; |
2119 | default: |
2120 | continue; |
2121 | } |
2122 | if (!Contents.empty()) |
2123 | return Contents; |
2124 | } |
2125 | return {}; |
2126 | } |
2127 | |
2128 | ArrayRef<uint8_t> |
2129 | MachOObjectFile::getSegmentContents(size_t SegmentIndex) const { |
2130 | size_t Idx = 0; |
2131 | for (auto LoadCmd : load_commands()) { |
2132 | switch (LoadCmd.C.cmd) { |
2133 | case MachO::LC_SEGMENT: |
2134 | if (Idx == SegmentIndex) |
2135 | return ::getSegmentContents<MachO::segment_command>(Obj: *this, LoadCmd); |
2136 | ++Idx; |
2137 | break; |
2138 | case MachO::LC_SEGMENT_64: |
2139 | if (Idx == SegmentIndex) |
2140 | return ::getSegmentContents<MachO::segment_command_64>(Obj: *this, LoadCmd); |
2141 | ++Idx; |
2142 | break; |
2143 | default: |
2144 | continue; |
2145 | } |
2146 | } |
2147 | return {}; |
2148 | } |
2149 | |
2150 | unsigned MachOObjectFile::getSectionID(SectionRef Sec) const { |
2151 | return Sec.getRawDataRefImpl().d.a; |
2152 | } |
2153 | |
2154 | bool MachOObjectFile::isSectionVirtual(DataRefImpl Sec) const { |
2155 | uint32_t Flags = getSectionFlags(O: *this, Sec); |
2156 | unsigned SectionType = Flags & MachO::SECTION_TYPE; |
2157 | return SectionType == MachO::S_ZEROFILL || |
2158 | SectionType == MachO::S_GB_ZEROFILL; |
2159 | } |
2160 | |
2161 | bool MachOObjectFile::isSectionBitcode(DataRefImpl Sec) const { |
2162 | StringRef SegmentName = getSectionFinalSegmentName(Sec); |
2163 | if (Expected<StringRef> NameOrErr = getSectionName(Sec)) |
2164 | return (SegmentName == "__LLVM" && *NameOrErr == "__bitcode" ); |
2165 | return false; |
2166 | } |
2167 | |
2168 | bool MachOObjectFile::isSectionStripped(DataRefImpl Sec) const { |
2169 | if (is64Bit()) |
2170 | return getSection64(DRI: Sec).offset == 0; |
2171 | return getSection(DRI: Sec).offset == 0; |
2172 | } |
2173 | |
2174 | relocation_iterator MachOObjectFile::section_rel_begin(DataRefImpl Sec) const { |
2175 | DataRefImpl Ret; |
2176 | Ret.d.a = Sec.d.a; |
2177 | Ret.d.b = 0; |
2178 | return relocation_iterator(RelocationRef(Ret, this)); |
2179 | } |
2180 | |
2181 | relocation_iterator |
2182 | MachOObjectFile::section_rel_end(DataRefImpl Sec) const { |
2183 | uint32_t Num; |
2184 | if (is64Bit()) { |
2185 | MachO::section_64 Sect = getSection64(DRI: Sec); |
2186 | Num = Sect.nreloc; |
2187 | } else { |
2188 | MachO::section Sect = getSection(DRI: Sec); |
2189 | Num = Sect.nreloc; |
2190 | } |
2191 | |
2192 | DataRefImpl Ret; |
2193 | Ret.d.a = Sec.d.a; |
2194 | Ret.d.b = Num; |
2195 | return relocation_iterator(RelocationRef(Ret, this)); |
2196 | } |
2197 | |
2198 | relocation_iterator MachOObjectFile::extrel_begin() const { |
2199 | DataRefImpl Ret; |
2200 | // for DYSYMTAB symbols, Ret.d.a == 0 for external relocations |
2201 | Ret.d.a = 0; // Would normally be a section index. |
2202 | Ret.d.b = 0; // Index into the external relocations |
2203 | return relocation_iterator(RelocationRef(Ret, this)); |
2204 | } |
2205 | |
2206 | relocation_iterator MachOObjectFile::extrel_end() const { |
2207 | MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand(); |
2208 | DataRefImpl Ret; |
2209 | // for DYSYMTAB symbols, Ret.d.a == 0 for external relocations |
2210 | Ret.d.a = 0; // Would normally be a section index. |
2211 | Ret.d.b = DysymtabLoadCmd.nextrel; // Index into the external relocations |
2212 | return relocation_iterator(RelocationRef(Ret, this)); |
2213 | } |
2214 | |
2215 | relocation_iterator MachOObjectFile::locrel_begin() const { |
2216 | DataRefImpl Ret; |
2217 | // for DYSYMTAB symbols, Ret.d.a == 1 for local relocations |
2218 | Ret.d.a = 1; // Would normally be a section index. |
2219 | Ret.d.b = 0; // Index into the local relocations |
2220 | return relocation_iterator(RelocationRef(Ret, this)); |
2221 | } |
2222 | |
2223 | relocation_iterator MachOObjectFile::locrel_end() const { |
2224 | MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand(); |
2225 | DataRefImpl Ret; |
2226 | // for DYSYMTAB symbols, Ret.d.a == 1 for local relocations |
2227 | Ret.d.a = 1; // Would normally be a section index. |
2228 | Ret.d.b = DysymtabLoadCmd.nlocrel; // Index into the local relocations |
2229 | return relocation_iterator(RelocationRef(Ret, this)); |
2230 | } |
2231 | |
2232 | void MachOObjectFile::moveRelocationNext(DataRefImpl &Rel) const { |
2233 | ++Rel.d.b; |
2234 | } |
2235 | |
2236 | uint64_t MachOObjectFile::getRelocationOffset(DataRefImpl Rel) const { |
2237 | assert((getHeader().filetype == MachO::MH_OBJECT || |
2238 | getHeader().filetype == MachO::MH_KEXT_BUNDLE) && |
2239 | "Only implemented for MH_OBJECT && MH_KEXT_BUNDLE" ); |
2240 | MachO::any_relocation_info RE = getRelocation(Rel); |
2241 | return getAnyRelocationAddress(RE); |
2242 | } |
2243 | |
2244 | symbol_iterator |
2245 | MachOObjectFile::getRelocationSymbol(DataRefImpl Rel) const { |
2246 | MachO::any_relocation_info RE = getRelocation(Rel); |
2247 | if (isRelocationScattered(RE)) |
2248 | return symbol_end(); |
2249 | |
2250 | uint32_t SymbolIdx = getPlainRelocationSymbolNum(RE); |
2251 | bool isExtern = getPlainRelocationExternal(RE); |
2252 | if (!isExtern) |
2253 | return symbol_end(); |
2254 | |
2255 | MachO::symtab_command S = getSymtabLoadCommand(); |
2256 | unsigned SymbolTableEntrySize = is64Bit() ? |
2257 | sizeof(MachO::nlist_64) : |
2258 | sizeof(MachO::nlist); |
2259 | uint64_t Offset = S.symoff + SymbolIdx * SymbolTableEntrySize; |
2260 | DataRefImpl Sym; |
2261 | Sym.p = reinterpret_cast<uintptr_t>(getPtr(O: *this, Offset)); |
2262 | return symbol_iterator(SymbolRef(Sym, this)); |
2263 | } |
2264 | |
2265 | section_iterator |
2266 | MachOObjectFile::getRelocationSection(DataRefImpl Rel) const { |
2267 | return section_iterator(getAnyRelocationSection(RE: getRelocation(Rel))); |
2268 | } |
2269 | |
2270 | uint64_t MachOObjectFile::getRelocationType(DataRefImpl Rel) const { |
2271 | MachO::any_relocation_info RE = getRelocation(Rel); |
2272 | return getAnyRelocationType(RE); |
2273 | } |
2274 | |
2275 | void MachOObjectFile::getRelocationTypeName( |
2276 | DataRefImpl Rel, SmallVectorImpl<char> &Result) const { |
2277 | StringRef res; |
2278 | uint64_t RType = getRelocationType(Rel); |
2279 | |
2280 | unsigned Arch = this->getArch(); |
2281 | |
2282 | switch (Arch) { |
2283 | case Triple::x86: { |
2284 | static const char *const Table[] = { |
2285 | "GENERIC_RELOC_VANILLA" , |
2286 | "GENERIC_RELOC_PAIR" , |
2287 | "GENERIC_RELOC_SECTDIFF" , |
2288 | "GENERIC_RELOC_PB_LA_PTR" , |
2289 | "GENERIC_RELOC_LOCAL_SECTDIFF" , |
2290 | "GENERIC_RELOC_TLV" }; |
2291 | |
2292 | if (RType > 5) |
2293 | res = "Unknown" ; |
2294 | else |
2295 | res = Table[RType]; |
2296 | break; |
2297 | } |
2298 | case Triple::x86_64: { |
2299 | static const char *const Table[] = { |
2300 | "X86_64_RELOC_UNSIGNED" , |
2301 | "X86_64_RELOC_SIGNED" , |
2302 | "X86_64_RELOC_BRANCH" , |
2303 | "X86_64_RELOC_GOT_LOAD" , |
2304 | "X86_64_RELOC_GOT" , |
2305 | "X86_64_RELOC_SUBTRACTOR" , |
2306 | "X86_64_RELOC_SIGNED_1" , |
2307 | "X86_64_RELOC_SIGNED_2" , |
2308 | "X86_64_RELOC_SIGNED_4" , |
2309 | "X86_64_RELOC_TLV" }; |
2310 | |
2311 | if (RType > 9) |
2312 | res = "Unknown" ; |
2313 | else |
2314 | res = Table[RType]; |
2315 | break; |
2316 | } |
2317 | case Triple::arm: { |
2318 | static const char *const Table[] = { |
2319 | "ARM_RELOC_VANILLA" , |
2320 | "ARM_RELOC_PAIR" , |
2321 | "ARM_RELOC_SECTDIFF" , |
2322 | "ARM_RELOC_LOCAL_SECTDIFF" , |
2323 | "ARM_RELOC_PB_LA_PTR" , |
2324 | "ARM_RELOC_BR24" , |
2325 | "ARM_THUMB_RELOC_BR22" , |
2326 | "ARM_THUMB_32BIT_BRANCH" , |
2327 | "ARM_RELOC_HALF" , |
2328 | "ARM_RELOC_HALF_SECTDIFF" }; |
2329 | |
2330 | if (RType > 9) |
2331 | res = "Unknown" ; |
2332 | else |
2333 | res = Table[RType]; |
2334 | break; |
2335 | } |
2336 | case Triple::aarch64: |
2337 | case Triple::aarch64_32: { |
2338 | static const char *const Table[] = { |
2339 | "ARM64_RELOC_UNSIGNED" , "ARM64_RELOC_SUBTRACTOR" , |
2340 | "ARM64_RELOC_BRANCH26" , "ARM64_RELOC_PAGE21" , |
2341 | "ARM64_RELOC_PAGEOFF12" , "ARM64_RELOC_GOT_LOAD_PAGE21" , |
2342 | "ARM64_RELOC_GOT_LOAD_PAGEOFF12" , "ARM64_RELOC_POINTER_TO_GOT" , |
2343 | "ARM64_RELOC_TLVP_LOAD_PAGE21" , "ARM64_RELOC_TLVP_LOAD_PAGEOFF12" , |
2344 | "ARM64_RELOC_ADDEND" |
2345 | }; |
2346 | |
2347 | if (RType >= std::size(Table)) |
2348 | res = "Unknown" ; |
2349 | else |
2350 | res = Table[RType]; |
2351 | break; |
2352 | } |
2353 | case Triple::ppc: { |
2354 | static const char *const Table[] = { |
2355 | "PPC_RELOC_VANILLA" , |
2356 | "PPC_RELOC_PAIR" , |
2357 | "PPC_RELOC_BR14" , |
2358 | "PPC_RELOC_BR24" , |
2359 | "PPC_RELOC_HI16" , |
2360 | "PPC_RELOC_LO16" , |
2361 | "PPC_RELOC_HA16" , |
2362 | "PPC_RELOC_LO14" , |
2363 | "PPC_RELOC_SECTDIFF" , |
2364 | "PPC_RELOC_PB_LA_PTR" , |
2365 | "PPC_RELOC_HI16_SECTDIFF" , |
2366 | "PPC_RELOC_LO16_SECTDIFF" , |
2367 | "PPC_RELOC_HA16_SECTDIFF" , |
2368 | "PPC_RELOC_JBSR" , |
2369 | "PPC_RELOC_LO14_SECTDIFF" , |
2370 | "PPC_RELOC_LOCAL_SECTDIFF" }; |
2371 | |
2372 | if (RType > 15) |
2373 | res = "Unknown" ; |
2374 | else |
2375 | res = Table[RType]; |
2376 | break; |
2377 | } |
2378 | case Triple::UnknownArch: |
2379 | res = "Unknown" ; |
2380 | break; |
2381 | } |
2382 | Result.append(in_start: res.begin(), in_end: res.end()); |
2383 | } |
2384 | |
2385 | uint8_t MachOObjectFile::getRelocationLength(DataRefImpl Rel) const { |
2386 | MachO::any_relocation_info RE = getRelocation(Rel); |
2387 | return getAnyRelocationLength(RE); |
2388 | } |
2389 | |
2390 | // |
2391 | // guessLibraryShortName() is passed a name of a dynamic library and returns a |
2392 | // guess on what the short name is. Then name is returned as a substring of the |
2393 | // StringRef Name passed in. The name of the dynamic library is recognized as |
2394 | // a framework if it has one of the two following forms: |
2395 | // Foo.framework/Versions/A/Foo |
2396 | // Foo.framework/Foo |
2397 | // Where A and Foo can be any string. And may contain a trailing suffix |
2398 | // starting with an underbar. If the Name is recognized as a framework then |
2399 | // isFramework is set to true else it is set to false. If the Name has a |
2400 | // suffix then Suffix is set to the substring in Name that contains the suffix |
2401 | // else it is set to a NULL StringRef. |
2402 | // |
2403 | // The Name of the dynamic library is recognized as a library name if it has |
2404 | // one of the two following forms: |
2405 | // libFoo.A.dylib |
2406 | // libFoo.dylib |
2407 | // |
2408 | // The library may have a suffix trailing the name Foo of the form: |
2409 | // libFoo_profile.A.dylib |
2410 | // libFoo_profile.dylib |
2411 | // These dyld image suffixes are separated from the short name by a '_' |
2412 | // character. Because the '_' character is commonly used to separate words in |
2413 | // filenames guessLibraryShortName() cannot reliably separate a dylib's short |
2414 | // name from an arbitrary image suffix; imagine if both the short name and the |
2415 | // suffix contains an '_' character! To better deal with this ambiguity, |
2416 | // guessLibraryShortName() will recognize only "_debug" and "_profile" as valid |
2417 | // Suffix values. Calling code needs to be tolerant of guessLibraryShortName() |
2418 | // guessing incorrectly. |
2419 | // |
2420 | // The Name of the dynamic library is also recognized as a library name if it |
2421 | // has the following form: |
2422 | // Foo.qtx |
2423 | // |
2424 | // If the Name of the dynamic library is none of the forms above then a NULL |
2425 | // StringRef is returned. |
2426 | StringRef MachOObjectFile::guessLibraryShortName(StringRef Name, |
2427 | bool &isFramework, |
2428 | StringRef &Suffix) { |
2429 | StringRef Foo, F, DotFramework, V, Dylib, Lib, Dot, Qtx; |
2430 | size_t a, b, c, d, Idx; |
2431 | |
2432 | isFramework = false; |
2433 | Suffix = StringRef(); |
2434 | |
2435 | // Pull off the last component and make Foo point to it |
2436 | a = Name.rfind(C: '/'); |
2437 | if (a == Name.npos || a == 0) |
2438 | goto guess_library; |
2439 | Foo = Name.slice(Start: a+1, End: Name.npos); |
2440 | |
2441 | // Look for a suffix starting with a '_' |
2442 | Idx = Foo.rfind(C: '_'); |
2443 | if (Idx != Foo.npos && Foo.size() >= 2) { |
2444 | Suffix = Foo.slice(Start: Idx, End: Foo.npos); |
2445 | if (Suffix != "_debug" && Suffix != "_profile" ) |
2446 | Suffix = StringRef(); |
2447 | else |
2448 | Foo = Foo.slice(Start: 0, End: Idx); |
2449 | } |
2450 | |
2451 | // First look for the form Foo.framework/Foo |
2452 | b = Name.rfind(C: '/', From: a); |
2453 | if (b == Name.npos) |
2454 | Idx = 0; |
2455 | else |
2456 | Idx = b+1; |
2457 | F = Name.slice(Start: Idx, End: Idx + Foo.size()); |
2458 | DotFramework = Name.slice(Start: Idx + Foo.size(), |
2459 | End: Idx + Foo.size() + sizeof(".framework/" )-1); |
2460 | if (F == Foo && DotFramework == ".framework/" ) { |
2461 | isFramework = true; |
2462 | return Foo; |
2463 | } |
2464 | |
2465 | // Next look for the form Foo.framework/Versions/A/Foo |
2466 | if (b == Name.npos) |
2467 | goto guess_library; |
2468 | c = Name.rfind(C: '/', From: b); |
2469 | if (c == Name.npos || c == 0) |
2470 | goto guess_library; |
2471 | V = Name.slice(Start: c+1, End: Name.npos); |
2472 | if (!V.starts_with(Prefix: "Versions/" )) |
2473 | goto guess_library; |
2474 | d = Name.rfind(C: '/', From: c); |
2475 | if (d == Name.npos) |
2476 | Idx = 0; |
2477 | else |
2478 | Idx = d+1; |
2479 | F = Name.slice(Start: Idx, End: Idx + Foo.size()); |
2480 | DotFramework = Name.slice(Start: Idx + Foo.size(), |
2481 | End: Idx + Foo.size() + sizeof(".framework/" )-1); |
2482 | if (F == Foo && DotFramework == ".framework/" ) { |
2483 | isFramework = true; |
2484 | return Foo; |
2485 | } |
2486 | |
2487 | guess_library: |
2488 | // pull off the suffix after the "." and make a point to it |
2489 | a = Name.rfind(C: '.'); |
2490 | if (a == Name.npos || a == 0) |
2491 | return StringRef(); |
2492 | Dylib = Name.slice(Start: a, End: Name.npos); |
2493 | if (Dylib != ".dylib" ) |
2494 | goto guess_qtx; |
2495 | |
2496 | // First pull off the version letter for the form Foo.A.dylib if any. |
2497 | if (a >= 3) { |
2498 | Dot = Name.slice(Start: a-2, End: a-1); |
2499 | if (Dot == "." ) |
2500 | a = a - 2; |
2501 | } |
2502 | |
2503 | b = Name.rfind(C: '/', From: a); |
2504 | if (b == Name.npos) |
2505 | b = 0; |
2506 | else |
2507 | b = b+1; |
2508 | // ignore any suffix after an underbar like Foo_profile.A.dylib |
2509 | Idx = Name.rfind(C: '_'); |
2510 | if (Idx != Name.npos && Idx != b) { |
2511 | Lib = Name.slice(Start: b, End: Idx); |
2512 | Suffix = Name.slice(Start: Idx, End: a); |
2513 | if (Suffix != "_debug" && Suffix != "_profile" ) { |
2514 | Suffix = StringRef(); |
2515 | Lib = Name.slice(Start: b, End: a); |
2516 | } |
2517 | } |
2518 | else |
2519 | Lib = Name.slice(Start: b, End: a); |
2520 | // There are incorrect library names of the form: |
2521 | // libATS.A_profile.dylib so check for these. |
2522 | if (Lib.size() >= 3) { |
2523 | Dot = Lib.slice(Start: Lib.size()-2, End: Lib.size()-1); |
2524 | if (Dot == "." ) |
2525 | Lib = Lib.slice(Start: 0, End: Lib.size()-2); |
2526 | } |
2527 | return Lib; |
2528 | |
2529 | guess_qtx: |
2530 | Qtx = Name.slice(Start: a, End: Name.npos); |
2531 | if (Qtx != ".qtx" ) |
2532 | return StringRef(); |
2533 | b = Name.rfind(C: '/', From: a); |
2534 | if (b == Name.npos) |
2535 | Lib = Name.slice(Start: 0, End: a); |
2536 | else |
2537 | Lib = Name.slice(Start: b+1, End: a); |
2538 | // There are library names of the form: QT.A.qtx so check for these. |
2539 | if (Lib.size() >= 3) { |
2540 | Dot = Lib.slice(Start: Lib.size()-2, End: Lib.size()-1); |
2541 | if (Dot == "." ) |
2542 | Lib = Lib.slice(Start: 0, End: Lib.size()-2); |
2543 | } |
2544 | return Lib; |
2545 | } |
2546 | |
2547 | // getLibraryShortNameByIndex() is used to get the short name of the library |
2548 | // for an undefined symbol in a linked Mach-O binary that was linked with the |
2549 | // normal two-level namespace default (that is MH_TWOLEVEL in the header). |
2550 | // It is passed the index (0 - based) of the library as translated from |
2551 | // GET_LIBRARY_ORDINAL (1 - based). |
2552 | std::error_code MachOObjectFile::getLibraryShortNameByIndex(unsigned Index, |
2553 | StringRef &Res) const { |
2554 | if (Index >= Libraries.size()) |
2555 | return object_error::parse_failed; |
2556 | |
2557 | // If the cache of LibrariesShortNames is not built up do that first for |
2558 | // all the Libraries. |
2559 | if (LibrariesShortNames.size() == 0) { |
2560 | for (unsigned i = 0; i < Libraries.size(); i++) { |
2561 | auto CommandOrErr = |
2562 | getStructOrErr<MachO::dylib_command>(O: *this, P: Libraries[i]); |
2563 | if (!CommandOrErr) |
2564 | return object_error::parse_failed; |
2565 | MachO::dylib_command D = CommandOrErr.get(); |
2566 | if (D.dylib.name >= D.cmdsize) |
2567 | return object_error::parse_failed; |
2568 | const char *P = (const char *)(Libraries[i]) + D.dylib.name; |
2569 | StringRef Name = StringRef(P); |
2570 | if (D.dylib.name+Name.size() >= D.cmdsize) |
2571 | return object_error::parse_failed; |
2572 | StringRef Suffix; |
2573 | bool isFramework; |
2574 | StringRef shortName = guessLibraryShortName(Name, isFramework, Suffix); |
2575 | if (shortName.empty()) |
2576 | LibrariesShortNames.push_back(Elt: Name); |
2577 | else |
2578 | LibrariesShortNames.push_back(Elt: shortName); |
2579 | } |
2580 | } |
2581 | |
2582 | Res = LibrariesShortNames[Index]; |
2583 | return std::error_code(); |
2584 | } |
2585 | |
2586 | uint32_t MachOObjectFile::getLibraryCount() const { |
2587 | return Libraries.size(); |
2588 | } |
2589 | |
2590 | section_iterator |
2591 | MachOObjectFile::getRelocationRelocatedSection(relocation_iterator Rel) const { |
2592 | DataRefImpl Sec; |
2593 | Sec.d.a = Rel->getRawDataRefImpl().d.a; |
2594 | return section_iterator(SectionRef(Sec, this)); |
2595 | } |
2596 | |
2597 | basic_symbol_iterator MachOObjectFile::symbol_begin() const { |
2598 | DataRefImpl DRI; |
2599 | MachO::symtab_command Symtab = getSymtabLoadCommand(); |
2600 | if (!SymtabLoadCmd || Symtab.nsyms == 0) |
2601 | return basic_symbol_iterator(SymbolRef(DRI, this)); |
2602 | |
2603 | return getSymbolByIndex(Index: 0); |
2604 | } |
2605 | |
2606 | basic_symbol_iterator MachOObjectFile::symbol_end() const { |
2607 | DataRefImpl DRI; |
2608 | MachO::symtab_command Symtab = getSymtabLoadCommand(); |
2609 | if (!SymtabLoadCmd || Symtab.nsyms == 0) |
2610 | return basic_symbol_iterator(SymbolRef(DRI, this)); |
2611 | |
2612 | unsigned SymbolTableEntrySize = is64Bit() ? |
2613 | sizeof(MachO::nlist_64) : |
2614 | sizeof(MachO::nlist); |
2615 | unsigned Offset = Symtab.symoff + |
2616 | Symtab.nsyms * SymbolTableEntrySize; |
2617 | DRI.p = reinterpret_cast<uintptr_t>(getPtr(O: *this, Offset)); |
2618 | return basic_symbol_iterator(SymbolRef(DRI, this)); |
2619 | } |
2620 | |
2621 | symbol_iterator MachOObjectFile::getSymbolByIndex(unsigned Index) const { |
2622 | MachO::symtab_command Symtab = getSymtabLoadCommand(); |
2623 | if (!SymtabLoadCmd || Index >= Symtab.nsyms) |
2624 | report_fatal_error(reason: "Requested symbol index is out of range." ); |
2625 | unsigned SymbolTableEntrySize = |
2626 | is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist); |
2627 | DataRefImpl DRI; |
2628 | DRI.p = reinterpret_cast<uintptr_t>(getPtr(O: *this, Offset: Symtab.symoff)); |
2629 | DRI.p += Index * SymbolTableEntrySize; |
2630 | return basic_symbol_iterator(SymbolRef(DRI, this)); |
2631 | } |
2632 | |
2633 | uint64_t MachOObjectFile::getSymbolIndex(DataRefImpl Symb) const { |
2634 | MachO::symtab_command Symtab = getSymtabLoadCommand(); |
2635 | if (!SymtabLoadCmd) |
2636 | report_fatal_error(reason: "getSymbolIndex() called with no symbol table symbol" ); |
2637 | unsigned SymbolTableEntrySize = |
2638 | is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist); |
2639 | DataRefImpl DRIstart; |
2640 | DRIstart.p = reinterpret_cast<uintptr_t>(getPtr(O: *this, Offset: Symtab.symoff)); |
2641 | uint64_t Index = (Symb.p - DRIstart.p) / SymbolTableEntrySize; |
2642 | return Index; |
2643 | } |
2644 | |
2645 | section_iterator MachOObjectFile::section_begin() const { |
2646 | DataRefImpl DRI; |
2647 | return section_iterator(SectionRef(DRI, this)); |
2648 | } |
2649 | |
2650 | section_iterator MachOObjectFile::section_end() const { |
2651 | DataRefImpl DRI; |
2652 | DRI.d.a = Sections.size(); |
2653 | return section_iterator(SectionRef(DRI, this)); |
2654 | } |
2655 | |
2656 | uint8_t MachOObjectFile::getBytesInAddress() const { |
2657 | return is64Bit() ? 8 : 4; |
2658 | } |
2659 | |
2660 | StringRef MachOObjectFile::getFileFormatName() const { |
2661 | unsigned CPUType = getCPUType(O: *this); |
2662 | if (!is64Bit()) { |
2663 | switch (CPUType) { |
2664 | case MachO::CPU_TYPE_I386: |
2665 | return "Mach-O 32-bit i386" ; |
2666 | case MachO::CPU_TYPE_ARM: |
2667 | return "Mach-O arm" ; |
2668 | case MachO::CPU_TYPE_ARM64_32: |
2669 | return "Mach-O arm64 (ILP32)" ; |
2670 | case MachO::CPU_TYPE_POWERPC: |
2671 | return "Mach-O 32-bit ppc" ; |
2672 | default: |
2673 | return "Mach-O 32-bit unknown" ; |
2674 | } |
2675 | } |
2676 | |
2677 | switch (CPUType) { |
2678 | case MachO::CPU_TYPE_X86_64: |
2679 | return "Mach-O 64-bit x86-64" ; |
2680 | case MachO::CPU_TYPE_ARM64: |
2681 | return "Mach-O arm64" ; |
2682 | case MachO::CPU_TYPE_POWERPC64: |
2683 | return "Mach-O 64-bit ppc64" ; |
2684 | default: |
2685 | return "Mach-O 64-bit unknown" ; |
2686 | } |
2687 | } |
2688 | |
2689 | Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) { |
2690 | switch (CPUType) { |
2691 | case MachO::CPU_TYPE_I386: |
2692 | return Triple::x86; |
2693 | case MachO::CPU_TYPE_X86_64: |
2694 | return Triple::x86_64; |
2695 | case MachO::CPU_TYPE_ARM: |
2696 | return Triple::arm; |
2697 | case MachO::CPU_TYPE_ARM64: |
2698 | return Triple::aarch64; |
2699 | case MachO::CPU_TYPE_ARM64_32: |
2700 | return Triple::aarch64_32; |
2701 | case MachO::CPU_TYPE_POWERPC: |
2702 | return Triple::ppc; |
2703 | case MachO::CPU_TYPE_POWERPC64: |
2704 | return Triple::ppc64; |
2705 | default: |
2706 | return Triple::UnknownArch; |
2707 | } |
2708 | } |
2709 | |
2710 | Triple MachOObjectFile::getArchTriple(uint32_t CPUType, uint32_t CPUSubType, |
2711 | const char **McpuDefault, |
2712 | const char **ArchFlag) { |
2713 | if (McpuDefault) |
2714 | *McpuDefault = nullptr; |
2715 | if (ArchFlag) |
2716 | *ArchFlag = nullptr; |
2717 | |
2718 | switch (CPUType) { |
2719 | case MachO::CPU_TYPE_I386: |
2720 | switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { |
2721 | case MachO::CPU_SUBTYPE_I386_ALL: |
2722 | if (ArchFlag) |
2723 | *ArchFlag = "i386" ; |
2724 | return Triple("i386-apple-darwin" ); |
2725 | default: |
2726 | return Triple(); |
2727 | } |
2728 | case MachO::CPU_TYPE_X86_64: |
2729 | switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { |
2730 | case MachO::CPU_SUBTYPE_X86_64_ALL: |
2731 | if (ArchFlag) |
2732 | *ArchFlag = "x86_64" ; |
2733 | return Triple("x86_64-apple-darwin" ); |
2734 | case MachO::CPU_SUBTYPE_X86_64_H: |
2735 | if (ArchFlag) |
2736 | *ArchFlag = "x86_64h" ; |
2737 | return Triple("x86_64h-apple-darwin" ); |
2738 | default: |
2739 | return Triple(); |
2740 | } |
2741 | case MachO::CPU_TYPE_ARM: |
2742 | switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { |
2743 | case MachO::CPU_SUBTYPE_ARM_V4T: |
2744 | if (ArchFlag) |
2745 | *ArchFlag = "armv4t" ; |
2746 | return Triple("armv4t-apple-darwin" ); |
2747 | case MachO::CPU_SUBTYPE_ARM_V5TEJ: |
2748 | if (ArchFlag) |
2749 | *ArchFlag = "armv5e" ; |
2750 | return Triple("armv5e-apple-darwin" ); |
2751 | case MachO::CPU_SUBTYPE_ARM_XSCALE: |
2752 | if (ArchFlag) |
2753 | *ArchFlag = "xscale" ; |
2754 | return Triple("xscale-apple-darwin" ); |
2755 | case MachO::CPU_SUBTYPE_ARM_V6: |
2756 | if (ArchFlag) |
2757 | *ArchFlag = "armv6" ; |
2758 | return Triple("armv6-apple-darwin" ); |
2759 | case MachO::CPU_SUBTYPE_ARM_V6M: |
2760 | if (McpuDefault) |
2761 | *McpuDefault = "cortex-m0" ; |
2762 | if (ArchFlag) |
2763 | *ArchFlag = "armv6m" ; |
2764 | return Triple("armv6m-apple-darwin" ); |
2765 | case MachO::CPU_SUBTYPE_ARM_V7: |
2766 | if (ArchFlag) |
2767 | *ArchFlag = "armv7" ; |
2768 | return Triple("armv7-apple-darwin" ); |
2769 | case MachO::CPU_SUBTYPE_ARM_V7EM: |
2770 | if (McpuDefault) |
2771 | *McpuDefault = "cortex-m4" ; |
2772 | if (ArchFlag) |
2773 | *ArchFlag = "armv7em" ; |
2774 | return Triple("thumbv7em-apple-darwin" ); |
2775 | case MachO::CPU_SUBTYPE_ARM_V7K: |
2776 | if (McpuDefault) |
2777 | *McpuDefault = "cortex-a7" ; |
2778 | if (ArchFlag) |
2779 | *ArchFlag = "armv7k" ; |
2780 | return Triple("armv7k-apple-darwin" ); |
2781 | case MachO::CPU_SUBTYPE_ARM_V7M: |
2782 | if (McpuDefault) |
2783 | *McpuDefault = "cortex-m3" ; |
2784 | if (ArchFlag) |
2785 | *ArchFlag = "armv7m" ; |
2786 | return Triple("thumbv7m-apple-darwin" ); |
2787 | case MachO::CPU_SUBTYPE_ARM_V7S: |
2788 | if (McpuDefault) |
2789 | *McpuDefault = "cortex-a7" ; |
2790 | if (ArchFlag) |
2791 | *ArchFlag = "armv7s" ; |
2792 | return Triple("armv7s-apple-darwin" ); |
2793 | default: |
2794 | return Triple(); |
2795 | } |
2796 | case MachO::CPU_TYPE_ARM64: |
2797 | switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { |
2798 | case MachO::CPU_SUBTYPE_ARM64_ALL: |
2799 | if (McpuDefault) |
2800 | *McpuDefault = "cyclone" ; |
2801 | if (ArchFlag) |
2802 | *ArchFlag = "arm64" ; |
2803 | return Triple("arm64-apple-darwin" ); |
2804 | case MachO::CPU_SUBTYPE_ARM64E: |
2805 | if (McpuDefault) |
2806 | *McpuDefault = "apple-a12" ; |
2807 | if (ArchFlag) |
2808 | *ArchFlag = "arm64e" ; |
2809 | return Triple("arm64e-apple-darwin" ); |
2810 | default: |
2811 | return Triple(); |
2812 | } |
2813 | case MachO::CPU_TYPE_ARM64_32: |
2814 | switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { |
2815 | case MachO::CPU_SUBTYPE_ARM64_32_V8: |
2816 | if (McpuDefault) |
2817 | *McpuDefault = "cyclone" ; |
2818 | if (ArchFlag) |
2819 | *ArchFlag = "arm64_32" ; |
2820 | return Triple("arm64_32-apple-darwin" ); |
2821 | default: |
2822 | return Triple(); |
2823 | } |
2824 | case MachO::CPU_TYPE_POWERPC: |
2825 | switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { |
2826 | case MachO::CPU_SUBTYPE_POWERPC_ALL: |
2827 | if (ArchFlag) |
2828 | *ArchFlag = "ppc" ; |
2829 | return Triple("ppc-apple-darwin" ); |
2830 | default: |
2831 | return Triple(); |
2832 | } |
2833 | case MachO::CPU_TYPE_POWERPC64: |
2834 | switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { |
2835 | case MachO::CPU_SUBTYPE_POWERPC_ALL: |
2836 | if (ArchFlag) |
2837 | *ArchFlag = "ppc64" ; |
2838 | return Triple("ppc64-apple-darwin" ); |
2839 | default: |
2840 | return Triple(); |
2841 | } |
2842 | default: |
2843 | return Triple(); |
2844 | } |
2845 | } |
2846 | |
2847 | Triple MachOObjectFile::getHostArch() { |
2848 | return Triple(sys::getDefaultTargetTriple()); |
2849 | } |
2850 | |
2851 | bool MachOObjectFile::isValidArch(StringRef ArchFlag) { |
2852 | auto validArchs = getValidArchs(); |
2853 | return llvm::is_contained(Range&: validArchs, Element: ArchFlag); |
2854 | } |
2855 | |
2856 | ArrayRef<StringRef> MachOObjectFile::getValidArchs() { |
2857 | static const std::array<StringRef, 18> ValidArchs = {._M_elems: { |
2858 | "i386" , |
2859 | "x86_64" , |
2860 | "x86_64h" , |
2861 | "armv4t" , |
2862 | "arm" , |
2863 | "armv5e" , |
2864 | "armv6" , |
2865 | "armv6m" , |
2866 | "armv7" , |
2867 | "armv7em" , |
2868 | "armv7k" , |
2869 | "armv7m" , |
2870 | "armv7s" , |
2871 | "arm64" , |
2872 | "arm64e" , |
2873 | "arm64_32" , |
2874 | "ppc" , |
2875 | "ppc64" , |
2876 | }}; |
2877 | |
2878 | return ValidArchs; |
2879 | } |
2880 | |
2881 | Triple::ArchType MachOObjectFile::getArch() const { |
2882 | return getArch(CPUType: getCPUType(O: *this), CPUSubType: getCPUSubType(O: *this)); |
2883 | } |
2884 | |
2885 | Triple MachOObjectFile::getArchTriple(const char **McpuDefault) const { |
2886 | return getArchTriple(CPUType: Header.cputype, CPUSubType: Header.cpusubtype, McpuDefault); |
2887 | } |
2888 | |
2889 | relocation_iterator MachOObjectFile::section_rel_begin(unsigned Index) const { |
2890 | DataRefImpl DRI; |
2891 | DRI.d.a = Index; |
2892 | return section_rel_begin(Sec: DRI); |
2893 | } |
2894 | |
2895 | relocation_iterator MachOObjectFile::section_rel_end(unsigned Index) const { |
2896 | DataRefImpl DRI; |
2897 | DRI.d.a = Index; |
2898 | return section_rel_end(Sec: DRI); |
2899 | } |
2900 | |
2901 | dice_iterator MachOObjectFile::begin_dices() const { |
2902 | DataRefImpl DRI; |
2903 | if (!DataInCodeLoadCmd) |
2904 | return dice_iterator(DiceRef(DRI, this)); |
2905 | |
2906 | MachO::linkedit_data_command DicLC = getDataInCodeLoadCommand(); |
2907 | DRI.p = reinterpret_cast<uintptr_t>(getPtr(O: *this, Offset: DicLC.dataoff)); |
2908 | return dice_iterator(DiceRef(DRI, this)); |
2909 | } |
2910 | |
2911 | dice_iterator MachOObjectFile::end_dices() const { |
2912 | DataRefImpl DRI; |
2913 | if (!DataInCodeLoadCmd) |
2914 | return dice_iterator(DiceRef(DRI, this)); |
2915 | |
2916 | MachO::linkedit_data_command DicLC = getDataInCodeLoadCommand(); |
2917 | unsigned Offset = DicLC.dataoff + DicLC.datasize; |
2918 | DRI.p = reinterpret_cast<uintptr_t>(getPtr(O: *this, Offset)); |
2919 | return dice_iterator(DiceRef(DRI, this)); |
2920 | } |
2921 | |
2922 | ExportEntry::ExportEntry(Error *E, const MachOObjectFile *O, |
2923 | ArrayRef<uint8_t> T) : E(E), O(O), Trie(T) {} |
2924 | |
2925 | void ExportEntry::moveToFirst() { |
2926 | ErrorAsOutParameter ErrAsOutParam(E); |
2927 | pushNode(Offset: 0); |
2928 | if (*E) |
2929 | return; |
2930 | pushDownUntilBottom(); |
2931 | } |
2932 | |
2933 | void ExportEntry::moveToEnd() { |
2934 | Stack.clear(); |
2935 | Done = true; |
2936 | } |
2937 | |
2938 | bool ExportEntry::operator==(const ExportEntry &Other) const { |
2939 | // Common case, one at end, other iterating from begin. |
2940 | if (Done || Other.Done) |
2941 | return (Done == Other.Done); |
2942 | // Not equal if different stack sizes. |
2943 | if (Stack.size() != Other.Stack.size()) |
2944 | return false; |
2945 | // Not equal if different cumulative strings. |
2946 | if (!CumulativeString.equals(RHS: Other.CumulativeString)) |
2947 | return false; |
2948 | // Equal if all nodes in both stacks match. |
2949 | for (unsigned i=0; i < Stack.size(); ++i) { |
2950 | if (Stack[i].Start != Other.Stack[i].Start) |
2951 | return false; |
2952 | } |
2953 | return true; |
2954 | } |
2955 | |
2956 | uint64_t ExportEntry::readULEB128(const uint8_t *&Ptr, const char **error) { |
2957 | unsigned Count; |
2958 | uint64_t Result = decodeULEB128(p: Ptr, n: &Count, end: Trie.end(), error); |
2959 | Ptr += Count; |
2960 | if (Ptr > Trie.end()) |
2961 | Ptr = Trie.end(); |
2962 | return Result; |
2963 | } |
2964 | |
2965 | StringRef ExportEntry::name() const { |
2966 | return CumulativeString; |
2967 | } |
2968 | |
2969 | uint64_t ExportEntry::flags() const { |
2970 | return Stack.back().Flags; |
2971 | } |
2972 | |
2973 | uint64_t ExportEntry::address() const { |
2974 | return Stack.back().Address; |
2975 | } |
2976 | |
2977 | uint64_t ExportEntry::other() const { |
2978 | return Stack.back().Other; |
2979 | } |
2980 | |
2981 | StringRef ExportEntry::otherName() const { |
2982 | const char* ImportName = Stack.back().ImportName; |
2983 | if (ImportName) |
2984 | return StringRef(ImportName); |
2985 | return StringRef(); |
2986 | } |
2987 | |
2988 | uint32_t ExportEntry::nodeOffset() const { |
2989 | return Stack.back().Start - Trie.begin(); |
2990 | } |
2991 | |
2992 | ExportEntry::NodeState::NodeState(const uint8_t *Ptr) |
2993 | : Start(Ptr), Current(Ptr) {} |
2994 | |
2995 | void ExportEntry::pushNode(uint64_t offset) { |
2996 | ErrorAsOutParameter ErrAsOutParam(E); |
2997 | const uint8_t *Ptr = Trie.begin() + offset; |
2998 | NodeState State(Ptr); |
2999 | const char *error = nullptr; |
3000 | uint64_t ExportInfoSize = readULEB128(Ptr&: State.Current, error: &error); |
3001 | if (error) { |
3002 | *E = malformedError(Msg: "export info size " + Twine(error) + |
3003 | " in export trie data at node: 0x" + |
3004 | Twine::utohexstr(Val: offset)); |
3005 | moveToEnd(); |
3006 | return; |
3007 | } |
3008 | State.IsExportNode = (ExportInfoSize != 0); |
3009 | const uint8_t* Children = State.Current + ExportInfoSize; |
3010 | if (Children > Trie.end()) { |
3011 | *E = malformedError( |
3012 | Msg: "export info size: 0x" + Twine::utohexstr(Val: ExportInfoSize) + |
3013 | " in export trie data at node: 0x" + Twine::utohexstr(Val: offset) + |
3014 | " too big and extends past end of trie data" ); |
3015 | moveToEnd(); |
3016 | return; |
3017 | } |
3018 | if (State.IsExportNode) { |
3019 | const uint8_t *ExportStart = State.Current; |
3020 | State.Flags = readULEB128(Ptr&: State.Current, error: &error); |
3021 | if (error) { |
3022 | *E = malformedError(Msg: "flags " + Twine(error) + |
3023 | " in export trie data at node: 0x" + |
3024 | Twine::utohexstr(Val: offset)); |
3025 | moveToEnd(); |
3026 | return; |
3027 | } |
3028 | uint64_t Kind = State.Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK; |
3029 | if (State.Flags != 0 && |
3030 | (Kind != MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR && |
3031 | Kind != MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE && |
3032 | Kind != MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL)) { |
3033 | *E = malformedError( |
3034 | Msg: "unsupported exported symbol kind: " + Twine((int)Kind) + |
3035 | " in flags: 0x" + Twine::utohexstr(Val: State.Flags) + |
3036 | " in export trie data at node: 0x" + Twine::utohexstr(Val: offset)); |
3037 | moveToEnd(); |
3038 | return; |
3039 | } |
3040 | if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) { |
3041 | State.Address = 0; |
3042 | State.Other = readULEB128(Ptr&: State.Current, error: &error); // dylib ordinal |
3043 | if (error) { |
3044 | *E = malformedError(Msg: "dylib ordinal of re-export " + Twine(error) + |
3045 | " in export trie data at node: 0x" + |
3046 | Twine::utohexstr(Val: offset)); |
3047 | moveToEnd(); |
3048 | return; |
3049 | } |
3050 | if (O != nullptr) { |
3051 | // Only positive numbers represent library ordinals. Zero and negative |
3052 | // numbers have special meaning (see BindSpecialDylib). |
3053 | if ((int64_t)State.Other > 0 && State.Other > O->getLibraryCount()) { |
3054 | *E = malformedError( |
3055 | Msg: "bad library ordinal: " + Twine((int)State.Other) + " (max " + |
3056 | Twine((int)O->getLibraryCount()) + |
3057 | ") in export trie data at node: 0x" + Twine::utohexstr(Val: offset)); |
3058 | moveToEnd(); |
3059 | return; |
3060 | } |
3061 | } |
3062 | State.ImportName = reinterpret_cast<const char*>(State.Current); |
3063 | if (*State.ImportName == '\0') { |
3064 | State.Current++; |
3065 | } else { |
3066 | const uint8_t *End = State.Current + 1; |
3067 | if (End >= Trie.end()) { |
3068 | *E = malformedError(Msg: "import name of re-export in export trie data at " |
3069 | "node: 0x" + |
3070 | Twine::utohexstr(Val: offset) + |
3071 | " starts past end of trie data" ); |
3072 | moveToEnd(); |
3073 | return; |
3074 | } |
3075 | while(*End != '\0' && End < Trie.end()) |
3076 | End++; |
3077 | if (*End != '\0') { |
3078 | *E = malformedError(Msg: "import name of re-export in export trie data at " |
3079 | "node: 0x" + |
3080 | Twine::utohexstr(Val: offset) + |
3081 | " extends past end of trie data" ); |
3082 | moveToEnd(); |
3083 | return; |
3084 | } |
3085 | State.Current = End + 1; |
3086 | } |
3087 | } else { |
3088 | State.Address = readULEB128(Ptr&: State.Current, error: &error); |
3089 | if (error) { |
3090 | *E = malformedError(Msg: "address " + Twine(error) + |
3091 | " in export trie data at node: 0x" + |
3092 | Twine::utohexstr(Val: offset)); |
3093 | moveToEnd(); |
3094 | return; |
3095 | } |
3096 | if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) { |
3097 | State.Other = readULEB128(Ptr&: State.Current, error: &error); |
3098 | if (error) { |
3099 | *E = malformedError(Msg: "resolver of stub and resolver " + Twine(error) + |
3100 | " in export trie data at node: 0x" + |
3101 | Twine::utohexstr(Val: offset)); |
3102 | moveToEnd(); |
3103 | return; |
3104 | } |
3105 | } |
3106 | } |
3107 | if (ExportStart + ExportInfoSize < State.Current) { |
3108 | *E = malformedError( |
3109 | Msg: "inconsistent export info size: 0x" + |
3110 | Twine::utohexstr(Val: ExportInfoSize) + " where actual size was: 0x" + |
3111 | Twine::utohexstr(Val: State.Current - ExportStart) + |
3112 | " in export trie data at node: 0x" + Twine::utohexstr(Val: offset)); |
3113 | moveToEnd(); |
3114 | return; |
3115 | } |
3116 | } |
3117 | State.ChildCount = *Children; |
3118 | if (State.ChildCount != 0 && Children + 1 >= Trie.end()) { |
3119 | *E = malformedError(Msg: "byte for count of childern in export trie data at " |
3120 | "node: 0x" + |
3121 | Twine::utohexstr(Val: offset) + |
3122 | " extends past end of trie data" ); |
3123 | moveToEnd(); |
3124 | return; |
3125 | } |
3126 | State.Current = Children + 1; |
3127 | State.NextChildIndex = 0; |
3128 | State.ParentStringLength = CumulativeString.size(); |
3129 | Stack.push_back(Elt: State); |
3130 | } |
3131 | |
3132 | void ExportEntry::pushDownUntilBottom() { |
3133 | ErrorAsOutParameter ErrAsOutParam(E); |
3134 | const char *error = nullptr; |
3135 | while (Stack.back().NextChildIndex < Stack.back().ChildCount) { |
3136 | NodeState &Top = Stack.back(); |
3137 | CumulativeString.resize(N: Top.ParentStringLength); |
3138 | for (;*Top.Current != 0 && Top.Current < Trie.end(); Top.Current++) { |
3139 | char C = *Top.Current; |
3140 | CumulativeString.push_back(Elt: C); |
3141 | } |
3142 | if (Top.Current >= Trie.end()) { |
3143 | *E = malformedError(Msg: "edge sub-string in export trie data at node: 0x" + |
3144 | Twine::utohexstr(Val: Top.Start - Trie.begin()) + |
3145 | " for child #" + Twine((int)Top.NextChildIndex) + |
3146 | " extends past end of trie data" ); |
3147 | moveToEnd(); |
3148 | return; |
3149 | } |
3150 | Top.Current += 1; |
3151 | uint64_t childNodeIndex = readULEB128(Ptr&: Top.Current, error: &error); |
3152 | if (error) { |
3153 | *E = malformedError(Msg: "child node offset " + Twine(error) + |
3154 | " in export trie data at node: 0x" + |
3155 | Twine::utohexstr(Val: Top.Start - Trie.begin())); |
3156 | moveToEnd(); |
3157 | return; |
3158 | } |
3159 | for (const NodeState &node : nodes()) { |
3160 | if (node.Start == Trie.begin() + childNodeIndex){ |
3161 | *E = malformedError(Msg: "loop in childern in export trie data at node: 0x" + |
3162 | Twine::utohexstr(Val: Top.Start - Trie.begin()) + |
3163 | " back to node: 0x" + |
3164 | Twine::utohexstr(Val: childNodeIndex)); |
3165 | moveToEnd(); |
3166 | return; |
3167 | } |
3168 | } |
3169 | Top.NextChildIndex += 1; |
3170 | pushNode(offset: childNodeIndex); |
3171 | if (*E) |
3172 | return; |
3173 | } |
3174 | if (!Stack.back().IsExportNode) { |
3175 | *E = malformedError(Msg: "node is not an export node in export trie data at " |
3176 | "node: 0x" + |
3177 | Twine::utohexstr(Val: Stack.back().Start - Trie.begin())); |
3178 | moveToEnd(); |
3179 | return; |
3180 | } |
3181 | } |
3182 | |
3183 | // We have a trie data structure and need a way to walk it that is compatible |
3184 | // with the C++ iterator model. The solution is a non-recursive depth first |
3185 | // traversal where the iterator contains a stack of parent nodes along with a |
3186 | // string that is the accumulation of all edge strings along the parent chain |
3187 | // to this point. |
3188 | // |
3189 | // There is one "export" node for each exported symbol. But because some |
3190 | // symbols may be a prefix of another symbol (e.g. _dup and _dup2), an export |
3191 | // node may have child nodes too. |
3192 | // |
3193 | // The algorithm for moveNext() is to keep moving down the leftmost unvisited |
3194 | // child until hitting a node with no children (which is an export node or |
3195 | // else the trie is malformed). On the way down, each node is pushed on the |
3196 | // stack ivar. If there is no more ways down, it pops up one and tries to go |
3197 | // down a sibling path until a childless node is reached. |
3198 | void ExportEntry::moveNext() { |
3199 | assert(!Stack.empty() && "ExportEntry::moveNext() with empty node stack" ); |
3200 | if (!Stack.back().IsExportNode) { |
3201 | *E = malformedError(Msg: "node is not an export node in export trie data at " |
3202 | "node: 0x" + |
3203 | Twine::utohexstr(Val: Stack.back().Start - Trie.begin())); |
3204 | moveToEnd(); |
3205 | return; |
3206 | } |
3207 | |
3208 | Stack.pop_back(); |
3209 | while (!Stack.empty()) { |
3210 | NodeState &Top = Stack.back(); |
3211 | if (Top.NextChildIndex < Top.ChildCount) { |
3212 | pushDownUntilBottom(); |
3213 | // Now at the next export node. |
3214 | return; |
3215 | } else { |
3216 | if (Top.IsExportNode) { |
3217 | // This node has no children but is itself an export node. |
3218 | CumulativeString.resize(N: Top.ParentStringLength); |
3219 | return; |
3220 | } |
3221 | Stack.pop_back(); |
3222 | } |
3223 | } |
3224 | Done = true; |
3225 | } |
3226 | |
3227 | iterator_range<export_iterator> |
3228 | MachOObjectFile::exports(Error &E, ArrayRef<uint8_t> Trie, |
3229 | const MachOObjectFile *O) { |
3230 | ExportEntry Start(&E, O, Trie); |
3231 | if (Trie.empty()) |
3232 | Start.moveToEnd(); |
3233 | else |
3234 | Start.moveToFirst(); |
3235 | |
3236 | ExportEntry Finish(&E, O, Trie); |
3237 | Finish.moveToEnd(); |
3238 | |
3239 | return make_range(x: export_iterator(Start), y: export_iterator(Finish)); |
3240 | } |
3241 | |
3242 | iterator_range<export_iterator> MachOObjectFile::exports(Error &Err) const { |
3243 | ArrayRef<uint8_t> Trie; |
3244 | if (DyldInfoLoadCmd) |
3245 | Trie = getDyldInfoExportsTrie(); |
3246 | else if (DyldExportsTrieLoadCmd) |
3247 | Trie = getDyldExportsTrie(); |
3248 | |
3249 | return exports(E&: Err, Trie, O: this); |
3250 | } |
3251 | |
3252 | MachOAbstractFixupEntry::MachOAbstractFixupEntry(Error *E, |
3253 | const MachOObjectFile *O) |
3254 | : E(E), O(O) { |
3255 | // Cache the vmaddress of __TEXT |
3256 | for (const auto &Command : O->load_commands()) { |
3257 | if (Command.C.cmd == MachO::LC_SEGMENT) { |
3258 | MachO::segment_command SLC = O->getSegmentLoadCommand(L: Command); |
3259 | if (StringRef(SLC.segname) == "__TEXT" ) { |
3260 | TextAddress = SLC.vmaddr; |
3261 | break; |
3262 | } |
3263 | } else if (Command.C.cmd == MachO::LC_SEGMENT_64) { |
3264 | MachO::segment_command_64 SLC_64 = O->getSegment64LoadCommand(L: Command); |
3265 | if (StringRef(SLC_64.segname) == "__TEXT" ) { |
3266 | TextAddress = SLC_64.vmaddr; |
3267 | break; |
3268 | } |
3269 | } |
3270 | } |
3271 | } |
3272 | |
3273 | int32_t MachOAbstractFixupEntry::segmentIndex() const { return SegmentIndex; } |
3274 | |
3275 | uint64_t MachOAbstractFixupEntry::segmentOffset() const { |
3276 | return SegmentOffset; |
3277 | } |
3278 | |
3279 | uint64_t MachOAbstractFixupEntry::segmentAddress() const { |
3280 | return O->BindRebaseAddress(SegIndex: SegmentIndex, SegOffset: 0); |
3281 | } |
3282 | |
3283 | StringRef MachOAbstractFixupEntry::segmentName() const { |
3284 | return O->BindRebaseSegmentName(SegIndex: SegmentIndex); |
3285 | } |
3286 | |
3287 | StringRef MachOAbstractFixupEntry::sectionName() const { |
3288 | return O->BindRebaseSectionName(SegIndex: SegmentIndex, SegOffset: SegmentOffset); |
3289 | } |
3290 | |
3291 | uint64_t MachOAbstractFixupEntry::address() const { |
3292 | return O->BindRebaseAddress(SegIndex: SegmentIndex, SegOffset: SegmentOffset); |
3293 | } |
3294 | |
3295 | StringRef MachOAbstractFixupEntry::symbolName() const { return SymbolName; } |
3296 | |
3297 | int64_t MachOAbstractFixupEntry::addend() const { return Addend; } |
3298 | |
3299 | uint32_t MachOAbstractFixupEntry::flags() const { return Flags; } |
3300 | |
3301 | int MachOAbstractFixupEntry::ordinal() const { return Ordinal; } |
3302 | |
3303 | StringRef MachOAbstractFixupEntry::typeName() const { return "unknown" ; } |
3304 | |
3305 | void MachOAbstractFixupEntry::moveToFirst() { |
3306 | SegmentOffset = 0; |
3307 | SegmentIndex = -1; |
3308 | Ordinal = 0; |
3309 | Flags = 0; |
3310 | Addend = 0; |
3311 | Done = false; |
3312 | } |
3313 | |
3314 | void MachOAbstractFixupEntry::moveToEnd() { Done = true; } |
3315 | |
3316 | void MachOAbstractFixupEntry::moveNext() {} |
3317 | |
3318 | MachOChainedFixupEntry::MachOChainedFixupEntry(Error *E, |
3319 | const MachOObjectFile *O, |
3320 | bool Parse) |
3321 | : MachOAbstractFixupEntry(E, O) { |
3322 | ErrorAsOutParameter e(E); |
3323 | if (!Parse) |
3324 | return; |
3325 | |
3326 | if (auto FixupTargetsOrErr = O->getDyldChainedFixupTargets()) { |
3327 | FixupTargets = *FixupTargetsOrErr; |
3328 | } else { |
3329 | *E = FixupTargetsOrErr.takeError(); |
3330 | return; |
3331 | } |
3332 | |
3333 | if (auto SegmentsOrErr = O->getChainedFixupsSegments()) { |
3334 | Segments = std::move(SegmentsOrErr->second); |
3335 | } else { |
3336 | *E = SegmentsOrErr.takeError(); |
3337 | return; |
3338 | } |
3339 | } |
3340 | |
3341 | void MachOChainedFixupEntry::findNextPageWithFixups() { |
3342 | auto FindInSegment = [this]() { |
3343 | const ChainedFixupsSegment &SegInfo = Segments[InfoSegIndex]; |
3344 | while (PageIndex < SegInfo.PageStarts.size() && |
3345 | SegInfo.PageStarts[PageIndex] == MachO::DYLD_CHAINED_PTR_START_NONE) |
3346 | ++PageIndex; |
3347 | return PageIndex < SegInfo.PageStarts.size(); |
3348 | }; |
3349 | |
3350 | while (InfoSegIndex < Segments.size()) { |
3351 | if (FindInSegment()) { |
3352 | PageOffset = Segments[InfoSegIndex].PageStarts[PageIndex]; |
3353 | SegmentData = O->getSegmentContents(SegmentIndex: Segments[InfoSegIndex].SegIdx); |
3354 | return; |
3355 | } |
3356 | |
3357 | InfoSegIndex++; |
3358 | PageIndex = 0; |
3359 | } |
3360 | } |
3361 | |
3362 | void MachOChainedFixupEntry::moveToFirst() { |
3363 | MachOAbstractFixupEntry::moveToFirst(); |
3364 | if (Segments.empty()) { |
3365 | Done = true; |
3366 | return; |
3367 | } |
3368 | |
3369 | InfoSegIndex = 0; |
3370 | PageIndex = 0; |
3371 | |
3372 | findNextPageWithFixups(); |
3373 | moveNext(); |
3374 | } |
3375 | |
3376 | void MachOChainedFixupEntry::moveToEnd() { |
3377 | MachOAbstractFixupEntry::moveToEnd(); |
3378 | } |
3379 | |
3380 | void MachOChainedFixupEntry::moveNext() { |
3381 | ErrorAsOutParameter ErrAsOutParam(E); |
3382 | |
3383 | if (InfoSegIndex == Segments.size()) { |
3384 | Done = true; |
3385 | return; |
3386 | } |
3387 | |
3388 | const ChainedFixupsSegment &SegInfo = Segments[InfoSegIndex]; |
3389 | SegmentIndex = SegInfo.SegIdx; |
3390 | SegmentOffset = SegInfo.Header.page_size * PageIndex + PageOffset; |
3391 | |
3392 | // FIXME: Handle other pointer formats. |
3393 | uint16_t PointerFormat = SegInfo.Header.pointer_format; |
3394 | if (PointerFormat != MachO::DYLD_CHAINED_PTR_64 && |
3395 | PointerFormat != MachO::DYLD_CHAINED_PTR_64_OFFSET) { |
3396 | *E = createError(Err: "segment " + Twine(SegmentIndex) + |
3397 | " has unsupported chained fixup pointer_format " + |
3398 | Twine(PointerFormat)); |
3399 | moveToEnd(); |
3400 | return; |
3401 | } |
3402 | |
3403 | Ordinal = 0; |
3404 | Flags = 0; |
3405 | Addend = 0; |
3406 | PointerValue = 0; |
3407 | SymbolName = {}; |
3408 | |
3409 | if (SegmentOffset + sizeof(RawValue) > SegmentData.size()) { |
3410 | *E = malformedError(Msg: "fixup in segment " + Twine(SegmentIndex) + |
3411 | " at offset " + Twine(SegmentOffset) + |
3412 | " extends past segment's end" ); |
3413 | moveToEnd(); |
3414 | return; |
3415 | } |
3416 | |
3417 | static_assert(sizeof(RawValue) == sizeof(MachO::dyld_chained_import_addend)); |
3418 | memcpy(dest: &RawValue, src: SegmentData.data() + SegmentOffset, n: sizeof(RawValue)); |
3419 | if (O->isLittleEndian() != sys::IsLittleEndianHost) |
3420 | sys::swapByteOrder(Value&: RawValue); |
3421 | |
3422 | // The bit extraction below assumes little-endian fixup entries. |
3423 | assert(O->isLittleEndian() && "big-endian object should have been rejected " |
3424 | "by getDyldChainedFixupTargets()" ); |
3425 | auto Field = [this](uint8_t Right, uint8_t Count) { |
3426 | return (RawValue >> Right) & ((1ULL << Count) - 1); |
3427 | }; |
3428 | |
3429 | // The `bind` field (most significant bit) of the encoded fixup determines |
3430 | // whether it is dyld_chained_ptr_64_bind or dyld_chained_ptr_64_rebase. |
3431 | bool IsBind = Field(63, 1); |
3432 | Kind = IsBind ? FixupKind::Bind : FixupKind::Rebase; |
3433 | uint32_t Next = Field(51, 12); |
3434 | if (IsBind) { |
3435 | uint32_t ImportOrdinal = Field(0, 24); |
3436 | uint8_t InlineAddend = Field(24, 8); |
3437 | |
3438 | if (ImportOrdinal >= FixupTargets.size()) { |
3439 | *E = malformedError(Msg: "fixup in segment " + Twine(SegmentIndex) + |
3440 | " at offset " + Twine(SegmentOffset) + |
3441 | " has out-of range import ordinal " + |
3442 | Twine(ImportOrdinal)); |
3443 | moveToEnd(); |
3444 | return; |
3445 | } |
3446 | |
3447 | ChainedFixupTarget &Target = FixupTargets[ImportOrdinal]; |
3448 | Ordinal = Target.libOrdinal(); |
3449 | Addend = InlineAddend ? InlineAddend : Target.addend(); |
3450 | Flags = Target.weakImport() ? MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT : 0; |
3451 | SymbolName = Target.symbolName(); |
3452 | } else { |
3453 | uint64_t Target = Field(0, 36); |
3454 | uint64_t High8 = Field(36, 8); |
3455 | |
3456 | PointerValue = Target | (High8 << 56); |
3457 | if (PointerFormat == MachO::DYLD_CHAINED_PTR_64_OFFSET) |
3458 | PointerValue += textAddress(); |
3459 | } |
3460 | |
3461 | // The stride is 4 bytes for DYLD_CHAINED_PTR_64(_OFFSET). |
3462 | if (Next != 0) { |
3463 | PageOffset += 4 * Next; |
3464 | } else { |
3465 | ++PageIndex; |
3466 | findNextPageWithFixups(); |
3467 | } |
3468 | } |
3469 | |
3470 | bool MachOChainedFixupEntry::operator==( |
3471 | const MachOChainedFixupEntry &Other) const { |
3472 | if (Done && Other.Done) |
3473 | return true; |
3474 | if (Done != Other.Done) |
3475 | return false; |
3476 | return InfoSegIndex == Other.InfoSegIndex && PageIndex == Other.PageIndex && |
3477 | PageOffset == Other.PageOffset; |
3478 | } |
3479 | |
3480 | MachORebaseEntry::MachORebaseEntry(Error *E, const MachOObjectFile *O, |
3481 | ArrayRef<uint8_t> Bytes, bool is64Bit) |
3482 | : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()), |
3483 | PointerSize(is64Bit ? 8 : 4) {} |
3484 | |
3485 | void MachORebaseEntry::moveToFirst() { |
3486 | Ptr = Opcodes.begin(); |
3487 | moveNext(); |
3488 | } |
3489 | |
3490 | void MachORebaseEntry::moveToEnd() { |
3491 | Ptr = Opcodes.end(); |
3492 | RemainingLoopCount = 0; |
3493 | Done = true; |
3494 | } |
3495 | |
3496 | void MachORebaseEntry::moveNext() { |
3497 | ErrorAsOutParameter ErrAsOutParam(E); |
3498 | // If in the middle of some loop, move to next rebasing in loop. |
3499 | SegmentOffset += AdvanceAmount; |
3500 | if (RemainingLoopCount) { |
3501 | --RemainingLoopCount; |
3502 | return; |
3503 | } |
3504 | |
3505 | bool More = true; |
3506 | while (More) { |
3507 | // REBASE_OPCODE_DONE is only used for padding if we are not aligned to |
3508 | // pointer size. Therefore it is possible to reach the end without ever |
3509 | // having seen REBASE_OPCODE_DONE. |
3510 | if (Ptr == Opcodes.end()) { |
3511 | Done = true; |
3512 | return; |
3513 | } |
3514 | |
3515 | // Parse next opcode and set up next loop. |
3516 | const uint8_t *OpcodeStart = Ptr; |
3517 | uint8_t Byte = *Ptr++; |
3518 | uint8_t ImmValue = Byte & MachO::REBASE_IMMEDIATE_MASK; |
3519 | uint8_t Opcode = Byte & MachO::REBASE_OPCODE_MASK; |
3520 | uint64_t Count, Skip; |
3521 | const char *error = nullptr; |
3522 | switch (Opcode) { |
3523 | case MachO::REBASE_OPCODE_DONE: |
3524 | More = false; |
3525 | Done = true; |
3526 | moveToEnd(); |
3527 | DEBUG_WITH_TYPE("mach-o-rebase" , dbgs() << "REBASE_OPCODE_DONE\n" ); |
3528 | break; |
3529 | case MachO::REBASE_OPCODE_SET_TYPE_IMM: |
3530 | RebaseType = ImmValue; |
3531 | if (RebaseType > MachO::REBASE_TYPE_TEXT_PCREL32) { |
3532 | *E = malformedError(Msg: "for REBASE_OPCODE_SET_TYPE_IMM bad bind type: " + |
3533 | Twine((int)RebaseType) + " for opcode at: 0x" + |
3534 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3535 | moveToEnd(); |
3536 | return; |
3537 | } |
3538 | DEBUG_WITH_TYPE( |
3539 | "mach-o-rebase" , |
3540 | dbgs() << "REBASE_OPCODE_SET_TYPE_IMM: " |
3541 | << "RebaseType=" << (int) RebaseType << "\n" ); |
3542 | break; |
3543 | case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: |
3544 | SegmentIndex = ImmValue; |
3545 | SegmentOffset = readULEB128(error: &error); |
3546 | if (error) { |
3547 | *E = malformedError(Msg: "for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + |
3548 | Twine(error) + " for opcode at: 0x" + |
3549 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3550 | moveToEnd(); |
3551 | return; |
3552 | } |
3553 | error = O->RebaseEntryCheckSegAndOffsets(SegIndex: SegmentIndex, SegOffset: SegmentOffset, |
3554 | PointerSize); |
3555 | if (error) { |
3556 | *E = malformedError(Msg: "for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + |
3557 | Twine(error) + " for opcode at: 0x" + |
3558 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3559 | moveToEnd(); |
3560 | return; |
3561 | } |
3562 | DEBUG_WITH_TYPE( |
3563 | "mach-o-rebase" , |
3564 | dbgs() << "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: " |
3565 | << "SegmentIndex=" << SegmentIndex << ", " |
3566 | << format("SegmentOffset=0x%06X" , SegmentOffset) |
3567 | << "\n" ); |
3568 | break; |
3569 | case MachO::REBASE_OPCODE_ADD_ADDR_ULEB: |
3570 | SegmentOffset += readULEB128(error: &error); |
3571 | if (error) { |
3572 | *E = malformedError(Msg: "for REBASE_OPCODE_ADD_ADDR_ULEB " + Twine(error) + |
3573 | " for opcode at: 0x" + |
3574 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3575 | moveToEnd(); |
3576 | return; |
3577 | } |
3578 | error = O->RebaseEntryCheckSegAndOffsets(SegIndex: SegmentIndex, SegOffset: SegmentOffset, |
3579 | PointerSize); |
3580 | if (error) { |
3581 | *E = malformedError(Msg: "for REBASE_OPCODE_ADD_ADDR_ULEB " + Twine(error) + |
3582 | " for opcode at: 0x" + |
3583 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3584 | moveToEnd(); |
3585 | return; |
3586 | } |
3587 | DEBUG_WITH_TYPE("mach-o-rebase" , |
3588 | dbgs() << "REBASE_OPCODE_ADD_ADDR_ULEB: " |
3589 | << format("SegmentOffset=0x%06X" , |
3590 | SegmentOffset) << "\n" ); |
3591 | break; |
3592 | case MachO::REBASE_OPCODE_ADD_ADDR_IMM_SCALED: |
3593 | SegmentOffset += ImmValue * PointerSize; |
3594 | error = O->RebaseEntryCheckSegAndOffsets(SegIndex: SegmentIndex, SegOffset: SegmentOffset, |
3595 | PointerSize); |
3596 | if (error) { |
3597 | *E = malformedError(Msg: "for REBASE_OPCODE_ADD_ADDR_IMM_SCALED " + |
3598 | Twine(error) + " for opcode at: 0x" + |
3599 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3600 | moveToEnd(); |
3601 | return; |
3602 | } |
3603 | DEBUG_WITH_TYPE("mach-o-rebase" , |
3604 | dbgs() << "REBASE_OPCODE_ADD_ADDR_IMM_SCALED: " |
3605 | << format("SegmentOffset=0x%06X" , |
3606 | SegmentOffset) << "\n" ); |
3607 | break; |
3608 | case MachO::REBASE_OPCODE_DO_REBASE_IMM_TIMES: |
3609 | AdvanceAmount = PointerSize; |
3610 | Skip = 0; |
3611 | Count = ImmValue; |
3612 | if (ImmValue != 0) |
3613 | RemainingLoopCount = ImmValue - 1; |
3614 | else |
3615 | RemainingLoopCount = 0; |
3616 | error = O->RebaseEntryCheckSegAndOffsets(SegIndex: SegmentIndex, SegOffset: SegmentOffset, |
3617 | PointerSize, Count, Skip); |
3618 | if (error) { |
3619 | *E = malformedError(Msg: "for REBASE_OPCODE_DO_REBASE_IMM_TIMES " + |
3620 | Twine(error) + " for opcode at: 0x" + |
3621 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3622 | moveToEnd(); |
3623 | return; |
3624 | } |
3625 | DEBUG_WITH_TYPE( |
3626 | "mach-o-rebase" , |
3627 | dbgs() << "REBASE_OPCODE_DO_REBASE_IMM_TIMES: " |
3628 | << format("SegmentOffset=0x%06X" , SegmentOffset) |
3629 | << ", AdvanceAmount=" << AdvanceAmount |
3630 | << ", RemainingLoopCount=" << RemainingLoopCount |
3631 | << "\n" ); |
3632 | return; |
3633 | case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES: |
3634 | AdvanceAmount = PointerSize; |
3635 | Skip = 0; |
3636 | Count = readULEB128(error: &error); |
3637 | if (error) { |
3638 | *E = malformedError(Msg: "for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " + |
3639 | Twine(error) + " for opcode at: 0x" + |
3640 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3641 | moveToEnd(); |
3642 | return; |
3643 | } |
3644 | if (Count != 0) |
3645 | RemainingLoopCount = Count - 1; |
3646 | else |
3647 | RemainingLoopCount = 0; |
3648 | error = O->RebaseEntryCheckSegAndOffsets(SegIndex: SegmentIndex, SegOffset: SegmentOffset, |
3649 | PointerSize, Count, Skip); |
3650 | if (error) { |
3651 | *E = malformedError(Msg: "for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " + |
3652 | Twine(error) + " for opcode at: 0x" + |
3653 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3654 | moveToEnd(); |
3655 | return; |
3656 | } |
3657 | DEBUG_WITH_TYPE( |
3658 | "mach-o-rebase" , |
3659 | dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES: " |
3660 | << format("SegmentOffset=0x%06X" , SegmentOffset) |
3661 | << ", AdvanceAmount=" << AdvanceAmount |
3662 | << ", RemainingLoopCount=" << RemainingLoopCount |
3663 | << "\n" ); |
3664 | return; |
3665 | case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: |
3666 | Skip = readULEB128(error: &error); |
3667 | if (error) { |
3668 | *E = malformedError(Msg: "for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " + |
3669 | Twine(error) + " for opcode at: 0x" + |
3670 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3671 | moveToEnd(); |
3672 | return; |
3673 | } |
3674 | AdvanceAmount = Skip + PointerSize; |
3675 | Count = 1; |
3676 | RemainingLoopCount = 0; |
3677 | error = O->RebaseEntryCheckSegAndOffsets(SegIndex: SegmentIndex, SegOffset: SegmentOffset, |
3678 | PointerSize, Count, Skip); |
3679 | if (error) { |
3680 | *E = malformedError(Msg: "for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " + |
3681 | Twine(error) + " for opcode at: 0x" + |
3682 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3683 | moveToEnd(); |
3684 | return; |
3685 | } |
3686 | DEBUG_WITH_TYPE( |
3687 | "mach-o-rebase" , |
3688 | dbgs() << "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: " |
3689 | << format("SegmentOffset=0x%06X" , SegmentOffset) |
3690 | << ", AdvanceAmount=" << AdvanceAmount |
3691 | << ", RemainingLoopCount=" << RemainingLoopCount |
3692 | << "\n" ); |
3693 | return; |
3694 | case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: |
3695 | Count = readULEB128(error: &error); |
3696 | if (error) { |
3697 | *E = malformedError(Msg: "for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" |
3698 | "ULEB " + |
3699 | Twine(error) + " for opcode at: 0x" + |
3700 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3701 | moveToEnd(); |
3702 | return; |
3703 | } |
3704 | if (Count != 0) |
3705 | RemainingLoopCount = Count - 1; |
3706 | else |
3707 | RemainingLoopCount = 0; |
3708 | Skip = readULEB128(error: &error); |
3709 | if (error) { |
3710 | *E = malformedError(Msg: "for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" |
3711 | "ULEB " + |
3712 | Twine(error) + " for opcode at: 0x" + |
3713 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3714 | moveToEnd(); |
3715 | return; |
3716 | } |
3717 | AdvanceAmount = Skip + PointerSize; |
3718 | |
3719 | error = O->RebaseEntryCheckSegAndOffsets(SegIndex: SegmentIndex, SegOffset: SegmentOffset, |
3720 | PointerSize, Count, Skip); |
3721 | if (error) { |
3722 | *E = malformedError(Msg: "for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" |
3723 | "ULEB " + |
3724 | Twine(error) + " for opcode at: 0x" + |
3725 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3726 | moveToEnd(); |
3727 | return; |
3728 | } |
3729 | DEBUG_WITH_TYPE( |
3730 | "mach-o-rebase" , |
3731 | dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: " |
3732 | << format("SegmentOffset=0x%06X" , SegmentOffset) |
3733 | << ", AdvanceAmount=" << AdvanceAmount |
3734 | << ", RemainingLoopCount=" << RemainingLoopCount |
3735 | << "\n" ); |
3736 | return; |
3737 | default: |
3738 | *E = malformedError(Msg: "bad rebase info (bad opcode value 0x" + |
3739 | Twine::utohexstr(Val: Opcode) + " for opcode at: 0x" + |
3740 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3741 | moveToEnd(); |
3742 | return; |
3743 | } |
3744 | } |
3745 | } |
3746 | |
3747 | uint64_t MachORebaseEntry::readULEB128(const char **error) { |
3748 | unsigned Count; |
3749 | uint64_t Result = decodeULEB128(p: Ptr, n: &Count, end: Opcodes.end(), error); |
3750 | Ptr += Count; |
3751 | if (Ptr > Opcodes.end()) |
3752 | Ptr = Opcodes.end(); |
3753 | return Result; |
3754 | } |
3755 | |
3756 | int32_t MachORebaseEntry::segmentIndex() const { return SegmentIndex; } |
3757 | |
3758 | uint64_t MachORebaseEntry::segmentOffset() const { return SegmentOffset; } |
3759 | |
3760 | StringRef MachORebaseEntry::typeName() const { |
3761 | switch (RebaseType) { |
3762 | case MachO::REBASE_TYPE_POINTER: |
3763 | return "pointer" ; |
3764 | case MachO::REBASE_TYPE_TEXT_ABSOLUTE32: |
3765 | return "text abs32" ; |
3766 | case MachO::REBASE_TYPE_TEXT_PCREL32: |
3767 | return "text rel32" ; |
3768 | } |
3769 | return "unknown" ; |
3770 | } |
3771 | |
3772 | // For use with the SegIndex of a checked Mach-O Rebase entry |
3773 | // to get the segment name. |
3774 | StringRef MachORebaseEntry::segmentName() const { |
3775 | return O->BindRebaseSegmentName(SegIndex: SegmentIndex); |
3776 | } |
3777 | |
3778 | // For use with a SegIndex,SegOffset pair from a checked Mach-O Rebase entry |
3779 | // to get the section name. |
3780 | StringRef MachORebaseEntry::sectionName() const { |
3781 | return O->BindRebaseSectionName(SegIndex: SegmentIndex, SegOffset: SegmentOffset); |
3782 | } |
3783 | |
3784 | // For use with a SegIndex,SegOffset pair from a checked Mach-O Rebase entry |
3785 | // to get the address. |
3786 | uint64_t MachORebaseEntry::address() const { |
3787 | return O->BindRebaseAddress(SegIndex: SegmentIndex, SegOffset: SegmentOffset); |
3788 | } |
3789 | |
3790 | bool MachORebaseEntry::operator==(const MachORebaseEntry &Other) const { |
3791 | #ifdef EXPENSIVE_CHECKS |
3792 | assert(Opcodes == Other.Opcodes && "compare iterators of different files" ); |
3793 | #else |
3794 | assert(Opcodes.data() == Other.Opcodes.data() && "compare iterators of different files" ); |
3795 | #endif |
3796 | return (Ptr == Other.Ptr) && |
3797 | (RemainingLoopCount == Other.RemainingLoopCount) && |
3798 | (Done == Other.Done); |
3799 | } |
3800 | |
3801 | iterator_range<rebase_iterator> |
3802 | MachOObjectFile::rebaseTable(Error &Err, MachOObjectFile *O, |
3803 | ArrayRef<uint8_t> Opcodes, bool is64) { |
3804 | if (O->BindRebaseSectionTable == nullptr) |
3805 | O->BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(args&: O); |
3806 | MachORebaseEntry Start(&Err, O, Opcodes, is64); |
3807 | Start.moveToFirst(); |
3808 | |
3809 | MachORebaseEntry Finish(&Err, O, Opcodes, is64); |
3810 | Finish.moveToEnd(); |
3811 | |
3812 | return make_range(x: rebase_iterator(Start), y: rebase_iterator(Finish)); |
3813 | } |
3814 | |
3815 | iterator_range<rebase_iterator> MachOObjectFile::rebaseTable(Error &Err) { |
3816 | return rebaseTable(Err, O: this, Opcodes: getDyldInfoRebaseOpcodes(), is64: is64Bit()); |
3817 | } |
3818 | |
3819 | MachOBindEntry::MachOBindEntry(Error *E, const MachOObjectFile *O, |
3820 | ArrayRef<uint8_t> Bytes, bool is64Bit, Kind BK) |
3821 | : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()), |
3822 | PointerSize(is64Bit ? 8 : 4), TableKind(BK) {} |
3823 | |
3824 | void MachOBindEntry::moveToFirst() { |
3825 | Ptr = Opcodes.begin(); |
3826 | moveNext(); |
3827 | } |
3828 | |
3829 | void MachOBindEntry::moveToEnd() { |
3830 | Ptr = Opcodes.end(); |
3831 | RemainingLoopCount = 0; |
3832 | Done = true; |
3833 | } |
3834 | |
3835 | void MachOBindEntry::moveNext() { |
3836 | ErrorAsOutParameter ErrAsOutParam(E); |
3837 | // If in the middle of some loop, move to next binding in loop. |
3838 | SegmentOffset += AdvanceAmount; |
3839 | if (RemainingLoopCount) { |
3840 | --RemainingLoopCount; |
3841 | return; |
3842 | } |
3843 | |
3844 | bool More = true; |
3845 | while (More) { |
3846 | // BIND_OPCODE_DONE is only used for padding if we are not aligned to |
3847 | // pointer size. Therefore it is possible to reach the end without ever |
3848 | // having seen BIND_OPCODE_DONE. |
3849 | if (Ptr == Opcodes.end()) { |
3850 | Done = true; |
3851 | return; |
3852 | } |
3853 | |
3854 | // Parse next opcode and set up next loop. |
3855 | const uint8_t *OpcodeStart = Ptr; |
3856 | uint8_t Byte = *Ptr++; |
3857 | uint8_t ImmValue = Byte & MachO::BIND_IMMEDIATE_MASK; |
3858 | uint8_t Opcode = Byte & MachO::BIND_OPCODE_MASK; |
3859 | int8_t SignExtended; |
3860 | const uint8_t *SymStart; |
3861 | uint64_t Count, Skip; |
3862 | const char *error = nullptr; |
3863 | switch (Opcode) { |
3864 | case MachO::BIND_OPCODE_DONE: |
3865 | if (TableKind == Kind::Lazy) { |
3866 | // Lazying bindings have a DONE opcode between entries. Need to ignore |
3867 | // it to advance to next entry. But need not if this is last entry. |
3868 | bool NotLastEntry = false; |
3869 | for (const uint8_t *P = Ptr; P < Opcodes.end(); ++P) { |
3870 | if (*P) { |
3871 | NotLastEntry = true; |
3872 | } |
3873 | } |
3874 | if (NotLastEntry) |
3875 | break; |
3876 | } |
3877 | More = false; |
3878 | moveToEnd(); |
3879 | DEBUG_WITH_TYPE("mach-o-bind" , dbgs() << "BIND_OPCODE_DONE\n" ); |
3880 | break; |
3881 | case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: |
3882 | if (TableKind == Kind::Weak) { |
3883 | *E = malformedError(Msg: "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM not allowed in " |
3884 | "weak bind table for opcode at: 0x" + |
3885 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3886 | moveToEnd(); |
3887 | return; |
3888 | } |
3889 | Ordinal = ImmValue; |
3890 | LibraryOrdinalSet = true; |
3891 | if (ImmValue > O->getLibraryCount()) { |
3892 | *E = malformedError(Msg: "for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB bad " |
3893 | "library ordinal: " + |
3894 | Twine((int)ImmValue) + " (max " + |
3895 | Twine((int)O->getLibraryCount()) + |
3896 | ") for opcode at: 0x" + |
3897 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3898 | moveToEnd(); |
3899 | return; |
3900 | } |
3901 | DEBUG_WITH_TYPE( |
3902 | "mach-o-bind" , |
3903 | dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: " |
3904 | << "Ordinal=" << Ordinal << "\n" ); |
3905 | break; |
3906 | case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: |
3907 | if (TableKind == Kind::Weak) { |
3908 | *E = malformedError(Msg: "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB not allowed in " |
3909 | "weak bind table for opcode at: 0x" + |
3910 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3911 | moveToEnd(); |
3912 | return; |
3913 | } |
3914 | Ordinal = readULEB128(error: &error); |
3915 | LibraryOrdinalSet = true; |
3916 | if (error) { |
3917 | *E = malformedError(Msg: "for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB " + |
3918 | Twine(error) + " for opcode at: 0x" + |
3919 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3920 | moveToEnd(); |
3921 | return; |
3922 | } |
3923 | if (Ordinal > (int)O->getLibraryCount()) { |
3924 | *E = malformedError(Msg: "for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB bad " |
3925 | "library ordinal: " + |
3926 | Twine((int)Ordinal) + " (max " + |
3927 | Twine((int)O->getLibraryCount()) + |
3928 | ") for opcode at: 0x" + |
3929 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3930 | moveToEnd(); |
3931 | return; |
3932 | } |
3933 | DEBUG_WITH_TYPE( |
3934 | "mach-o-bind" , |
3935 | dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: " |
3936 | << "Ordinal=" << Ordinal << "\n" ); |
3937 | break; |
3938 | case MachO::BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: |
3939 | if (TableKind == Kind::Weak) { |
3940 | *E = malformedError(Msg: "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM not allowed in " |
3941 | "weak bind table for opcode at: 0x" + |
3942 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3943 | moveToEnd(); |
3944 | return; |
3945 | } |
3946 | if (ImmValue) { |
3947 | SignExtended = MachO::BIND_OPCODE_MASK | ImmValue; |
3948 | Ordinal = SignExtended; |
3949 | if (Ordinal < MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP) { |
3950 | *E = malformedError(Msg: "for BIND_OPCODE_SET_DYLIB_SPECIAL_IMM unknown " |
3951 | "special ordinal: " + |
3952 | Twine((int)Ordinal) + " for opcode at: 0x" + |
3953 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3954 | moveToEnd(); |
3955 | return; |
3956 | } |
3957 | } else |
3958 | Ordinal = 0; |
3959 | LibraryOrdinalSet = true; |
3960 | DEBUG_WITH_TYPE( |
3961 | "mach-o-bind" , |
3962 | dbgs() << "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: " |
3963 | << "Ordinal=" << Ordinal << "\n" ); |
3964 | break; |
3965 | case MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: |
3966 | Flags = ImmValue; |
3967 | SymStart = Ptr; |
3968 | while (*Ptr && (Ptr < Opcodes.end())) { |
3969 | ++Ptr; |
3970 | } |
3971 | if (Ptr == Opcodes.end()) { |
3972 | *E = malformedError( |
3973 | Msg: "for BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM " |
3974 | "symbol name extends past opcodes for opcode at: 0x" + |
3975 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3976 | moveToEnd(); |
3977 | return; |
3978 | } |
3979 | SymbolName = StringRef(reinterpret_cast<const char*>(SymStart), |
3980 | Ptr-SymStart); |
3981 | ++Ptr; |
3982 | DEBUG_WITH_TYPE( |
3983 | "mach-o-bind" , |
3984 | dbgs() << "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: " |
3985 | << "SymbolName=" << SymbolName << "\n" ); |
3986 | if (TableKind == Kind::Weak) { |
3987 | if (ImmValue & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) |
3988 | return; |
3989 | } |
3990 | break; |
3991 | case MachO::BIND_OPCODE_SET_TYPE_IMM: |
3992 | BindType = ImmValue; |
3993 | if (ImmValue > MachO::BIND_TYPE_TEXT_PCREL32) { |
3994 | *E = malformedError(Msg: "for BIND_OPCODE_SET_TYPE_IMM bad bind type: " + |
3995 | Twine((int)ImmValue) + " for opcode at: 0x" + |
3996 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
3997 | moveToEnd(); |
3998 | return; |
3999 | } |
4000 | DEBUG_WITH_TYPE( |
4001 | "mach-o-bind" , |
4002 | dbgs() << "BIND_OPCODE_SET_TYPE_IMM: " |
4003 | << "BindType=" << (int)BindType << "\n" ); |
4004 | break; |
4005 | case MachO::BIND_OPCODE_SET_ADDEND_SLEB: |
4006 | Addend = readSLEB128(error: &error); |
4007 | if (error) { |
4008 | *E = malformedError(Msg: "for BIND_OPCODE_SET_ADDEND_SLEB " + Twine(error) + |
4009 | " for opcode at: 0x" + |
4010 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4011 | moveToEnd(); |
4012 | return; |
4013 | } |
4014 | DEBUG_WITH_TYPE( |
4015 | "mach-o-bind" , |
4016 | dbgs() << "BIND_OPCODE_SET_ADDEND_SLEB: " |
4017 | << "Addend=" << Addend << "\n" ); |
4018 | break; |
4019 | case MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: |
4020 | SegmentIndex = ImmValue; |
4021 | SegmentOffset = readULEB128(error: &error); |
4022 | if (error) { |
4023 | *E = malformedError(Msg: "for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + |
4024 | Twine(error) + " for opcode at: 0x" + |
4025 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4026 | moveToEnd(); |
4027 | return; |
4028 | } |
4029 | error = O->BindEntryCheckSegAndOffsets(SegIndex: SegmentIndex, SegOffset: SegmentOffset, |
4030 | PointerSize); |
4031 | if (error) { |
4032 | *E = malformedError(Msg: "for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + |
4033 | Twine(error) + " for opcode at: 0x" + |
4034 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4035 | moveToEnd(); |
4036 | return; |
4037 | } |
4038 | DEBUG_WITH_TYPE( |
4039 | "mach-o-bind" , |
4040 | dbgs() << "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: " |
4041 | << "SegmentIndex=" << SegmentIndex << ", " |
4042 | << format("SegmentOffset=0x%06X" , SegmentOffset) |
4043 | << "\n" ); |
4044 | break; |
4045 | case MachO::BIND_OPCODE_ADD_ADDR_ULEB: |
4046 | SegmentOffset += readULEB128(error: &error); |
4047 | if (error) { |
4048 | *E = malformedError(Msg: "for BIND_OPCODE_ADD_ADDR_ULEB " + Twine(error) + |
4049 | " for opcode at: 0x" + |
4050 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4051 | moveToEnd(); |
4052 | return; |
4053 | } |
4054 | error = O->BindEntryCheckSegAndOffsets(SegIndex: SegmentIndex, SegOffset: SegmentOffset, |
4055 | PointerSize); |
4056 | if (error) { |
4057 | *E = malformedError(Msg: "for BIND_OPCODE_ADD_ADDR_ULEB " + Twine(error) + |
4058 | " for opcode at: 0x" + |
4059 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4060 | moveToEnd(); |
4061 | return; |
4062 | } |
4063 | DEBUG_WITH_TYPE("mach-o-bind" , |
4064 | dbgs() << "BIND_OPCODE_ADD_ADDR_ULEB: " |
4065 | << format("SegmentOffset=0x%06X" , |
4066 | SegmentOffset) << "\n" ); |
4067 | break; |
4068 | case MachO::BIND_OPCODE_DO_BIND: |
4069 | AdvanceAmount = PointerSize; |
4070 | RemainingLoopCount = 0; |
4071 | error = O->BindEntryCheckSegAndOffsets(SegIndex: SegmentIndex, SegOffset: SegmentOffset, |
4072 | PointerSize); |
4073 | if (error) { |
4074 | *E = malformedError(Msg: "for BIND_OPCODE_DO_BIND " + Twine(error) + |
4075 | " for opcode at: 0x" + |
4076 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4077 | moveToEnd(); |
4078 | return; |
4079 | } |
4080 | if (SymbolName == StringRef()) { |
4081 | *E = malformedError( |
4082 | Msg: "for BIND_OPCODE_DO_BIND missing preceding " |
4083 | "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for opcode at: 0x" + |
4084 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4085 | moveToEnd(); |
4086 | return; |
4087 | } |
4088 | if (!LibraryOrdinalSet && TableKind != Kind::Weak) { |
4089 | *E = |
4090 | malformedError(Msg: "for BIND_OPCODE_DO_BIND missing preceding " |
4091 | "BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode at: 0x" + |
4092 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4093 | moveToEnd(); |
4094 | return; |
4095 | } |
4096 | DEBUG_WITH_TYPE("mach-o-bind" , |
4097 | dbgs() << "BIND_OPCODE_DO_BIND: " |
4098 | << format("SegmentOffset=0x%06X" , |
4099 | SegmentOffset) << "\n" ); |
4100 | return; |
4101 | case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: |
4102 | if (TableKind == Kind::Lazy) { |
4103 | *E = malformedError(Msg: "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB not allowed in " |
4104 | "lazy bind table for opcode at: 0x" + |
4105 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4106 | moveToEnd(); |
4107 | return; |
4108 | } |
4109 | error = O->BindEntryCheckSegAndOffsets(SegIndex: SegmentIndex, SegOffset: SegmentOffset, |
4110 | PointerSize); |
4111 | if (error) { |
4112 | *E = malformedError(Msg: "for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB " + |
4113 | Twine(error) + " for opcode at: 0x" + |
4114 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4115 | moveToEnd(); |
4116 | return; |
4117 | } |
4118 | if (SymbolName == StringRef()) { |
4119 | *E = malformedError( |
4120 | Msg: "for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB missing " |
4121 | "preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for opcode " |
4122 | "at: 0x" + |
4123 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4124 | moveToEnd(); |
4125 | return; |
4126 | } |
4127 | if (!LibraryOrdinalSet && TableKind != Kind::Weak) { |
4128 | *E = malformedError( |
4129 | Msg: "for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB missing " |
4130 | "preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode at: 0x" + |
4131 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4132 | moveToEnd(); |
4133 | return; |
4134 | } |
4135 | AdvanceAmount = readULEB128(error: &error) + PointerSize; |
4136 | if (error) { |
4137 | *E = malformedError(Msg: "for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB " + |
4138 | Twine(error) + " for opcode at: 0x" + |
4139 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4140 | moveToEnd(); |
4141 | return; |
4142 | } |
4143 | // Note, this is not really an error until the next bind but make no sense |
4144 | // for a BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB to not be followed by another |
4145 | // bind operation. |
4146 | error = O->BindEntryCheckSegAndOffsets(SegIndex: SegmentIndex, SegOffset: SegmentOffset + |
4147 | AdvanceAmount, PointerSize); |
4148 | if (error) { |
4149 | *E = malformedError(Msg: "for BIND_OPCODE_ADD_ADDR_ULEB (after adding " |
4150 | "ULEB) " + |
4151 | Twine(error) + " for opcode at: 0x" + |
4152 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4153 | moveToEnd(); |
4154 | return; |
4155 | } |
4156 | RemainingLoopCount = 0; |
4157 | DEBUG_WITH_TYPE( |
4158 | "mach-o-bind" , |
4159 | dbgs() << "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: " |
4160 | << format("SegmentOffset=0x%06X" , SegmentOffset) |
4161 | << ", AdvanceAmount=" << AdvanceAmount |
4162 | << ", RemainingLoopCount=" << RemainingLoopCount |
4163 | << "\n" ); |
4164 | return; |
4165 | case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: |
4166 | if (TableKind == Kind::Lazy) { |
4167 | *E = malformedError(Msg: "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED not " |
4168 | "allowed in lazy bind table for opcode at: 0x" + |
4169 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4170 | moveToEnd(); |
4171 | return; |
4172 | } |
4173 | if (SymbolName == StringRef()) { |
4174 | *E = malformedError( |
4175 | Msg: "for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " |
4176 | "missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for " |
4177 | "opcode at: 0x" + |
4178 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4179 | moveToEnd(); |
4180 | return; |
4181 | } |
4182 | if (!LibraryOrdinalSet && TableKind != Kind::Weak) { |
4183 | *E = malformedError( |
4184 | Msg: "for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " |
4185 | "missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode " |
4186 | "at: 0x" + |
4187 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4188 | moveToEnd(); |
4189 | return; |
4190 | } |
4191 | AdvanceAmount = ImmValue * PointerSize + PointerSize; |
4192 | RemainingLoopCount = 0; |
4193 | error = O->BindEntryCheckSegAndOffsets(SegIndex: SegmentIndex, SegOffset: SegmentOffset + |
4194 | AdvanceAmount, PointerSize); |
4195 | if (error) { |
4196 | *E = malformedError(Msg: "for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " + |
4197 | Twine(error) + " for opcode at: 0x" + |
4198 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4199 | moveToEnd(); |
4200 | return; |
4201 | } |
4202 | DEBUG_WITH_TYPE("mach-o-bind" , |
4203 | dbgs() |
4204 | << "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: " |
4205 | << format("SegmentOffset=0x%06X" , SegmentOffset) << "\n" ); |
4206 | return; |
4207 | case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: |
4208 | if (TableKind == Kind::Lazy) { |
4209 | *E = malformedError(Msg: "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB not " |
4210 | "allowed in lazy bind table for opcode at: 0x" + |
4211 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4212 | moveToEnd(); |
4213 | return; |
4214 | } |
4215 | Count = readULEB128(error: &error); |
4216 | if (Count != 0) |
4217 | RemainingLoopCount = Count - 1; |
4218 | else |
4219 | RemainingLoopCount = 0; |
4220 | if (error) { |
4221 | *E = malformedError(Msg: "for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " |
4222 | " (count value) " + |
4223 | Twine(error) + " for opcode at: 0x" + |
4224 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4225 | moveToEnd(); |
4226 | return; |
4227 | } |
4228 | Skip = readULEB128(error: &error); |
4229 | AdvanceAmount = Skip + PointerSize; |
4230 | if (error) { |
4231 | *E = malformedError(Msg: "for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " |
4232 | " (skip value) " + |
4233 | Twine(error) + " for opcode at: 0x" + |
4234 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4235 | moveToEnd(); |
4236 | return; |
4237 | } |
4238 | if (SymbolName == StringRef()) { |
4239 | *E = malformedError( |
4240 | Msg: "for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " |
4241 | "missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for " |
4242 | "opcode at: 0x" + |
4243 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4244 | moveToEnd(); |
4245 | return; |
4246 | } |
4247 | if (!LibraryOrdinalSet && TableKind != Kind::Weak) { |
4248 | *E = malformedError( |
4249 | Msg: "for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " |
4250 | "missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode " |
4251 | "at: 0x" + |
4252 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4253 | moveToEnd(); |
4254 | return; |
4255 | } |
4256 | error = O->BindEntryCheckSegAndOffsets(SegIndex: SegmentIndex, SegOffset: SegmentOffset, |
4257 | PointerSize, Count, Skip); |
4258 | if (error) { |
4259 | *E = |
4260 | malformedError(Msg: "for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " + |
4261 | Twine(error) + " for opcode at: 0x" + |
4262 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4263 | moveToEnd(); |
4264 | return; |
4265 | } |
4266 | DEBUG_WITH_TYPE( |
4267 | "mach-o-bind" , |
4268 | dbgs() << "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: " |
4269 | << format("SegmentOffset=0x%06X" , SegmentOffset) |
4270 | << ", AdvanceAmount=" << AdvanceAmount |
4271 | << ", RemainingLoopCount=" << RemainingLoopCount |
4272 | << "\n" ); |
4273 | return; |
4274 | default: |
4275 | *E = malformedError(Msg: "bad bind info (bad opcode value 0x" + |
4276 | Twine::utohexstr(Val: Opcode) + " for opcode at: 0x" + |
4277 | Twine::utohexstr(Val: OpcodeStart - Opcodes.begin())); |
4278 | moveToEnd(); |
4279 | return; |
4280 | } |
4281 | } |
4282 | } |
4283 | |
4284 | uint64_t MachOBindEntry::readULEB128(const char **error) { |
4285 | unsigned Count; |
4286 | uint64_t Result = decodeULEB128(p: Ptr, n: &Count, end: Opcodes.end(), error); |
4287 | Ptr += Count; |
4288 | if (Ptr > Opcodes.end()) |
4289 | Ptr = Opcodes.end(); |
4290 | return Result; |
4291 | } |
4292 | |
4293 | int64_t MachOBindEntry::readSLEB128(const char **error) { |
4294 | unsigned Count; |
4295 | int64_t Result = decodeSLEB128(p: Ptr, n: &Count, end: Opcodes.end(), error); |
4296 | Ptr += Count; |
4297 | if (Ptr > Opcodes.end()) |
4298 | Ptr = Opcodes.end(); |
4299 | return Result; |
4300 | } |
4301 | |
4302 | int32_t MachOBindEntry::segmentIndex() const { return SegmentIndex; } |
4303 | |
4304 | uint64_t MachOBindEntry::segmentOffset() const { return SegmentOffset; } |
4305 | |
4306 | StringRef MachOBindEntry::typeName() const { |
4307 | switch (BindType) { |
4308 | case MachO::BIND_TYPE_POINTER: |
4309 | return "pointer" ; |
4310 | case MachO::BIND_TYPE_TEXT_ABSOLUTE32: |
4311 | return "text abs32" ; |
4312 | case MachO::BIND_TYPE_TEXT_PCREL32: |
4313 | return "text rel32" ; |
4314 | } |
4315 | return "unknown" ; |
4316 | } |
4317 | |
4318 | StringRef MachOBindEntry::symbolName() const { return SymbolName; } |
4319 | |
4320 | int64_t MachOBindEntry::addend() const { return Addend; } |
4321 | |
4322 | uint32_t MachOBindEntry::flags() const { return Flags; } |
4323 | |
4324 | int MachOBindEntry::ordinal() const { return Ordinal; } |
4325 | |
4326 | // For use with the SegIndex of a checked Mach-O Bind entry |
4327 | // to get the segment name. |
4328 | StringRef MachOBindEntry::segmentName() const { |
4329 | return O->BindRebaseSegmentName(SegIndex: SegmentIndex); |
4330 | } |
4331 | |
4332 | // For use with a SegIndex,SegOffset pair from a checked Mach-O Bind entry |
4333 | // to get the section name. |
4334 | StringRef MachOBindEntry::sectionName() const { |
4335 | return O->BindRebaseSectionName(SegIndex: SegmentIndex, SegOffset: SegmentOffset); |
4336 | } |
4337 | |
4338 | // For use with a SegIndex,SegOffset pair from a checked Mach-O Bind entry |
4339 | // to get the address. |
4340 | uint64_t MachOBindEntry::address() const { |
4341 | return O->BindRebaseAddress(SegIndex: SegmentIndex, SegOffset: SegmentOffset); |
4342 | } |
4343 | |
4344 | bool MachOBindEntry::operator==(const MachOBindEntry &Other) const { |
4345 | #ifdef EXPENSIVE_CHECKS |
4346 | assert(Opcodes == Other.Opcodes && "compare iterators of different files" ); |
4347 | #else |
4348 | assert(Opcodes.data() == Other.Opcodes.data() && "compare iterators of different files" ); |
4349 | #endif |
4350 | return (Ptr == Other.Ptr) && |
4351 | (RemainingLoopCount == Other.RemainingLoopCount) && |
4352 | (Done == Other.Done); |
4353 | } |
4354 | |
4355 | // Build table of sections so SegIndex/SegOffset pairs can be translated. |
4356 | BindRebaseSegInfo::BindRebaseSegInfo(const object::MachOObjectFile *Obj) { |
4357 | uint32_t CurSegIndex = Obj->hasPageZeroSegment() ? 1 : 0; |
4358 | StringRef CurSegName; |
4359 | uint64_t CurSegAddress; |
4360 | for (const SectionRef &Section : Obj->sections()) { |
4361 | SectionInfo Info; |
4362 | Expected<StringRef> NameOrErr = Section.getName(); |
4363 | if (!NameOrErr) |
4364 | consumeError(Err: NameOrErr.takeError()); |
4365 | else |
4366 | Info.SectionName = *NameOrErr; |
4367 | Info.Address = Section.getAddress(); |
4368 | Info.Size = Section.getSize(); |
4369 | Info.SegmentName = |
4370 | Obj->getSectionFinalSegmentName(Sec: Section.getRawDataRefImpl()); |
4371 | if (Info.SegmentName != CurSegName) { |
4372 | ++CurSegIndex; |
4373 | CurSegName = Info.SegmentName; |
4374 | CurSegAddress = Info.Address; |
4375 | } |
4376 | Info.SegmentIndex = CurSegIndex - 1; |
4377 | Info.OffsetInSegment = Info.Address - CurSegAddress; |
4378 | Info.SegmentStartAddress = CurSegAddress; |
4379 | Sections.push_back(Elt: Info); |
4380 | } |
4381 | MaxSegIndex = CurSegIndex; |
4382 | } |
4383 | |
4384 | // For use with a SegIndex, SegOffset, and PointerSize triple in |
4385 | // MachOBindEntry::moveNext() to validate a MachOBindEntry or MachORebaseEntry. |
4386 | // |
4387 | // Given a SegIndex, SegOffset, and PointerSize, verify a valid section exists |
4388 | // that fully contains a pointer at that location. Multiple fixups in a bind |
4389 | // (such as with the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode) can |
4390 | // be tested via the Count and Skip parameters. |
4391 | const char *BindRebaseSegInfo::checkSegAndOffsets(int32_t SegIndex, |
4392 | uint64_t SegOffset, |
4393 | uint8_t PointerSize, |
4394 | uint64_t Count, |
4395 | uint64_t Skip) { |
4396 | if (SegIndex == -1) |
4397 | return "missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB" ; |
4398 | if (SegIndex >= MaxSegIndex) |
4399 | return "bad segIndex (too large)" ; |
4400 | for (uint64_t i = 0; i < Count; ++i) { |
4401 | uint64_t Start = SegOffset + i * (PointerSize + Skip); |
4402 | uint64_t End = Start + PointerSize; |
4403 | bool Found = false; |
4404 | for (const SectionInfo &SI : Sections) { |
4405 | if (SI.SegmentIndex != SegIndex) |
4406 | continue; |
4407 | if ((SI.OffsetInSegment<=Start) && (Start<(SI.OffsetInSegment+SI.Size))) { |
4408 | if (End <= SI.OffsetInSegment + SI.Size) { |
4409 | Found = true; |
4410 | break; |
4411 | } |
4412 | else |
4413 | return "bad offset, extends beyond section boundary" ; |
4414 | } |
4415 | } |
4416 | if (!Found) |
4417 | return "bad offset, not in section" ; |
4418 | } |
4419 | return nullptr; |
4420 | } |
4421 | |
4422 | // For use with the SegIndex of a checked Mach-O Bind or Rebase entry |
4423 | // to get the segment name. |
4424 | StringRef BindRebaseSegInfo::segmentName(int32_t SegIndex) { |
4425 | for (const SectionInfo &SI : Sections) { |
4426 | if (SI.SegmentIndex == SegIndex) |
4427 | return SI.SegmentName; |
4428 | } |
4429 | llvm_unreachable("invalid SegIndex" ); |
4430 | } |
4431 | |
4432 | // For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase |
4433 | // to get the SectionInfo. |
4434 | const BindRebaseSegInfo::SectionInfo &BindRebaseSegInfo::findSection( |
4435 | int32_t SegIndex, uint64_t SegOffset) { |
4436 | for (const SectionInfo &SI : Sections) { |
4437 | if (SI.SegmentIndex != SegIndex) |
4438 | continue; |
4439 | if (SI.OffsetInSegment > SegOffset) |
4440 | continue; |
4441 | if (SegOffset >= (SI.OffsetInSegment + SI.Size)) |
4442 | continue; |
4443 | return SI; |
4444 | } |
4445 | llvm_unreachable("SegIndex and SegOffset not in any section" ); |
4446 | } |
4447 | |
4448 | // For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase |
4449 | // entry to get the section name. |
4450 | StringRef BindRebaseSegInfo::sectionName(int32_t SegIndex, |
4451 | uint64_t SegOffset) { |
4452 | return findSection(SegIndex, SegOffset).SectionName; |
4453 | } |
4454 | |
4455 | // For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase |
4456 | // entry to get the address. |
4457 | uint64_t BindRebaseSegInfo::address(uint32_t SegIndex, uint64_t OffsetInSeg) { |
4458 | const SectionInfo &SI = findSection(SegIndex, SegOffset: OffsetInSeg); |
4459 | return SI.SegmentStartAddress + OffsetInSeg; |
4460 | } |
4461 | |
4462 | iterator_range<bind_iterator> |
4463 | MachOObjectFile::bindTable(Error &Err, MachOObjectFile *O, |
4464 | ArrayRef<uint8_t> Opcodes, bool is64, |
4465 | MachOBindEntry::Kind BKind) { |
4466 | if (O->BindRebaseSectionTable == nullptr) |
4467 | O->BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(args&: O); |
4468 | MachOBindEntry Start(&Err, O, Opcodes, is64, BKind); |
4469 | Start.moveToFirst(); |
4470 | |
4471 | MachOBindEntry Finish(&Err, O, Opcodes, is64, BKind); |
4472 | Finish.moveToEnd(); |
4473 | |
4474 | return make_range(x: bind_iterator(Start), y: bind_iterator(Finish)); |
4475 | } |
4476 | |
4477 | iterator_range<bind_iterator> MachOObjectFile::bindTable(Error &Err) { |
4478 | return bindTable(Err, O: this, Opcodes: getDyldInfoBindOpcodes(), is64: is64Bit(), |
4479 | BKind: MachOBindEntry::Kind::Regular); |
4480 | } |
4481 | |
4482 | iterator_range<bind_iterator> MachOObjectFile::lazyBindTable(Error &Err) { |
4483 | return bindTable(Err, O: this, Opcodes: getDyldInfoLazyBindOpcodes(), is64: is64Bit(), |
4484 | BKind: MachOBindEntry::Kind::Lazy); |
4485 | } |
4486 | |
4487 | iterator_range<bind_iterator> MachOObjectFile::weakBindTable(Error &Err) { |
4488 | return bindTable(Err, O: this, Opcodes: getDyldInfoWeakBindOpcodes(), is64: is64Bit(), |
4489 | BKind: MachOBindEntry::Kind::Weak); |
4490 | } |
4491 | |
4492 | iterator_range<fixup_iterator> MachOObjectFile::fixupTable(Error &Err) { |
4493 | if (BindRebaseSectionTable == nullptr) |
4494 | BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(args: this); |
4495 | |
4496 | MachOChainedFixupEntry Start(&Err, this, true); |
4497 | Start.moveToFirst(); |
4498 | |
4499 | MachOChainedFixupEntry Finish(&Err, this, false); |
4500 | Finish.moveToEnd(); |
4501 | |
4502 | return make_range(x: fixup_iterator(Start), y: fixup_iterator(Finish)); |
4503 | } |
4504 | |
4505 | MachOObjectFile::load_command_iterator |
4506 | MachOObjectFile::begin_load_commands() const { |
4507 | return LoadCommands.begin(); |
4508 | } |
4509 | |
4510 | MachOObjectFile::load_command_iterator |
4511 | MachOObjectFile::end_load_commands() const { |
4512 | return LoadCommands.end(); |
4513 | } |
4514 | |
4515 | iterator_range<MachOObjectFile::load_command_iterator> |
4516 | MachOObjectFile::load_commands() const { |
4517 | return make_range(x: begin_load_commands(), y: end_load_commands()); |
4518 | } |
4519 | |
4520 | StringRef |
4521 | MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const { |
4522 | ArrayRef<char> Raw = getSectionRawFinalSegmentName(Sec); |
4523 | return parseSegmentOrSectionName(P: Raw.data()); |
4524 | } |
4525 | |
4526 | ArrayRef<char> |
4527 | MachOObjectFile::getSectionRawName(DataRefImpl Sec) const { |
4528 | assert(Sec.d.a < Sections.size() && "Should have detected this earlier" ); |
4529 | const section_base *Base = |
4530 | reinterpret_cast<const section_base *>(Sections[Sec.d.a]); |
4531 | return ArrayRef(Base->sectname); |
4532 | } |
4533 | |
4534 | ArrayRef<char> |
4535 | MachOObjectFile::getSectionRawFinalSegmentName(DataRefImpl Sec) const { |
4536 | assert(Sec.d.a < Sections.size() && "Should have detected this earlier" ); |
4537 | const section_base *Base = |
4538 | reinterpret_cast<const section_base *>(Sections[Sec.d.a]); |
4539 | return ArrayRef(Base->segname); |
4540 | } |
4541 | |
4542 | bool |
4543 | MachOObjectFile::isRelocationScattered(const MachO::any_relocation_info &RE) |
4544 | const { |
4545 | if (getCPUType(O: *this) == MachO::CPU_TYPE_X86_64) |
4546 | return false; |
4547 | return getPlainRelocationAddress(RE) & MachO::R_SCATTERED; |
4548 | } |
4549 | |
4550 | unsigned MachOObjectFile::getPlainRelocationSymbolNum( |
4551 | const MachO::any_relocation_info &RE) const { |
4552 | if (isLittleEndian()) |
4553 | return RE.r_word1 & 0xffffff; |
4554 | return RE.r_word1 >> 8; |
4555 | } |
4556 | |
4557 | bool MachOObjectFile::getPlainRelocationExternal( |
4558 | const MachO::any_relocation_info &RE) const { |
4559 | if (isLittleEndian()) |
4560 | return (RE.r_word1 >> 27) & 1; |
4561 | return (RE.r_word1 >> 4) & 1; |
4562 | } |
4563 | |
4564 | bool MachOObjectFile::getScatteredRelocationScattered( |
4565 | const MachO::any_relocation_info &RE) const { |
4566 | return RE.r_word0 >> 31; |
4567 | } |
4568 | |
4569 | uint32_t MachOObjectFile::getScatteredRelocationValue( |
4570 | const MachO::any_relocation_info &RE) const { |
4571 | return RE.r_word1; |
4572 | } |
4573 | |
4574 | uint32_t MachOObjectFile::getScatteredRelocationType( |
4575 | const MachO::any_relocation_info &RE) const { |
4576 | return (RE.r_word0 >> 24) & 0xf; |
4577 | } |
4578 | |
4579 | unsigned MachOObjectFile::getAnyRelocationAddress( |
4580 | const MachO::any_relocation_info &RE) const { |
4581 | if (isRelocationScattered(RE)) |
4582 | return getScatteredRelocationAddress(RE); |
4583 | return getPlainRelocationAddress(RE); |
4584 | } |
4585 | |
4586 | unsigned MachOObjectFile::getAnyRelocationPCRel( |
4587 | const MachO::any_relocation_info &RE) const { |
4588 | if (isRelocationScattered(RE)) |
4589 | return getScatteredRelocationPCRel(RE); |
4590 | return getPlainRelocationPCRel(O: *this, RE); |
4591 | } |
4592 | |
4593 | unsigned MachOObjectFile::getAnyRelocationLength( |
4594 | const MachO::any_relocation_info &RE) const { |
4595 | if (isRelocationScattered(RE)) |
4596 | return getScatteredRelocationLength(RE); |
4597 | return getPlainRelocationLength(O: *this, RE); |
4598 | } |
4599 | |
4600 | unsigned |
4601 | MachOObjectFile::getAnyRelocationType( |
4602 | const MachO::any_relocation_info &RE) const { |
4603 | if (isRelocationScattered(RE)) |
4604 | return getScatteredRelocationType(RE); |
4605 | return getPlainRelocationType(O: *this, RE); |
4606 | } |
4607 | |
4608 | SectionRef |
4609 | MachOObjectFile::getAnyRelocationSection( |
4610 | const MachO::any_relocation_info &RE) const { |
4611 | if (isRelocationScattered(RE) || getPlainRelocationExternal(RE)) |
4612 | return *section_end(); |
4613 | unsigned SecNum = getPlainRelocationSymbolNum(RE); |
4614 | if (SecNum == MachO::R_ABS || SecNum > Sections.size()) |
4615 | return *section_end(); |
4616 | DataRefImpl DRI; |
4617 | DRI.d.a = SecNum - 1; |
4618 | return SectionRef(DRI, this); |
4619 | } |
4620 | |
4621 | MachO::section MachOObjectFile::getSection(DataRefImpl DRI) const { |
4622 | assert(DRI.d.a < Sections.size() && "Should have detected this earlier" ); |
4623 | return getStruct<MachO::section>(O: *this, P: Sections[DRI.d.a]); |
4624 | } |
4625 | |
4626 | MachO::section_64 MachOObjectFile::getSection64(DataRefImpl DRI) const { |
4627 | assert(DRI.d.a < Sections.size() && "Should have detected this earlier" ); |
4628 | return getStruct<MachO::section_64>(O: *this, P: Sections[DRI.d.a]); |
4629 | } |
4630 | |
4631 | MachO::section MachOObjectFile::getSection(const LoadCommandInfo &L, |
4632 | unsigned Index) const { |
4633 | const char *Sec = getSectionPtr(O: *this, L, Sec: Index); |
4634 | return getStruct<MachO::section>(O: *this, P: Sec); |
4635 | } |
4636 | |
4637 | MachO::section_64 MachOObjectFile::getSection64(const LoadCommandInfo &L, |
4638 | unsigned Index) const { |
4639 | const char *Sec = getSectionPtr(O: *this, L, Sec: Index); |
4640 | return getStruct<MachO::section_64>(O: *this, P: Sec); |
4641 | } |
4642 | |
4643 | MachO::nlist |
4644 | MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI) const { |
4645 | const char *P = reinterpret_cast<const char *>(DRI.p); |
4646 | return getStruct<MachO::nlist>(O: *this, P); |
4647 | } |
4648 | |
4649 | MachO::nlist_64 |
4650 | MachOObjectFile::getSymbol64TableEntry(DataRefImpl DRI) const { |
4651 | const char *P = reinterpret_cast<const char *>(DRI.p); |
4652 | return getStruct<MachO::nlist_64>(O: *this, P); |
4653 | } |
4654 | |
4655 | MachO::linkedit_data_command |
4656 | MachOObjectFile::getLinkeditDataLoadCommand(const LoadCommandInfo &L) const { |
4657 | return getStruct<MachO::linkedit_data_command>(O: *this, P: L.Ptr); |
4658 | } |
4659 | |
4660 | MachO::segment_command |
4661 | MachOObjectFile::getSegmentLoadCommand(const LoadCommandInfo &L) const { |
4662 | return getStruct<MachO::segment_command>(O: *this, P: L.Ptr); |
4663 | } |
4664 | |
4665 | MachO::segment_command_64 |
4666 | MachOObjectFile::getSegment64LoadCommand(const LoadCommandInfo &L) const { |
4667 | return getStruct<MachO::segment_command_64>(O: *this, P: L.Ptr); |
4668 | } |
4669 | |
4670 | MachO::linker_option_command |
4671 | MachOObjectFile::getLinkerOptionLoadCommand(const LoadCommandInfo &L) const { |
4672 | return getStruct<MachO::linker_option_command>(O: *this, P: L.Ptr); |
4673 | } |
4674 | |
4675 | MachO::version_min_command |
4676 | MachOObjectFile::getVersionMinLoadCommand(const LoadCommandInfo &L) const { |
4677 | return getStruct<MachO::version_min_command>(O: *this, P: L.Ptr); |
4678 | } |
4679 | |
4680 | MachO::note_command |
4681 | MachOObjectFile::getNoteLoadCommand(const LoadCommandInfo &L) const { |
4682 | return getStruct<MachO::note_command>(O: *this, P: L.Ptr); |
4683 | } |
4684 | |
4685 | MachO::build_version_command |
4686 | MachOObjectFile::getBuildVersionLoadCommand(const LoadCommandInfo &L) const { |
4687 | return getStruct<MachO::build_version_command>(O: *this, P: L.Ptr); |
4688 | } |
4689 | |
4690 | MachO::build_tool_version |
4691 | MachOObjectFile::getBuildToolVersion(unsigned index) const { |
4692 | return getStruct<MachO::build_tool_version>(O: *this, P: BuildTools[index]); |
4693 | } |
4694 | |
4695 | MachO::dylib_command |
4696 | MachOObjectFile::getDylibIDLoadCommand(const LoadCommandInfo &L) const { |
4697 | return getStruct<MachO::dylib_command>(O: *this, P: L.Ptr); |
4698 | } |
4699 | |
4700 | MachO::dyld_info_command |
4701 | MachOObjectFile::getDyldInfoLoadCommand(const LoadCommandInfo &L) const { |
4702 | return getStruct<MachO::dyld_info_command>(O: *this, P: L.Ptr); |
4703 | } |
4704 | |
4705 | MachO::dylinker_command |
4706 | MachOObjectFile::getDylinkerCommand(const LoadCommandInfo &L) const { |
4707 | return getStruct<MachO::dylinker_command>(O: *this, P: L.Ptr); |
4708 | } |
4709 | |
4710 | MachO::uuid_command |
4711 | MachOObjectFile::getUuidCommand(const LoadCommandInfo &L) const { |
4712 | return getStruct<MachO::uuid_command>(O: *this, P: L.Ptr); |
4713 | } |
4714 | |
4715 | MachO::rpath_command |
4716 | MachOObjectFile::getRpathCommand(const LoadCommandInfo &L) const { |
4717 | return getStruct<MachO::rpath_command>(O: *this, P: L.Ptr); |
4718 | } |
4719 | |
4720 | MachO::source_version_command |
4721 | MachOObjectFile::getSourceVersionCommand(const LoadCommandInfo &L) const { |
4722 | return getStruct<MachO::source_version_command>(O: *this, P: L.Ptr); |
4723 | } |
4724 | |
4725 | MachO::entry_point_command |
4726 | MachOObjectFile::getEntryPointCommand(const LoadCommandInfo &L) const { |
4727 | return getStruct<MachO::entry_point_command>(O: *this, P: L.Ptr); |
4728 | } |
4729 | |
4730 | MachO::encryption_info_command |
4731 | MachOObjectFile::getEncryptionInfoCommand(const LoadCommandInfo &L) const { |
4732 | return getStruct<MachO::encryption_info_command>(O: *this, P: L.Ptr); |
4733 | } |
4734 | |
4735 | MachO::encryption_info_command_64 |
4736 | MachOObjectFile::getEncryptionInfoCommand64(const LoadCommandInfo &L) const { |
4737 | return getStruct<MachO::encryption_info_command_64>(O: *this, P: L.Ptr); |
4738 | } |
4739 | |
4740 | MachO::sub_framework_command |
4741 | MachOObjectFile::getSubFrameworkCommand(const LoadCommandInfo &L) const { |
4742 | return getStruct<MachO::sub_framework_command>(O: *this, P: L.Ptr); |
4743 | } |
4744 | |
4745 | MachO::sub_umbrella_command |
4746 | MachOObjectFile::getSubUmbrellaCommand(const LoadCommandInfo &L) const { |
4747 | return getStruct<MachO::sub_umbrella_command>(O: *this, P: L.Ptr); |
4748 | } |
4749 | |
4750 | MachO::sub_library_command |
4751 | MachOObjectFile::getSubLibraryCommand(const LoadCommandInfo &L) const { |
4752 | return getStruct<MachO::sub_library_command>(O: *this, P: L.Ptr); |
4753 | } |
4754 | |
4755 | MachO::sub_client_command |
4756 | MachOObjectFile::getSubClientCommand(const LoadCommandInfo &L) const { |
4757 | return getStruct<MachO::sub_client_command>(O: *this, P: L.Ptr); |
4758 | } |
4759 | |
4760 | MachO::routines_command |
4761 | MachOObjectFile::getRoutinesCommand(const LoadCommandInfo &L) const { |
4762 | return getStruct<MachO::routines_command>(O: *this, P: L.Ptr); |
4763 | } |
4764 | |
4765 | MachO::routines_command_64 |
4766 | MachOObjectFile::getRoutinesCommand64(const LoadCommandInfo &L) const { |
4767 | return getStruct<MachO::routines_command_64>(O: *this, P: L.Ptr); |
4768 | } |
4769 | |
4770 | MachO::thread_command |
4771 | MachOObjectFile::getThreadCommand(const LoadCommandInfo &L) const { |
4772 | return getStruct<MachO::thread_command>(O: *this, P: L.Ptr); |
4773 | } |
4774 | |
4775 | MachO::fileset_entry_command |
4776 | MachOObjectFile::getFilesetEntryLoadCommand(const LoadCommandInfo &L) const { |
4777 | return getStruct<MachO::fileset_entry_command>(O: *this, P: L.Ptr); |
4778 | } |
4779 | |
4780 | MachO::any_relocation_info |
4781 | MachOObjectFile::getRelocation(DataRefImpl Rel) const { |
4782 | uint32_t Offset; |
4783 | if (getHeader().filetype == MachO::MH_OBJECT) { |
4784 | DataRefImpl Sec; |
4785 | Sec.d.a = Rel.d.a; |
4786 | if (is64Bit()) { |
4787 | MachO::section_64 Sect = getSection64(DRI: Sec); |
4788 | Offset = Sect.reloff; |
4789 | } else { |
4790 | MachO::section Sect = getSection(DRI: Sec); |
4791 | Offset = Sect.reloff; |
4792 | } |
4793 | } else { |
4794 | MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand(); |
4795 | if (Rel.d.a == 0) |
4796 | Offset = DysymtabLoadCmd.extreloff; // Offset to the external relocations |
4797 | else |
4798 | Offset = DysymtabLoadCmd.locreloff; // Offset to the local relocations |
4799 | } |
4800 | |
4801 | auto P = reinterpret_cast<const MachO::any_relocation_info *>( |
4802 | getPtr(O: *this, Offset)) + Rel.d.b; |
4803 | return getStruct<MachO::any_relocation_info>( |
4804 | O: *this, P: reinterpret_cast<const char *>(P)); |
4805 | } |
4806 | |
4807 | MachO::data_in_code_entry |
4808 | MachOObjectFile::getDice(DataRefImpl Rel) const { |
4809 | const char *P = reinterpret_cast<const char *>(Rel.p); |
4810 | return getStruct<MachO::data_in_code_entry>(O: *this, P); |
4811 | } |
4812 | |
4813 | const MachO::mach_header &MachOObjectFile::() const { |
4814 | return Header; |
4815 | } |
4816 | |
4817 | const MachO::mach_header_64 &MachOObjectFile::() const { |
4818 | assert(is64Bit()); |
4819 | return Header64; |
4820 | } |
4821 | |
4822 | uint32_t MachOObjectFile::getIndirectSymbolTableEntry( |
4823 | const MachO::dysymtab_command &DLC, |
4824 | unsigned Index) const { |
4825 | uint64_t Offset = DLC.indirectsymoff + Index * sizeof(uint32_t); |
4826 | return getStruct<uint32_t>(O: *this, P: getPtr(O: *this, Offset)); |
4827 | } |
4828 | |
4829 | MachO::data_in_code_entry |
4830 | MachOObjectFile::getDataInCodeTableEntry(uint32_t DataOffset, |
4831 | unsigned Index) const { |
4832 | uint64_t Offset = DataOffset + Index * sizeof(MachO::data_in_code_entry); |
4833 | return getStruct<MachO::data_in_code_entry>(O: *this, P: getPtr(O: *this, Offset)); |
4834 | } |
4835 | |
4836 | MachO::symtab_command MachOObjectFile::getSymtabLoadCommand() const { |
4837 | if (SymtabLoadCmd) |
4838 | return getStruct<MachO::symtab_command>(O: *this, P: SymtabLoadCmd); |
4839 | |
4840 | // If there is no SymtabLoadCmd return a load command with zero'ed fields. |
4841 | MachO::symtab_command Cmd; |
4842 | Cmd.cmd = MachO::LC_SYMTAB; |
4843 | Cmd.cmdsize = sizeof(MachO::symtab_command); |
4844 | Cmd.symoff = 0; |
4845 | Cmd.nsyms = 0; |
4846 | Cmd.stroff = 0; |
4847 | Cmd.strsize = 0; |
4848 | return Cmd; |
4849 | } |
4850 | |
4851 | MachO::dysymtab_command MachOObjectFile::getDysymtabLoadCommand() const { |
4852 | if (DysymtabLoadCmd) |
4853 | return getStruct<MachO::dysymtab_command>(O: *this, P: DysymtabLoadCmd); |
4854 | |
4855 | // If there is no DysymtabLoadCmd return a load command with zero'ed fields. |
4856 | MachO::dysymtab_command Cmd; |
4857 | Cmd.cmd = MachO::LC_DYSYMTAB; |
4858 | Cmd.cmdsize = sizeof(MachO::dysymtab_command); |
4859 | Cmd.ilocalsym = 0; |
4860 | Cmd.nlocalsym = 0; |
4861 | Cmd.iextdefsym = 0; |
4862 | Cmd.nextdefsym = 0; |
4863 | Cmd.iundefsym = 0; |
4864 | Cmd.nundefsym = 0; |
4865 | Cmd.tocoff = 0; |
4866 | Cmd.ntoc = 0; |
4867 | Cmd.modtaboff = 0; |
4868 | Cmd.nmodtab = 0; |
4869 | Cmd.extrefsymoff = 0; |
4870 | Cmd.nextrefsyms = 0; |
4871 | Cmd.indirectsymoff = 0; |
4872 | Cmd.nindirectsyms = 0; |
4873 | Cmd.extreloff = 0; |
4874 | Cmd.nextrel = 0; |
4875 | Cmd.locreloff = 0; |
4876 | Cmd.nlocrel = 0; |
4877 | return Cmd; |
4878 | } |
4879 | |
4880 | MachO::linkedit_data_command |
4881 | MachOObjectFile::getDataInCodeLoadCommand() const { |
4882 | if (DataInCodeLoadCmd) |
4883 | return getStruct<MachO::linkedit_data_command>(O: *this, P: DataInCodeLoadCmd); |
4884 | |
4885 | // If there is no DataInCodeLoadCmd return a load command with zero'ed fields. |
4886 | MachO::linkedit_data_command Cmd; |
4887 | Cmd.cmd = MachO::LC_DATA_IN_CODE; |
4888 | Cmd.cmdsize = sizeof(MachO::linkedit_data_command); |
4889 | Cmd.dataoff = 0; |
4890 | Cmd.datasize = 0; |
4891 | return Cmd; |
4892 | } |
4893 | |
4894 | MachO::linkedit_data_command |
4895 | MachOObjectFile::getLinkOptHintsLoadCommand() const { |
4896 | if (LinkOptHintsLoadCmd) |
4897 | return getStruct<MachO::linkedit_data_command>(O: *this, P: LinkOptHintsLoadCmd); |
4898 | |
4899 | // If there is no LinkOptHintsLoadCmd return a load command with zero'ed |
4900 | // fields. |
4901 | MachO::linkedit_data_command Cmd; |
4902 | Cmd.cmd = MachO::LC_LINKER_OPTIMIZATION_HINT; |
4903 | Cmd.cmdsize = sizeof(MachO::linkedit_data_command); |
4904 | Cmd.dataoff = 0; |
4905 | Cmd.datasize = 0; |
4906 | return Cmd; |
4907 | } |
4908 | |
4909 | ArrayRef<uint8_t> MachOObjectFile::getDyldInfoRebaseOpcodes() const { |
4910 | if (!DyldInfoLoadCmd) |
4911 | return std::nullopt; |
4912 | |
4913 | auto DyldInfoOrErr = |
4914 | getStructOrErr<MachO::dyld_info_command>(O: *this, P: DyldInfoLoadCmd); |
4915 | if (!DyldInfoOrErr) |
4916 | return std::nullopt; |
4917 | MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); |
4918 | const uint8_t *Ptr = |
4919 | reinterpret_cast<const uint8_t *>(getPtr(O: *this, Offset: DyldInfo.rebase_off)); |
4920 | return ArrayRef(Ptr, DyldInfo.rebase_size); |
4921 | } |
4922 | |
4923 | ArrayRef<uint8_t> MachOObjectFile::getDyldInfoBindOpcodes() const { |
4924 | if (!DyldInfoLoadCmd) |
4925 | return std::nullopt; |
4926 | |
4927 | auto DyldInfoOrErr = |
4928 | getStructOrErr<MachO::dyld_info_command>(O: *this, P: DyldInfoLoadCmd); |
4929 | if (!DyldInfoOrErr) |
4930 | return std::nullopt; |
4931 | MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); |
4932 | const uint8_t *Ptr = |
4933 | reinterpret_cast<const uint8_t *>(getPtr(O: *this, Offset: DyldInfo.bind_off)); |
4934 | return ArrayRef(Ptr, DyldInfo.bind_size); |
4935 | } |
4936 | |
4937 | ArrayRef<uint8_t> MachOObjectFile::getDyldInfoWeakBindOpcodes() const { |
4938 | if (!DyldInfoLoadCmd) |
4939 | return std::nullopt; |
4940 | |
4941 | auto DyldInfoOrErr = |
4942 | getStructOrErr<MachO::dyld_info_command>(O: *this, P: DyldInfoLoadCmd); |
4943 | if (!DyldInfoOrErr) |
4944 | return std::nullopt; |
4945 | MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); |
4946 | const uint8_t *Ptr = |
4947 | reinterpret_cast<const uint8_t *>(getPtr(O: *this, Offset: DyldInfo.weak_bind_off)); |
4948 | return ArrayRef(Ptr, DyldInfo.weak_bind_size); |
4949 | } |
4950 | |
4951 | ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const { |
4952 | if (!DyldInfoLoadCmd) |
4953 | return std::nullopt; |
4954 | |
4955 | auto DyldInfoOrErr = |
4956 | getStructOrErr<MachO::dyld_info_command>(O: *this, P: DyldInfoLoadCmd); |
4957 | if (!DyldInfoOrErr) |
4958 | return std::nullopt; |
4959 | MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); |
4960 | const uint8_t *Ptr = |
4961 | reinterpret_cast<const uint8_t *>(getPtr(O: *this, Offset: DyldInfo.lazy_bind_off)); |
4962 | return ArrayRef(Ptr, DyldInfo.lazy_bind_size); |
4963 | } |
4964 | |
4965 | ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const { |
4966 | if (!DyldInfoLoadCmd) |
4967 | return std::nullopt; |
4968 | |
4969 | auto DyldInfoOrErr = |
4970 | getStructOrErr<MachO::dyld_info_command>(O: *this, P: DyldInfoLoadCmd); |
4971 | if (!DyldInfoOrErr) |
4972 | return std::nullopt; |
4973 | MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); |
4974 | const uint8_t *Ptr = |
4975 | reinterpret_cast<const uint8_t *>(getPtr(O: *this, Offset: DyldInfo.export_off)); |
4976 | return ArrayRef(Ptr, DyldInfo.export_size); |
4977 | } |
4978 | |
4979 | Expected<std::optional<MachO::linkedit_data_command>> |
4980 | MachOObjectFile::getChainedFixupsLoadCommand() const { |
4981 | // Load the dyld chained fixups load command. |
4982 | if (!DyldChainedFixupsLoadCmd) |
4983 | return std::nullopt; |
4984 | auto DyldChainedFixupsOrErr = getStructOrErr<MachO::linkedit_data_command>( |
4985 | O: *this, P: DyldChainedFixupsLoadCmd); |
4986 | if (!DyldChainedFixupsOrErr) |
4987 | return DyldChainedFixupsOrErr.takeError(); |
4988 | const MachO::linkedit_data_command &DyldChainedFixups = |
4989 | *DyldChainedFixupsOrErr; |
4990 | |
4991 | // If the load command is present but the data offset has been zeroed out, |
4992 | // as is the case for dylib stubs, return std::nullopt (no error). |
4993 | if (!DyldChainedFixups.dataoff) |
4994 | return std::nullopt; |
4995 | return DyldChainedFixups; |
4996 | } |
4997 | |
4998 | Expected<std::optional<MachO::dyld_chained_fixups_header>> |
4999 | MachOObjectFile::() const { |
5000 | auto CFOrErr = getChainedFixupsLoadCommand(); |
5001 | if (!CFOrErr) |
5002 | return CFOrErr.takeError(); |
5003 | if (!CFOrErr->has_value()) |
5004 | return std::nullopt; |
5005 | |
5006 | const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr; |
5007 | |
5008 | uint64_t = DyldChainedFixups.dataoff; |
5009 | uint64_t CFSize = DyldChainedFixups.datasize; |
5010 | |
5011 | // Load the dyld chained fixups header. |
5012 | const char * = getPtr(O: *this, Offset: CFHeaderOffset); |
5013 | auto = |
5014 | getStructOrErr<MachO::dyld_chained_fixups_header>(O: *this, P: CFHeaderPtr); |
5015 | if (!CFHeaderOrErr) |
5016 | return CFHeaderOrErr.takeError(); |
5017 | MachO::dyld_chained_fixups_header = CFHeaderOrErr.get(); |
5018 | |
5019 | // Reject unknown chained fixup formats. |
5020 | if (CFHeader.fixups_version != 0) |
5021 | return malformedError(Msg: Twine("bad chained fixups: unknown version: " ) + |
5022 | Twine(CFHeader.fixups_version)); |
5023 | if (CFHeader.imports_format < 1 || CFHeader.imports_format > 3) |
5024 | return malformedError( |
5025 | Msg: Twine("bad chained fixups: unknown imports format: " ) + |
5026 | Twine(CFHeader.imports_format)); |
5027 | |
5028 | // Validate the image format. |
5029 | // |
5030 | // Load the image starts. |
5031 | uint64_t CFImageStartsOffset = (CFHeaderOffset + CFHeader.starts_offset); |
5032 | if (CFHeader.starts_offset < sizeof(MachO::dyld_chained_fixups_header)) { |
5033 | return malformedError(Msg: Twine("bad chained fixups: image starts offset " ) + |
5034 | Twine(CFHeader.starts_offset) + |
5035 | " overlaps with chained fixups header" ); |
5036 | } |
5037 | uint32_t EndOffset = CFHeaderOffset + CFSize; |
5038 | if (CFImageStartsOffset + sizeof(MachO::dyld_chained_starts_in_image) > |
5039 | EndOffset) { |
5040 | return malformedError(Msg: Twine("bad chained fixups: image starts end " ) + |
5041 | Twine(CFImageStartsOffset + |
5042 | sizeof(MachO::dyld_chained_starts_in_image)) + |
5043 | " extends past end " + Twine(EndOffset)); |
5044 | } |
5045 | |
5046 | return CFHeader; |
5047 | } |
5048 | |
5049 | Expected<std::pair<size_t, std::vector<ChainedFixupsSegment>>> |
5050 | MachOObjectFile::getChainedFixupsSegments() const { |
5051 | auto CFOrErr = getChainedFixupsLoadCommand(); |
5052 | if (!CFOrErr) |
5053 | return CFOrErr.takeError(); |
5054 | |
5055 | std::vector<ChainedFixupsSegment> Segments; |
5056 | if (!CFOrErr->has_value()) |
5057 | return std::make_pair(x: 0, y&: Segments); |
5058 | |
5059 | const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr; |
5060 | |
5061 | auto = getChainedFixupsHeader(); |
5062 | if (!HeaderOrErr) |
5063 | return HeaderOrErr.takeError(); |
5064 | if (!HeaderOrErr->has_value()) |
5065 | return std::make_pair(x: 0, y&: Segments); |
5066 | const MachO::dyld_chained_fixups_header & = **HeaderOrErr; |
5067 | |
5068 | const char *Contents = getPtr(O: *this, Offset: DyldChainedFixups.dataoff); |
5069 | |
5070 | auto ImageStartsOrErr = getStructOrErr<MachO::dyld_chained_starts_in_image>( |
5071 | O: *this, P: Contents + Header.starts_offset); |
5072 | if (!ImageStartsOrErr) |
5073 | return ImageStartsOrErr.takeError(); |
5074 | const MachO::dyld_chained_starts_in_image &ImageStarts = *ImageStartsOrErr; |
5075 | |
5076 | const char *SegOffsPtr = |
5077 | Contents + Header.starts_offset + |
5078 | offsetof(MachO::dyld_chained_starts_in_image, seg_info_offset); |
5079 | const char *SegOffsEnd = |
5080 | SegOffsPtr + ImageStarts.seg_count * sizeof(uint32_t); |
5081 | if (SegOffsEnd > Contents + DyldChainedFixups.datasize) |
5082 | return malformedError( |
5083 | Msg: "bad chained fixups: seg_info_offset extends past end" ); |
5084 | |
5085 | const char *LastSegEnd = nullptr; |
5086 | for (size_t I = 0, N = ImageStarts.seg_count; I < N; ++I) { |
5087 | auto OffOrErr = |
5088 | getStructOrErr<uint32_t>(O: *this, P: SegOffsPtr + I * sizeof(uint32_t)); |
5089 | if (!OffOrErr) |
5090 | return OffOrErr.takeError(); |
5091 | // seg_info_offset == 0 means there is no associated starts_in_segment |
5092 | // entry. |
5093 | if (!*OffOrErr) |
5094 | continue; |
5095 | |
5096 | auto Fail = [&](Twine Message) { |
5097 | return malformedError(Msg: "bad chained fixups: segment info" + Twine(I) + |
5098 | " at offset " + Twine(*OffOrErr) + Message); |
5099 | }; |
5100 | |
5101 | const char *SegPtr = Contents + Header.starts_offset + *OffOrErr; |
5102 | if (LastSegEnd && SegPtr < LastSegEnd) |
5103 | return Fail(" overlaps with previous segment info" ); |
5104 | |
5105 | auto SegOrErr = |
5106 | getStructOrErr<MachO::dyld_chained_starts_in_segment>(O: *this, P: SegPtr); |
5107 | if (!SegOrErr) |
5108 | return SegOrErr.takeError(); |
5109 | const MachO::dyld_chained_starts_in_segment &Seg = *SegOrErr; |
5110 | |
5111 | LastSegEnd = SegPtr + Seg.size; |
5112 | if (Seg.pointer_format < 1 || Seg.pointer_format > 12) |
5113 | return Fail(" has unknown pointer format: " + Twine(Seg.pointer_format)); |
5114 | |
5115 | const char *PageStart = |
5116 | SegPtr + offsetof(MachO::dyld_chained_starts_in_segment, page_start); |
5117 | const char *PageEnd = PageStart + Seg.page_count * sizeof(uint16_t); |
5118 | if (PageEnd > SegPtr + Seg.size) |
5119 | return Fail(" : page_starts extend past seg_info size" ); |
5120 | |
5121 | // FIXME: This does not account for multiple offsets on a single page |
5122 | // (DYLD_CHAINED_PTR_START_MULTI; 32-bit only). |
5123 | std::vector<uint16_t> PageStarts; |
5124 | for (size_t PageIdx = 0; PageIdx < Seg.page_count; ++PageIdx) { |
5125 | uint16_t Start; |
5126 | memcpy(dest: &Start, src: PageStart + PageIdx * sizeof(uint16_t), n: sizeof(uint16_t)); |
5127 | if (isLittleEndian() != sys::IsLittleEndianHost) |
5128 | sys::swapByteOrder(Value&: Start); |
5129 | PageStarts.push_back(x: Start); |
5130 | } |
5131 | |
5132 | Segments.emplace_back(args&: I, args&: *OffOrErr, args: Seg, args: std::move(PageStarts)); |
5133 | } |
5134 | |
5135 | return std::make_pair(x: ImageStarts.seg_count, y&: Segments); |
5136 | } |
5137 | |
5138 | // The special library ordinals have a negative value, but they are encoded in |
5139 | // an unsigned bitfield, so we need to sign extend the value. |
5140 | template <typename T> static int getEncodedOrdinal(T Value) { |
5141 | if (Value == static_cast<T>(MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE) || |
5142 | Value == static_cast<T>(MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP) || |
5143 | Value == static_cast<T>(MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP)) |
5144 | return SignExtend32<sizeof(T) * CHAR_BIT>(Value); |
5145 | return Value; |
5146 | } |
5147 | |
5148 | template <typename T, unsigned N> |
5149 | static std::array<T, N> getArray(const MachOObjectFile &O, const void *Ptr) { |
5150 | std::array<T, N> RawValue; |
5151 | memcpy(RawValue.data(), Ptr, N * sizeof(T)); |
5152 | if (O.isLittleEndian() != sys::IsLittleEndianHost) |
5153 | for (auto &Element : RawValue) |
5154 | sys::swapByteOrder(Element); |
5155 | return RawValue; |
5156 | } |
5157 | |
5158 | Expected<std::vector<ChainedFixupTarget>> |
5159 | MachOObjectFile::getDyldChainedFixupTargets() const { |
5160 | auto CFOrErr = getChainedFixupsLoadCommand(); |
5161 | if (!CFOrErr) |
5162 | return CFOrErr.takeError(); |
5163 | |
5164 | std::vector<ChainedFixupTarget> Targets; |
5165 | if (!CFOrErr->has_value()) |
5166 | return Targets; |
5167 | |
5168 | const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr; |
5169 | |
5170 | auto = getChainedFixupsHeader(); |
5171 | if (!CFHeaderOrErr) |
5172 | return CFHeaderOrErr.takeError(); |
5173 | if (!(*CFHeaderOrErr)) |
5174 | return Targets; |
5175 | const MachO::dyld_chained_fixups_header & = **CFHeaderOrErr; |
5176 | |
5177 | size_t ImportSize = 0; |
5178 | if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT) |
5179 | ImportSize = sizeof(MachO::dyld_chained_import); |
5180 | else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND) |
5181 | ImportSize = sizeof(MachO::dyld_chained_import_addend); |
5182 | else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND64) |
5183 | ImportSize = sizeof(MachO::dyld_chained_import_addend64); |
5184 | else |
5185 | return malformedError(Msg: "bad chained fixups: unknown imports format: " + |
5186 | Twine(Header.imports_format)); |
5187 | |
5188 | const char *Contents = getPtr(O: *this, Offset: DyldChainedFixups.dataoff); |
5189 | const char *Imports = Contents + Header.imports_offset; |
5190 | size_t ImportsEndOffset = |
5191 | Header.imports_offset + ImportSize * Header.imports_count; |
5192 | const char *ImportsEnd = Contents + ImportsEndOffset; |
5193 | const char *Symbols = Contents + Header.symbols_offset; |
5194 | const char *SymbolsEnd = Contents + DyldChainedFixups.datasize; |
5195 | |
5196 | if (ImportsEnd > Symbols) |
5197 | return malformedError(Msg: "bad chained fixups: imports end " + |
5198 | Twine(ImportsEndOffset) + " extends past end " + |
5199 | Twine(DyldChainedFixups.datasize)); |
5200 | |
5201 | if (ImportsEnd > Symbols) |
5202 | return malformedError(Msg: "bad chained fixups: imports end " + |
5203 | Twine(ImportsEndOffset) + " overlaps with symbols" ); |
5204 | |
5205 | // We use bit manipulation to extract data from the bitfields. This is correct |
5206 | // for both LE and BE hosts, but we assume that the object is little-endian. |
5207 | if (!isLittleEndian()) |
5208 | return createError(Err: "parsing big-endian chained fixups is not implemented" ); |
5209 | for (const char *ImportPtr = Imports; ImportPtr < ImportsEnd; |
5210 | ImportPtr += ImportSize) { |
5211 | int LibOrdinal; |
5212 | bool WeakImport; |
5213 | uint32_t NameOffset; |
5214 | uint64_t Addend; |
5215 | if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT) { |
5216 | static_assert(sizeof(uint32_t) == sizeof(MachO::dyld_chained_import)); |
5217 | auto RawValue = getArray<uint32_t, 1>(O: *this, Ptr: ImportPtr); |
5218 | |
5219 | LibOrdinal = getEncodedOrdinal<uint8_t>(Value: RawValue[0] & 0xFF); |
5220 | WeakImport = (RawValue[0] >> 8) & 1; |
5221 | NameOffset = RawValue[0] >> 9; |
5222 | Addend = 0; |
5223 | } else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND) { |
5224 | static_assert(sizeof(uint64_t) == |
5225 | sizeof(MachO::dyld_chained_import_addend)); |
5226 | auto RawValue = getArray<uint32_t, 2>(O: *this, Ptr: ImportPtr); |
5227 | |
5228 | LibOrdinal = getEncodedOrdinal<uint8_t>(Value: RawValue[0] & 0xFF); |
5229 | WeakImport = (RawValue[0] >> 8) & 1; |
5230 | NameOffset = RawValue[0] >> 9; |
5231 | Addend = bit_cast<int32_t>(from: RawValue[1]); |
5232 | } else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND64) { |
5233 | static_assert(2 * sizeof(uint64_t) == |
5234 | sizeof(MachO::dyld_chained_import_addend64)); |
5235 | auto RawValue = getArray<uint64_t, 2>(O: *this, Ptr: ImportPtr); |
5236 | |
5237 | LibOrdinal = getEncodedOrdinal<uint16_t>(Value: RawValue[0] & 0xFFFF); |
5238 | NameOffset = (RawValue[0] >> 16) & 1; |
5239 | WeakImport = RawValue[0] >> 17; |
5240 | Addend = RawValue[1]; |
5241 | } else { |
5242 | llvm_unreachable("Import format should have been checked" ); |
5243 | } |
5244 | |
5245 | const char *Str = Symbols + NameOffset; |
5246 | if (Str >= SymbolsEnd) |
5247 | return malformedError(Msg: "bad chained fixups: symbol offset " + |
5248 | Twine(NameOffset) + " extends past end " + |
5249 | Twine(DyldChainedFixups.datasize)); |
5250 | Targets.emplace_back(args&: LibOrdinal, args&: NameOffset, args&: Str, args&: Addend, args&: WeakImport); |
5251 | } |
5252 | |
5253 | return std::move(Targets); |
5254 | } |
5255 | |
5256 | ArrayRef<uint8_t> MachOObjectFile::getDyldExportsTrie() const { |
5257 | if (!DyldExportsTrieLoadCmd) |
5258 | return std::nullopt; |
5259 | |
5260 | auto DyldExportsTrieOrError = getStructOrErr<MachO::linkedit_data_command>( |
5261 | O: *this, P: DyldExportsTrieLoadCmd); |
5262 | if (!DyldExportsTrieOrError) |
5263 | return std::nullopt; |
5264 | MachO::linkedit_data_command DyldExportsTrie = DyldExportsTrieOrError.get(); |
5265 | const uint8_t *Ptr = |
5266 | reinterpret_cast<const uint8_t *>(getPtr(O: *this, Offset: DyldExportsTrie.dataoff)); |
5267 | return ArrayRef(Ptr, DyldExportsTrie.datasize); |
5268 | } |
5269 | |
5270 | SmallVector<uint64_t> MachOObjectFile::getFunctionStarts() const { |
5271 | if (!FuncStartsLoadCmd) |
5272 | return {}; |
5273 | |
5274 | auto InfoOrErr = |
5275 | getStructOrErr<MachO::linkedit_data_command>(O: *this, P: FuncStartsLoadCmd); |
5276 | if (!InfoOrErr) |
5277 | return {}; |
5278 | |
5279 | MachO::linkedit_data_command Info = InfoOrErr.get(); |
5280 | SmallVector<uint64_t, 8> FunctionStarts; |
5281 | this->ReadULEB128s(Index: Info.dataoff, Out&: FunctionStarts); |
5282 | return std::move(FunctionStarts); |
5283 | } |
5284 | |
5285 | ArrayRef<uint8_t> MachOObjectFile::getUuid() const { |
5286 | if (!UuidLoadCmd) |
5287 | return std::nullopt; |
5288 | // Returning a pointer is fine as uuid doesn't need endian swapping. |
5289 | const char *Ptr = UuidLoadCmd + offsetof(MachO::uuid_command, uuid); |
5290 | return ArrayRef(reinterpret_cast<const uint8_t *>(Ptr), 16); |
5291 | } |
5292 | |
5293 | StringRef MachOObjectFile::getStringTableData() const { |
5294 | MachO::symtab_command S = getSymtabLoadCommand(); |
5295 | return getData().substr(Start: S.stroff, N: S.strsize); |
5296 | } |
5297 | |
5298 | bool MachOObjectFile::is64Bit() const { |
5299 | return getType() == getMachOType(isLE: false, is64Bits: true) || |
5300 | getType() == getMachOType(isLE: true, is64Bits: true); |
5301 | } |
5302 | |
5303 | void MachOObjectFile::ReadULEB128s(uint64_t Index, |
5304 | SmallVectorImpl<uint64_t> &Out) const { |
5305 | DataExtractor (ObjectFile::getData(), true, 0); |
5306 | |
5307 | uint64_t offset = Index; |
5308 | uint64_t data = 0; |
5309 | while (uint64_t delta = extractor.getULEB128(offset_ptr: &offset)) { |
5310 | data += delta; |
5311 | Out.push_back(Elt: data); |
5312 | } |
5313 | } |
5314 | |
5315 | bool MachOObjectFile::isRelocatableObject() const { |
5316 | return getHeader().filetype == MachO::MH_OBJECT; |
5317 | } |
5318 | |
5319 | /// Create a MachOObjectFile instance from a given buffer. |
5320 | /// |
5321 | /// \param Buffer Memory buffer containing the MachO binary data. |
5322 | /// \param UniversalCputype CPU type when the MachO part of a universal binary. |
5323 | /// \param UniversalIndex Index of the MachO within a universal binary. |
5324 | /// \param MachOFilesetEntryOffset Offset of the MachO entry in a fileset MachO. |
5325 | /// \returns A std::unique_ptr to a MachOObjectFile instance on success. |
5326 | Expected<std::unique_ptr<MachOObjectFile>> ObjectFile::createMachOObjectFile( |
5327 | MemoryBufferRef Buffer, uint32_t UniversalCputype, uint32_t UniversalIndex, |
5328 | size_t MachOFilesetEntryOffset) { |
5329 | StringRef Magic = Buffer.getBuffer().slice(Start: 0, End: 4); |
5330 | if (Magic == "\xFE\xED\xFA\xCE" ) |
5331 | return MachOObjectFile::create(Object: Buffer, IsLittleEndian: false, Is64Bits: false, UniversalCputype, |
5332 | UniversalIndex, MachOFilesetEntryOffset); |
5333 | if (Magic == "\xCE\xFA\xED\xFE" ) |
5334 | return MachOObjectFile::create(Object: Buffer, IsLittleEndian: true, Is64Bits: false, UniversalCputype, |
5335 | UniversalIndex, MachOFilesetEntryOffset); |
5336 | if (Magic == "\xFE\xED\xFA\xCF" ) |
5337 | return MachOObjectFile::create(Object: Buffer, IsLittleEndian: false, Is64Bits: true, UniversalCputype, |
5338 | UniversalIndex, MachOFilesetEntryOffset); |
5339 | if (Magic == "\xCF\xFA\xED\xFE" ) |
5340 | return MachOObjectFile::create(Object: Buffer, IsLittleEndian: true, Is64Bits: true, UniversalCputype, |
5341 | UniversalIndex, MachOFilesetEntryOffset); |
5342 | return make_error<GenericBinaryError>(Args: "Unrecognized MachO magic number" , |
5343 | Args: object_error::invalid_file_type); |
5344 | } |
5345 | |
5346 | StringRef MachOObjectFile::mapDebugSectionName(StringRef Name) const { |
5347 | return StringSwitch<StringRef>(Name) |
5348 | .Case(S: "debug_str_offs" , Value: "debug_str_offsets" ) |
5349 | .Default(Value: Name); |
5350 | } |
5351 | |
5352 | Expected<std::vector<std::string>> |
5353 | MachOObjectFile::findDsymObjectMembers(StringRef Path) { |
5354 | SmallString<256> BundlePath(Path); |
5355 | // Normalize input path. This is necessary to accept `bundle.dSYM/`. |
5356 | sys::path::remove_dots(path&: BundlePath); |
5357 | if (!sys::fs::is_directory(Path: BundlePath) || |
5358 | sys::path::extension(path: BundlePath) != ".dSYM" ) |
5359 | return std::vector<std::string>(); |
5360 | sys::path::append(path&: BundlePath, a: "Contents" , b: "Resources" , c: "DWARF" ); |
5361 | bool IsDir; |
5362 | auto EC = sys::fs::is_directory(path: BundlePath, result&: IsDir); |
5363 | if (EC == errc::no_such_file_or_directory || (!EC && !IsDir)) |
5364 | return createStringError( |
5365 | EC, Fmt: "%s: expected directory 'Contents/Resources/DWARF' in dSYM bundle" , |
5366 | Vals: Path.str().c_str()); |
5367 | if (EC) |
5368 | return createFileError(F: BundlePath, E: errorCodeToError(EC)); |
5369 | |
5370 | std::vector<std::string> ObjectPaths; |
5371 | for (sys::fs::directory_iterator Dir(BundlePath, EC), DirEnd; |
5372 | Dir != DirEnd && !EC; Dir.increment(ec&: EC)) { |
5373 | StringRef ObjectPath = Dir->path(); |
5374 | sys::fs::file_status Status; |
5375 | if (auto EC = sys::fs::status(path: ObjectPath, result&: Status)) |
5376 | return createFileError(F: ObjectPath, E: errorCodeToError(EC)); |
5377 | switch (Status.type()) { |
5378 | case sys::fs::file_type::regular_file: |
5379 | case sys::fs::file_type::symlink_file: |
5380 | case sys::fs::file_type::type_unknown: |
5381 | ObjectPaths.push_back(x: ObjectPath.str()); |
5382 | break; |
5383 | default: /*ignore*/; |
5384 | } |
5385 | } |
5386 | if (EC) |
5387 | return createFileError(F: BundlePath, E: errorCodeToError(EC)); |
5388 | if (ObjectPaths.empty()) |
5389 | return createStringError(EC: std::error_code(), |
5390 | Fmt: "%s: no objects found in dSYM bundle" , |
5391 | Vals: Path.str().c_str()); |
5392 | return ObjectPaths; |
5393 | } |
5394 | |
5395 | llvm::binaryformat::Swift5ReflectionSectionKind |
5396 | MachOObjectFile::mapReflectionSectionNameToEnumValue( |
5397 | StringRef SectionName) const { |
5398 | #define HANDLE_SWIFT_SECTION(KIND, MACHO, ELF, COFF) \ |
5399 | .Case(MACHO, llvm::binaryformat::Swift5ReflectionSectionKind::KIND) |
5400 | return StringSwitch<llvm::binaryformat::Swift5ReflectionSectionKind>( |
5401 | SectionName) |
5402 | #include "llvm/BinaryFormat/Swift.def" |
5403 | .Default(Value: llvm::binaryformat::Swift5ReflectionSectionKind::unknown); |
5404 | #undef HANDLE_SWIFT_SECTION |
5405 | } |
5406 | |
5407 | bool MachOObjectFile::isMachOPairedReloc(uint64_t RelocType, uint64_t Arch) { |
5408 | switch (Arch) { |
5409 | case Triple::x86: |
5410 | return RelocType == MachO::GENERIC_RELOC_SECTDIFF || |
5411 | RelocType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF; |
5412 | case Triple::x86_64: |
5413 | return RelocType == MachO::X86_64_RELOC_SUBTRACTOR; |
5414 | case Triple::arm: |
5415 | case Triple::thumb: |
5416 | return RelocType == MachO::ARM_RELOC_SECTDIFF || |
5417 | RelocType == MachO::ARM_RELOC_LOCAL_SECTDIFF || |
5418 | RelocType == MachO::ARM_RELOC_HALF || |
5419 | RelocType == MachO::ARM_RELOC_HALF_SECTDIFF; |
5420 | case Triple::aarch64: |
5421 | return RelocType == MachO::ARM64_RELOC_SUBTRACTOR; |
5422 | default: |
5423 | return false; |
5424 | } |
5425 | } |
5426 | |