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