@isopodlabs/binary_libs 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/mach.ts ADDED
@@ -0,0 +1,1089 @@
1
+ import * as binary from '@isopodlabs/binary';
2
+
3
+ class mach_stream extends binary.stream_endian {
4
+ constructor(public base: Uint8Array, data: Uint8Array, be: boolean, public mem?: binary.utils.memory) { super(data, be); }
5
+ subdata(offset: number, size?: number) {
6
+ return this.base.subarray(offset, size && offset + size);
7
+ }
8
+ substream(offset: number, size?: number) {
9
+ return new mach_stream(this.base, this.subdata(offset, size), this.be, this.mem);
10
+ }
11
+ getmem(address: bigint, size: number) {
12
+ return this.mem?.get(address, size);
13
+ }
14
+ }
15
+
16
+ const uint16 = binary.UINT16;
17
+ const uint32 = binary.UINT32;
18
+ const uint64 = binary.UINT64;
19
+ const int32 = binary.INT32;
20
+ const xint32 = binary.XINT32;
21
+ const xint64 = binary.XINT64;
22
+
23
+ const FILETYPE = {
24
+ OBJECT: 1, // Relocatable object file
25
+ EXECUTE: 2, // Executable file
26
+ FVMLIB: 3, // Fixed VM shared library file
27
+ CORE: 4, // Core file
28
+ PRELOAD: 5, // Preloaded executable file
29
+ DYLIB: 6, // Dynamically bound shared library
30
+ DYLINKER: 7, // Dynamic link editor
31
+ BUNDLE: 8, // Dynamically bound bundle file
32
+ DYLIB_STUB: 9, // Shared library stub for static linking
33
+ DSYM: 10, // Companion file with only debug sections
34
+ KEXT_BUNDLE: 11, // x86_64 kexts
35
+ FILESET: 12
36
+ }
37
+
38
+ // Machine types known by all
39
+ enum CPU_TYPE {
40
+ ANY = -1,
41
+ ARCH_MASK = 0xff000000, // mask for architecture bits
42
+ ARCH_64 = 0x01000000, // 64 bit ABI
43
+
44
+ VAX = 1,
45
+ MC680x0 = 6,
46
+ X86 = 7,
47
+ MIPS = 8,
48
+ MC98000 = 10,
49
+ HPPA = 11,
50
+ ARM = 12,
51
+ MC88000 = 13,
52
+ SPARC = 14,
53
+ I860 = 15,
54
+ ALPHA = 16,
55
+ POWERPC = 18,
56
+
57
+ X86_64 = X86 | ARCH_64,
58
+ POWERPC_64 = POWERPC | ARCH_64,
59
+ ARM_64 = ARM | ARCH_64,
60
+ }
61
+
62
+ const CPU_SUBTYPES: {[K in CPU_TYPE]?: any} = {
63
+ [CPU_TYPE.VAX] : {
64
+ VAX_ALL: 0,
65
+ VAX780: 1,
66
+ VAX785: 2,
67
+ VAX750: 3,
68
+ VAX730: 4,
69
+ UVAXI: 5,
70
+ UVAXII: 6,
71
+ VAX8200: 7,
72
+ VAX8500: 8,
73
+ VAX8600: 9,
74
+ VAX8650: 10,
75
+ VAX8800: 11,
76
+ UVAXIII: 12,
77
+ },
78
+ [CPU_TYPE.MC680x0] : {
79
+ MC680x0_ALL: 1,
80
+ MC68030: 1, // compat
81
+ MC68040: 2,
82
+ MC68030_ONLY: 3,
83
+ },
84
+ [CPU_TYPE.X86] : {
85
+ X86_ALL: 3,
86
+ X86_64_ALL: 3,
87
+ X86_ARCH1: 4,
88
+ },
89
+ [CPU_TYPE.MIPS] : {
90
+ MIPS_ALL: 0,
91
+ MIPS_R2300: 1,
92
+ MIPS_R2600: 2,
93
+ MIPS_R2800: 3,
94
+ MIPS_R2000a: 4, // pmax
95
+ MIPS_R2000: 5,
96
+ MIPS_R3000a: 6, // 3max
97
+ MIPS_R3000: 7,
98
+
99
+ },
100
+ [CPU_TYPE.MC98000] : {
101
+ MC98000_ALL: 0,
102
+ MC98601: 1,
103
+
104
+ },
105
+ [CPU_TYPE.HPPA] : {
106
+ HPPA_ALL: 0,
107
+ HPPA_7100: 0, // compat
108
+ HPPA_7100LC: 1,
109
+ },
110
+ [CPU_TYPE.ARM] : {
111
+ ARM_ALL: 0,
112
+ ARM_V4T: 5,
113
+ ARM_V6: 6,
114
+ ARM_V5TEJ: 7,
115
+ ARM_XSCALE: 8,
116
+ ARM_V7: 9,
117
+ ARM_V7S: 11,
118
+ ARM_V7K: 12,
119
+ ARM_V6M: 14,
120
+ ARM_V7M: 15,
121
+ ARM_V7EM: 16,
122
+
123
+ },
124
+ [CPU_TYPE.MC88000] : {
125
+ MC88000_ALL: 0,
126
+ MC88100: 1,
127
+ MC88110: 2,
128
+
129
+ },
130
+ [CPU_TYPE.SPARC] : {
131
+ SPARC_ALL: 0,
132
+ },
133
+ [CPU_TYPE.I860] : {
134
+ I860_ALL: 0,
135
+ I860_860: 1,
136
+ },
137
+ [CPU_TYPE.ALPHA] : {
138
+
139
+ },
140
+ [CPU_TYPE.POWERPC] : {
141
+ POWERPC_ALL: 0,
142
+ POWERPC_601: 1,
143
+ POWERPC_602: 2,
144
+ POWERPC_603: 3,
145
+ POWERPC_603e: 4,
146
+ POWERPC_603ev: 5,
147
+ POWERPC_604: 6,
148
+ POWERPC_604e: 7,
149
+ POWERPC_620: 8,
150
+ POWERPC_750: 9,
151
+ POWERPC_7400: 10,
152
+ POWERPC_7450: 11,
153
+ POWERPC_970: 100,
154
+ },
155
+ [CPU_TYPE.X86_64] : {
156
+ I386_ALL: 0x03,
157
+ I386: 0x03,
158
+ I486: 0x04,
159
+ I486SX: 0x84,
160
+ I586: 0x05,
161
+ PENT: 0x05,
162
+ PENTPRO: 0x16,
163
+ PENTII_M3: 0x36,
164
+ PENTII_M5: 0x56,
165
+ CELERON: 0x67,
166
+ CELERON_MOBILE: 0x77,
167
+ PENTIUM_3: 0x08,
168
+ PENTIUM_3_M: 0x18,
169
+ PENTIUM_3_XEON: 0x28,
170
+ PENTIUM_M: 0x09,
171
+ PENTIUM_4: 0x0a,
172
+ PENTIUM_4_M: 0x1a,
173
+ ITANIUM: 0x0b,
174
+ ITANIUM_2: 0x1b,
175
+ XEON: 0x0c,
176
+ XEON_MP: 0x1c,
177
+ },
178
+ [CPU_TYPE.POWERPC_64] : {
179
+
180
+ },
181
+ [CPU_TYPE.ARM_64] : {
182
+ FEATURE: 0x01000000, // mask for feature flags
183
+ LIB64: 0x80000000, // 64 bit libraries
184
+ ARM64_ALL: 0,
185
+ ARM64_V8: 1,
186
+ ARM64E: 2,
187
+ },
188
+ }
189
+
190
+ // Constants for the flags field of the header
191
+ const HEADER_FLAGS = {
192
+ NOUNDEFS: 0x1, // the object file has no undefinedreferences
193
+ INCRLINK: 0x2, // the object file is the output of an incremental link against a base file and can't be link edited again
194
+ DYLDLINK: 0x4, // the object file is input for the dynamic linker and can't be staticly link edited again
195
+ BINDATLOAD: 0x8, // the object file's undefined references are bound by the dynamic linker when loaded.
196
+ PREBOUND: 0x10, // the file has its dynamic undefined references prebound.
197
+ SPLIT_SEGS: 0x20, // the file has its read-only and read-write segments split
198
+ LAZY_INIT: 0x40, // the shared library init routine is to be run lazily via catching memory faults to its writeable segments (obsolete)
199
+ TWOLEVEL: 0x80, // the image is using two-level name space bindings
200
+ FORCE_FLAT: 0x100, // the executable is forcing all images to use flat name space bindings
201
+ NOMULTIDEFS: 0x200, // this umbrella guarantees no multiple defintions of symbols in its sub-images so the two-level namespace hints can always be used.
202
+ NOFIXPREBINDING: 0x400, // do not have dyld notify the prebinding agent about this executable
203
+ PREBINDABLE: 0x800, // the binary is not prebound but can have its prebinding redone. only used when MH_PREBOUND is not set.
204
+ ALLMODSBOUND: 0x1000, // indicates that this binary binds to all two-level namespace modules of its dependent libraries. only used when MH_PREBINDABLE and MH_TWOLEVELare both set.
205
+ SUBSECTIONS_VIA_SYMBOLS:0x2000, // safe to divide up the sections into sub-sections via symbols for dead code stripping
206
+ CANONICAL: 0x4000, // the binary has been canonicalized via the unprebind operation
207
+ WEAK_DEFINES: 0x8000, // the final linked image contains external weak symbols
208
+ BINDS_TO_WEAK: 0x10000, // the final linked image uses weak symbols
209
+ ALLOW_STACK_EXECUTION: 0x20000, // When this bit is set, all stacks in the task will be given stack execution privilege. Only used in MH_EXECUTE filetypes.
210
+ ROOT_SAFE: 0x40000, // When this bit is set, the binary declares it is safe for use in processes with uid zero
211
+ SETUID_SAFE: 0x80000, // When this bit is set, the binary declares it is safe for use in processes when issetugid() is true
212
+ NO_REEXPORTED_DYLIBS: 0x100000, // When this bit is set on a dylib, the static linker does not need to examine dependent dylibs to see if any are re-exported
213
+ PIE: 0x200000, // When this bit is set, the OS will load the main executable at a random address.Only used in MH_EXECUTE filetypes.
214
+ DEAD_STRIPPABLE_DYLIB: 0x400000, // Only for use on dylibs. When linking against a dylib that has this bit set, the static linker will automatically not create a LC_LOAD_DYLIBload command to the dylib if no symbols are being referenced from the dylib.
215
+ HAS_TLV_DESCRIPTORS: 0x800000, // Contains a section of type S_THREAD_LOCAL_VARIABLES
216
+ NO_HEAP_EXECUTION: 0x1000000, // When this bit is set, the OS will run the main executable with a non-executable heap even on platforms (e.g. i386) that don't require it.Only used in MH_EXECUTE filetypes.
217
+ }
218
+
219
+ const header = {
220
+ magic: uint32, // mach magic number identifier
221
+ cputype: binary.as(uint32, binary.Enum(CPU_TYPE)),
222
+ cpusubtype: binary.as(uint32, (x: number): number|string => x),//binary.Enum(CPU_SUBTYPE)),
223
+ filetype: binary.as(uint32, binary.Enum(FILETYPE)),
224
+ ncmds: uint32, // number of load commands
225
+ sizeofcmds: uint32, // the size of all the load commands
226
+ flags: binary.as(uint32, binary.Flags(HEADER_FLAGS, true))
227
+ };
228
+
229
+ const fat_arch = {
230
+ cputype: binary.as(uint32, binary.Enum(CPU_TYPE)),
231
+ cpusubtype: binary.as(uint32, (x: number): number|string => x),//binary.Enum(CPU_SUBTYPE)),
232
+ offset: binary.UINT32_BE, // file offset to this object file
233
+ size: binary.UINT32_BE, // size of this object file
234
+ align: binary.UINT32_BE, // alignment as a power of 2
235
+ contents: binary.DontRead<MachFile>(),
236
+ };
237
+
238
+ const fat_header = {
239
+ magic: uint32, // FAT_MAGIC
240
+ archs: binary.ArrayType(uint32, fat_arch)
241
+ };
242
+
243
+ const REQ_DYLD = 0x80000000;
244
+ export const CMD = {
245
+ SEGMENT: 0x01, // segment of this file to be mapped
246
+ SYMTAB: 0x02, // link-edit stab symbol table info
247
+ SYMSEG: 0x03, // link-edit gdb symbol table info (obsolete)
248
+ THREAD: 0x04, // thread
249
+ UNIXTHREAD: 0x05, // unix thread (includes a stack)
250
+ LOADFVMLIB: 0x06, // load a specified fixed VM shared library
251
+ IDFVMLIB: 0x07, // fixed VM shared library identification
252
+ IDENT: 0x08, // object identification info (obsolete)
253
+ FVMFILE: 0x09, // fixed VM file inclusion (internal use)
254
+ PREPAGE: 0x0a, // prepage command (internal use)
255
+ DYSYMTAB: 0x0b, // dynamic link-edit symbol table info
256
+ LOAD_DYLIB: 0x0c, // load a dynamically linked shared library
257
+ ID_DYLIB: 0x0d, // dynamically linked shared lib ident
258
+ LOAD_DYLINKER: 0x0e, // load a dynamic linker
259
+ ID_DYLINKER: 0x0f, // dynamic linker identification
260
+ PREBOUND_DYLIB: 0x10, // modules prebound for a dynamically linked shared library
261
+ ROUTINES: 0x11, // image routines
262
+ SUB_FRAMEWORK: 0x12, // sub framework
263
+ SUB_UMBRELLA: 0x13, // sub umbrella
264
+ SUB_CLIENT: 0x14, // sub client
265
+ SUB_LIBRARY: 0x15, // sub library
266
+ TWOLEVEL_HINTS: 0x16, // two-level namespace lookup hints
267
+ PREBIND_CKSUM: 0x17, // prebind checksum
268
+ LOAD_WEAK_DYLIB: 0x18 + REQ_DYLD, // load a dynamically linked shared library that is allowed to be missing (all symbols are weak imported).
269
+ SEGMENT_64: 0x19, // 64-bit segment of this file to be mapped
270
+ ROUTINES_64: 0x1a, // 64-bit image routines
271
+ UUID: 0x1b, // the uuid
272
+ RPATH: 0x1c + REQ_DYLD, // runpath additions
273
+ CODE_SIGNATURE: 0x1d, // local of code signature
274
+ SEGMENT_SPLIT_INFO: 0x1e, // local of info to split segments
275
+ REEXPORT_DYLIB: 0x1f + REQ_DYLD, // load and re-export dylib
276
+ LAZY_LOAD_DYLIB: 0x20, // delay load of dylib until first use
277
+ ENCRYPTION_INFO: 0x21, // encrypted segment information
278
+ DYLD_INFO: 0x22, // compressed dyld information
279
+ DYLD_INFO_ONLY: 0x22 + REQ_DYLD, // compressed dyld information only
280
+ LOAD_UPWARD_DYLIB: 0x23 + REQ_DYLD, // load upward dylib
281
+ VERSION_MIN_MACOSX: 0x24, // build for MacOSX min OS version
282
+ VERSION_MIN_IPHONEOS: 0x25, // build for iPhoneOS min OS version
283
+ FUNCTION_STARTS: 0x26, // compressed table of function start addresses
284
+ DYLD_ENVIRONMENT: 0x27, // string for dyld to treat like environment variable
285
+ MAIN: 0x28 + REQ_DYLD, // replacement for LC_UNIXTHREAD
286
+ DATA_IN_CODE: 0x29, // table of non-instructions in __text
287
+ SOURCE_VERSION: 0x2A, // source version used to build binary
288
+ DYLIB_CODE_SIGN_DRS: 0x2B, // Code signing DRs copied from linked dylibs
289
+ ENCRYPTION_INFO_64: 0x2C, // 64-bit encrypted segment information
290
+ LINKER_OPTION: 0x2D, // linker options in MH_OBJECT files
291
+ LINKER_OPTIMIZATION_HINT: 0x2E, // optimization hints in MH_OBJECT files
292
+ VERSION_MIN_TVOS: 0x2F, // build for AppleTV min OS version
293
+ VERSION_MIN_WATCHOS: 0x30, // build for Watch min OS version
294
+ NOTE: 0x31, // arbitrary data included within a Mach-O file
295
+ BUILD_VERSION: 0x32, // build for platform min OS version
296
+ DYLD_EXPORTS_TRIE: 0x33 + REQ_DYLD, // used with linkedit_data_command, payload is trie
297
+ DYLD_CHAINED_FIXUPS: 0x34 + REQ_DYLD, // used with linkedit_data_command
298
+ } as const;
299
+ export type CMD = typeof CMD[keyof typeof CMD];
300
+
301
+ const str = {
302
+ get(s: binary.stream) {
303
+ const off = uint32.get(s); // offset to the string
304
+ return binary.utils.decodeTextTo0(s.buffer_at(off - 8), 'utf8');
305
+ }
306
+ };
307
+
308
+ const index_table = {
309
+ first: uint32,
310
+ count: uint32,
311
+ }
312
+
313
+ const blob = {
314
+ get(s: mach_stream) {
315
+ const offset = uint32.get(s);
316
+ const size = uint32.get(s);
317
+ if (size)
318
+ return s.subdata(offset, size);//.buffer_at(offset, size);
319
+ }
320
+ };
321
+
322
+ function blobT<T extends binary.TypeReader>(type: T) {
323
+ return {
324
+ get(s: mach_stream) {
325
+ const offset = uint32.get(s);
326
+ const size = uint32.get(s);
327
+ return {
328
+ data: s.subdata(offset, size),
329
+ contents: binary.read(s.substream(offset, size), type)
330
+ }
331
+ }
332
+ };
333
+ }
334
+
335
+ function count_table<T extends binary.TypeReader>(type: T) {
336
+ return {
337
+ get(s: mach_stream) {
338
+ const offset = uint32.get(s);
339
+ const count = uint32.get(s);
340
+ if (count)
341
+ return binary.readn(s.substream(offset), type, count);
342
+ }
343
+ };
344
+ }
345
+
346
+ const fixed_string16 = binary.StringType(16);
347
+ const version = binary.asFlags(uint32, {major: 0xffff0000, minor: 0xff00, patch: 0xff}, false);
348
+
349
+ const command = {
350
+ cmd: binary.as(uint32, binary.EnumV(CMD)),
351
+ cmdsize: uint32,
352
+ }
353
+
354
+ const SECTION_FLAGS = binary.BitFields({
355
+ TYPE: [8, binary.Enum({
356
+ REGULAR: 0x0, // regular section
357
+ ZEROFILL: 0x1, // zero fill on demand section
358
+ CSTRING_LITERALS: 0x2, // section with only literal C strings
359
+ LITERALS4: 0x3, // section with only 4 byte literals
360
+ LITERALS8: 0x4, // section with only 8 byte literals
361
+ LITERAL_POINTERS: 0x5, // section with only pointers to literals
362
+ NON_LAZY_SYMBOL_POINTERS: 0x6, // section with only non-lazy symbol pointers
363
+ LAZY_SYMBOL_POINTERS: 0x7, // section with only lazy symbol pointers
364
+ SYMBOL_STUBS: 0x8, // section with only symbol stubs, byte size of stub in the reserved2 field
365
+ MOD_INIT_FUNC_POINTERS: 0x9, // section with only function pointers for initialization
366
+ MOD_TERM_FUNC_POINTERS: 0xa, // section with only function pointers for termination
367
+ COALESCED: 0xb, // section contains symbols that are to be coalesced
368
+ GB_ZEROFILL: 0xc, // zero fill on demand section (that can be larger than 4 gigabytes)
369
+ INTERPOSING: 0xd, // section with only pairs of function pointers for interposing
370
+ LITERALS16: 0xe, // section with only 16 byte literals
371
+ DTRACE_DOF: 0xf, // section contains DTrace Object Format
372
+ LAZY_DYLIB_SYMBOL_POINTERS: 0x10, // section with only lazy symbol pointers to lazy loaded dylibs
373
+ // Section types to support thread local variables
374
+ THREAD_LOCAL_REGULAR: 0x11, // template of initial values for TLVs
375
+ THREAD_LOCAL_ZEROFILL: 0x12, // template of initial values for TLVs
376
+ THREAD_LOCAL_VARIABLES: 0x13, // TLV descriptors
377
+ THREAD_LOCAL_VARIABLE_POINTERS: 0x14, // pointers to TLV descriptors
378
+ THREAD_LOCAL_INIT_FUNCTION_POINTERS:0x15, // functions to call to initialize TLV values
379
+ })],
380
+ ATTRIBUTES: [24, binary.BitFields({
381
+ SYS: [16, binary.Flags({
382
+ SOME_INSTRUCTIONS: 0x0004, // section contains some machine instructions
383
+ EXT_RELOC: 0x0002, // section has external relocation entries
384
+ LOC_RELOC: 0x0001, // section has local relocation entries
385
+ }, true)],
386
+ USR: [8, binary.Flags({
387
+ PURE_INSTRUCTIONS: 0x80, // section contains only true machine instructions
388
+ NO_TOC: 0x40, // section contains coalesced symbols that are not to be in a ranlib table of contents
389
+ STRIP_STATIC_SYMS: 0x20, // ok to strip static symbols in this section in files with the MH_DYLDLINK flag
390
+ NO_DEAD_STRIP: 0x10, // no dead stripping
391
+ LIVE_SUPPORT: 0x08, // blocks are live if they reference live blocks
392
+ SELF_MODIFYING_CODE: 0x04, // Used with i386 code stubs written on by dyld
393
+ DEBUG: 0x02, // a debug section
394
+ }, true)],
395
+ })],
396
+ });
397
+
398
+ function section(bits: 32|64) {
399
+ const type = binary.UINT(bits);
400
+
401
+ class Section extends binary.ReadWriteStruct({
402
+ //data: binary.DontRead<binary.utils.MappedMemory>(),
403
+ sectname: fixed_string16,
404
+ segname: fixed_string16,
405
+ addr: type, // memory address of this section
406
+ size: type, // size in bytes of this section
407
+ offset: xint32, // file offset of this section
408
+ align: uint32, // section alignment (power of 2)
409
+ reloff: xint32, // file offset of relocation entries
410
+ nreloc: uint32, // number of relocation entries
411
+ flags: binary.as(uint32, SECTION_FLAGS), // flags (section type and attributes)
412
+ reserved1: uint32, // reserved (for offset or index)
413
+ reserved2: uint32, // reserved (for count or sizeof)
414
+ _: binary.AlignType(bits / 8)
415
+ }) {
416
+ data: Promise<binary.utils.MappedMemory>;
417
+ constructor(s: mach_stream) {
418
+ super(s);
419
+ const prot = this.flags.ATTRIBUTES.SYS.SOME_INSTRUCTIONS ? binary.utils.MEM.EXECUTE : binary.utils.MEM.NONE;
420
+ this.data = (async () => {
421
+ //return new binary.utils.MappedMemory(await s.file.get(BigInt(this.addr), Number(this.size)), Number(this.addr), prot)
422
+ return new binary.utils.MappedMemory(s.subdata(+this.offset, Number(this.size)), Number(this.addr), prot)
423
+ })();
424
+ }
425
+ }
426
+ return Section;
427
+ }
428
+
429
+ const SEGMENT_FLAGS = {
430
+ HIGHVM: 0x1, // the file contents for this segment is for the high part of the VM space, the low part is zero filled (for stacks in core files)
431
+ FVMLIB: 0x2, // this segment is the VM that is allocated by a fixed VM library, for overlap checking in the link editor
432
+ NORELOC: 0x4, // this segment has nothing that was relocated in it and nothing relocated to it, that is it maybe safely replaced without relocation
433
+ PROTECTED_VERSION_1: 0x8, // This segment is protected. If the segment starts at file offset 0, the first page of the segment is not protected. All other pages of the segment are protected.
434
+ }
435
+
436
+ function segment(bits: 32|64) {
437
+ const type = binary.UINT(bits);
438
+ const fields = {
439
+ data: binary.DontRead<binary.utils.MappedMemory>(),
440
+ segname: fixed_string16, // segment name
441
+ vmaddr: type, // memory address of this segment
442
+ vmsize: type, // memory size of this segment
443
+ fileoff: type, // file offset of this segment
444
+ filesize: type, // amount to map from the file
445
+ maxprot: uint32, // maximum VM protection
446
+ initprot: uint32, // initial VM protection
447
+ nsects: uint32, // number of sections in segment
448
+ flags: binary.as(uint32, binary.Flags(SEGMENT_FLAGS,true)), // flags
449
+ sections: binary.DontRead<Record<string, any>>(),//binary.ReadType<typeof section(bits)>)),
450
+ };
451
+ return {
452
+ async get(s: mach_stream) {
453
+ const o = binary.read(s, fields);
454
+ const data = await s.getmem(BigInt(o.vmaddr), Number(o.filesize)) ?? s.subdata(Number(o.fileoff), Number(o.filesize));
455
+ o.data = new binary.utils.MappedMemory(data, Number(o.vmaddr), o.initprot);
456
+
457
+ const sect = section(bits);
458
+ if (o.nsects) {
459
+ o.sections = binary.objectWithNames(binary.ArrayType(o.nsects, section(bits)), binary.field('sectname')).get(s);
460
+ //o.sections = Object.fromEntries(Array.from({length: o.nsects}, (_,i)=>new sect(s)).map(s => [s.sectname, s]));
461
+ }
462
+ return o;
463
+ }
464
+ };
465
+ }
466
+
467
+ const fvmlib = {
468
+ name: str, // library's target pathname
469
+ minor_version: xint32, // library's minor version number
470
+ header_addr: xint32, // library's header address
471
+ };
472
+
473
+ const dylib = {
474
+ name: str,
475
+ timestamp: uint32,
476
+ current_version: version,
477
+ compatibility_version: version,
478
+ };
479
+
480
+ const thread_command = {
481
+ // uint32 flavor flavor of thread state
482
+ // uint32 count count of longs in thread state
483
+ // struct XXX_thread_state state thread state for this flavor
484
+ // ...
485
+ };
486
+
487
+
488
+ // SYMTAB
489
+ const nlist_flags = binary.BitFields({
490
+ ext: 1,
491
+ type: [3, binary.Enum({
492
+ UNDF: 0, // undefined, n_sect == NO_SECT
493
+ ABS: 1, // absolute, n_sect == NO_SECT
494
+ INDR: 5, // indirect
495
+ PBUD: 6, // prebound undefined (defined in a dylib)
496
+ SECT: 7, // defined in section number n_sect
497
+ })],
498
+ pext: 1,
499
+ stab: [3, binary.Enum({
500
+
501
+ })],
502
+ });
503
+ /*
504
+ //masks
505
+ //STAB = 0xe0, // if any of these bits set, a symbolic debugging entry
506
+ PEXT = 0x10, // private external symbol bit
507
+ //TYPE = 0x0e, // mask for the type bits
508
+ EXT = 0x01, // external symbol bit, set for external symbols
509
+
510
+ UNDF = 0x00, // undefined, n_sect == NO_SECT
511
+ ABS = 0x02, // absolute, n_sect == NO_SECT
512
+ INDR = 0x0a, // indirect
513
+ PBUD = 0x0c, // prebound undefined (defined in a dylib)
514
+ SECT = 0x0e, // defined in section number n_sect
515
+ // STAB values
516
+ GSYM = 0x20, // global symbol: name,,NO_SECT,type,0
517
+ FNAME = 0x22, // procedure name (f77 kludge): name,,NO_SECT,0,0
518
+ FUN = 0x24, // procedure: name,,n_sect,linenumber,address
519
+ STSYM = 0x26, // static symbol: name,,n_sect,type,address
520
+ LCSYM = 0x28, // .lcomm symbol: name,,n_sect,type,address
521
+ BNSYM = 0x2e, // begin nsect sym: 0,,n_sect,0,address
522
+ OPT = 0x3c, // emitted with gcc2_compiled and in gcc source
523
+ RSYM = 0x40, // register sym: name,,NO_SECT,type,register
524
+ SLINE = 0x44, // src line: 0,,n_sect,linenumber,address
525
+ ENSYM = 0x4e, // end nsect sym: 0,,n_sect,0,address
526
+ SSYM = 0x60, // structure elt: name,,NO_SECT,type,struct_offset
527
+ SO = 0x64, // source file name: name,,n_sect,0,address
528
+ OSO = 0x66, // object file name: name,,0,0,st_mtime
529
+ LSYM = 0x80, // local sym: name,,NO_SECT,type,offset
530
+ BINCL = 0x82, // include file beginning: name,,NO_SECT,0,sum
531
+ SOL = 0x84, // #included file name: name,,n_sect,0,address
532
+ PARAMS = 0x86, // compiler parameters: name,,NO_SECT,0,0
533
+ VERSION = 0x88, // compiler version: name,,NO_SECT,0,0
534
+ OLEVEL = 0x8A, // compiler -O level: name,,NO_SECT,0,0
535
+ PSYM = 0xa0, // parameter: name,,NO_SECT,type,offset
536
+ EINCL = 0xa2, // include file end: name,,NO_SECT,0,0
537
+ ENTRY = 0xa4, // alternate entry: name,,n_sect,linenumber,address
538
+ LBRAC = 0xc0, // left bracket: 0,,NO_SECT,nesting level,address
539
+ EXCL = 0xc2, // deleted include file: name,,NO_SECT,0,sum
540
+ RBRAC = 0xe0, // right bracket: 0,,NO_SECT,nesting level,address
541
+ BCOMM = 0xe2, // begin common: name,,NO_SECT,0,0
542
+ ECOMM = 0xe4, // end common: name,,n_sect,0,0
543
+ ECOML = 0xe8, // end common (local name): 0,,n_sect,0,address
544
+ LENG = 0xfe, // second stab entry with length information
545
+ }
546
+ */
547
+ const nlist_desc = binary.BitFields({
548
+ ref: [3, binary.Enum({
549
+ UNDEFINED_NON_LAZY: 0,
550
+ UNDEFINED_LAZY: 1,
551
+ DEFINED: 2,
552
+ PRIVATE_DEFINED: 3,
553
+ PRIVATE_UNDEFINED_NON_LAZY: 4,
554
+ PRIVATE_UNDEFINED_LAZY: 5,
555
+ })],
556
+ flags: [5, binary.Flags({
557
+ ARM_THUMB_DEF: 1 << 0, // symbol is a Thumb function (ARM)
558
+ REF_DYNAMIC: 1 << 1,
559
+ NO_DEAD_STRIP: 1 << 2, // symbol is not to be dead stripped
560
+ //DESC_DISCARDE: 1 << 2, // symbol is discarded
561
+ WEAK_REF: 1 << 3, // symbol is weak referenced
562
+ WEAK_DEF: 1 << 4, // coalesed symbol is a weak definition
563
+ //REF_TO_WEA 1 << 4, // reference to a weak symbol
564
+ //SYMBOL_RESOLVER: 0x0100,
565
+ }, true)],
566
+ align: 8
567
+ //MAX_LIBRARY_ORDINAL = 0xfd << 8,
568
+ //DYNAMIC_LOOKUP_ORDINAL = 0xfe << 8,
569
+ //EXECUTABLE_ORDINAL = 0xff << 8,
570
+ });
571
+
572
+ function nlist(bits:32|64) { return {
573
+ strx: uint32, // index into the string table
574
+ flags: binary.as(binary.UINT8, nlist_flags),
575
+ sect: binary.UINT8,// section number or NO_SECT
576
+ desc: binary.as(uint16, nlist_desc),
577
+ value: binary.UINT(bits),
578
+
579
+ //const char *name(const char *s) const { return s ? s + strx : ""; }
580
+ //FLAGS type() const { return FLAGS(flags & TYPE); }
581
+ //FLAGS stab() const { return FLAGS(flags & STAB); }
582
+ }; }
583
+
584
+ const symtab = {
585
+ get(s: binary._stream) {
586
+ const sym = binary.read(s, count_table(nlist(64)));
587
+ const str = binary.read(s, blob) as Uint8Array;
588
+ return sym?.map(v => [binary.utils.decodeTextTo0(str.subarray(v.strx), 'utf8'), v]);
589
+ }
590
+ };
591
+
592
+ // DYSYMTAB
593
+
594
+ const INDIRECT = {
595
+ INDIRECT_SYMBOL_LOCAL: 0x80000000, // non-lazy symbol pointer section for a defined symbol which strip(1) has removed
596
+ INDIRECT_SYMBOL_ABS: 0x40000000,
597
+ }
598
+
599
+ const toc_entry = {
600
+ symbol_index: uint32, // the defined external symbol (index into the symbol table)
601
+ module_index: uint32, // index into the module table this symbol is defined in
602
+ };
603
+
604
+ function module(bits:32|64) {
605
+ const fields = {
606
+ module_name: uint32, // the module name (index into string table)
607
+ extdefsym: index_table, // index into externally defined symbols
608
+ refsym: index_table, // index into reference symbol table
609
+ localsym: index_table, // index into symbols for local symbols
610
+ extrel: index_table, // index into external relocation entries
611
+ init_iterm: index_table, // low 16 bits are the index into the init section, high 16 bits are the index into the term section
612
+ };
613
+ return bits == 32 ? {...fields,
614
+ objc_module_info_addr: uint32, // for this module address of the start of the (__OBJC,__module_info) section
615
+ objc_module_info_size: uint32, // for this module size of the (__OBJC,__module_info) section
616
+ } : {...fields,
617
+ objc_module_info_size: uint32, // for this module size of the (__OBJC, __module_info) section
618
+ objc_module_info_addr: uint64, // for this module address of the start of the (__OBJC, __module_info) section
619
+ };
620
+ }
621
+
622
+ const symbol_ref = binary.as(uint32, binary.BitFields({
623
+ symbol_index: 24, // index into the symbol table
624
+ flags: 8
625
+ }));
626
+
627
+ const hint = binary.as(uint32, binary.BitFields({
628
+ sub_image: 8, // index into the sub images
629
+ toc: 24 // index into the table of contents
630
+ }));
631
+
632
+ const version_min = {
633
+ version,
634
+ reserved: uint32, // zero
635
+ };
636
+
637
+ const REBASE = binary.BitFields({
638
+ immediate: 4,
639
+ opcode: [4, binary.Enum({
640
+ DONE: 0,
641
+ SET_TYPE_IMM: 1,
642
+ SET_SEGMENT_AND_OFFSET_ULEB: 2,
643
+ ADD_ADDR_ULEB: 3,
644
+ ADD_ADDR_IMM_SCALED: 4,
645
+ DO_REBASE_IMM_TIMES: 5,
646
+ DO_REBASE_ULEB_TIMES: 6,
647
+ DO_REBASE_ADD_ADDR_ULEB: 7,
648
+ DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: 8,
649
+ })]
650
+ //TYPE_POINTER = 1,
651
+ //TYPE_TEXT_ABSOLUTE32 = 2,
652
+ //TYPE_TEXT_PCREL32 = 3,
653
+ });
654
+
655
+ const BIND = binary.BitFields({
656
+ immediate: 4,
657
+ opcode: [4, binary.Enum({
658
+ DONE: 0,
659
+ SET_DYLIB_ORDINAL_IMM: 1,
660
+ SET_DYLIB_ORDINAL_ULEB: 2,
661
+ SET_DYLIB_SPECIAL_IMM: 3,
662
+ SET_SYMBOL_TRAILING_FLAGS_IMM: 4,
663
+ SET_TYPE_IMM: 5,
664
+ SET_ADDEND_SLEB: 6,
665
+ SET_SEGMENT_AND_OFFSET_ULEB: 7,
666
+ ADD_ADDR_ULEB: 8,
667
+ DO_BIND: 9,
668
+ DO_BIND_ADD_ADDR_ULEB: 10,
669
+ DO_BIND_ADD_ADDR_IMM_SCALED: 11,
670
+ DO_BIND_ULEB_TIMES_SKIPPING_ULEB: 12,
671
+ })]
672
+ //TYPE_POINTER = 1,
673
+ //TYPE_TEXT_ABSOLUTE32 = 2,
674
+ //TYPE_TEXT_PCREL32 = 3,
675
+ //SPECIAL_DYLIB_SELF = 0,
676
+ //SPECIAL_DYLIB_MAIN_EXECUTABLE = -1,
677
+ //SPECIAL_DYLIB_FLAT_LOOKUP = -2,
678
+ //SYMBOL_FLAGS_WEAK_IMPORT = 0x1,
679
+ //SYMBOL_FLAGS_NON_WEAK_DEFINITION = 0x8,
680
+ });
681
+
682
+ const dyld_kind = {
683
+ KIND_MASK: 0x03,
684
+ KIND_REGULAR: 0x00,
685
+ KIND_THREAD_LOCAL: 0x01,
686
+ KIND_ABSOLUTE: 0x02,
687
+ WEAK_DEFINITION: 0x04,
688
+ REEXPORT: 0x08,
689
+ STUB_AND_RESOLVER: 0x10,
690
+ }
691
+
692
+ const dyldinfo = {
693
+ rebase: blob,
694
+ bind: blob,
695
+ weak_bind: blob,
696
+ lazy_bind: blob,
697
+ exprt: blob,
698
+ };
699
+
700
+ //BUILD_VERSION
701
+ const TOOL = {
702
+ CLANG: 1,
703
+ SWIFT: 2,
704
+ LD: 3,
705
+ LLD: 4,
706
+ }
707
+ const PLATFORM = {
708
+ MACOS: 1,
709
+ IOS: 2,
710
+ TVOS: 3,
711
+ WATCHOS: 4,
712
+ BRIDGEOS: 5,
713
+ MACCATALYST: 6,
714
+ IOSSIMULATOR: 7,
715
+ TVOSSIMULATOR: 8,
716
+ WATCHOSSIMULATOR: 9,
717
+ DRIVERKIT: 10,
718
+ }
719
+
720
+ //DYLD_CHAINED_FIXUPS
721
+
722
+ const dyld_chained_starts_in_segment = {
723
+ size: uint32, ///< Size of this, including chain_starts entries
724
+ page_size: uint16, ///< Page size in bytes (0x1000 or 0x4000)
725
+ pointer_format: binary.asEnum(uint16, {
726
+ ARM64E: 1,
727
+ '64': 2,
728
+ '32': 3,
729
+ '32_CACHE': 4,
730
+ '32_FIRMWARE': 5,
731
+ '64_OFFSET': 6,
732
+ ARM64E_KERNEL: 7,
733
+ '64_KERNEL_CACHE': 8,
734
+ ARM64E_USERLAND: 9,
735
+ ARM64E_FIRMWARE: 10,
736
+ X86_64_KERNEL_CACHE: 11,
737
+ ARM64E_USERLAND24: 12,
738
+ }),
739
+ segment_offset: xint64, // VM offset from the __TEXT segment
740
+ max_valid_pointer: xint32, // Values beyond this are not pointers on 32-bit
741
+ pages: binary.ArrayType(uint16, binary.asEnum(uint16, {
742
+ NONE: 0xFFFF,
743
+ MULTI: 0x8000, // page which has multiple starts
744
+ LAST: 0x8000, // last chain_start for a given page
745
+ }))
746
+ };
747
+
748
+ const dyld_chained_starts_in_image = binary.ArrayType(uint32, binary.OffsetType(uint32, dyld_chained_starts_in_segment));
749
+
750
+ const dyld_chained_import = binary.as(uint32, binary.BitFields({
751
+ lib_ordinal : 8,
752
+ weak_import : 1,
753
+ name_offset : 23,
754
+ }));
755
+
756
+ const dyld_chained_import_addend = {
757
+ import: dyld_chained_import,
758
+ addend: int32,
759
+ };
760
+
761
+ const dyld_chained_import_addend64 = {
762
+ import: binary.as(uint64, binary.BitFields({
763
+ lib_ordinal : 16,
764
+ weak_import : 1,
765
+ reserved : 15,
766
+ name_offset : 32,
767
+ })),
768
+ addend: uint64,
769
+ };
770
+
771
+ class dyld_chained_fixups extends binary.ReadStruct({
772
+ fixups_version: uint32, // currently 0
773
+ starts: binary.OffsetType(uint32, dyld_chained_starts_in_image),
774
+ imports: binary.OffsetType(uint32, binary.Remainder), // offset of imports table in chain_data
775
+ symbols: binary.OffsetType(uint32, binary.Remainder), // offset of symbol strings in chain_data
776
+ imports_count: uint32, // number of imported symbol names
777
+ imports_format: binary.asEnum(uint32, {
778
+ IMPORT: 1,
779
+ IMPORT_ADDEND: 2,
780
+ IMPORT_ADDEND64: 3
781
+ }),
782
+ symbols_format: binary.asEnum(uint32, {
783
+ UNCOMPRESSED: 0,
784
+ ZLIB: 1,
785
+ }),
786
+ }) {
787
+ constructor(s: binary.stream_endian) {
788
+ super(s);
789
+ const imports = new binary.stream_endian(this.imports, s.be);
790
+ switch (this.imports_format) {
791
+ case 'IMPORT':
792
+ this.imports = binary.withNames(binary.readn(imports, dyld_chained_import, this.imports_count), imp => binary.utils.decodeTextTo0(this.symbols.subarray(imp.name_offset)));
793
+ break;
794
+ case 'IMPORT_ADDEND':
795
+ this.imports = binary.withNames(binary.readn(imports, dyld_chained_import_addend, this.imports_count), imp => binary.utils.decodeTextTo0(this.symbols.subarray(imp.import.name_offset)));
796
+ break;
797
+ case 'IMPORT_ADDEND64':
798
+ this.imports = binary.withNames(binary.readn(imports, dyld_chained_import_addend64, this.imports_count), imp => binary.utils.decodeTextTo0(this.symbols.subarray(imp.import.name_offset)));
799
+ break;
800
+ }
801
+ }
802
+ }
803
+
804
+ const dyld_chained_ptr_64_bind = binary.as(uint64, binary.BitFields({
805
+ ordinal : 24,
806
+ addend : 8,
807
+ reserved : 19,
808
+ next : 12,
809
+ bind : 1, // set to 1
810
+ }));
811
+
812
+ const dyld_chained_ptr_64_rebase = binary.as(uint64, binary.BitFields({
813
+ target : 36,
814
+ high8 : 8,
815
+ reserved : 7,
816
+ next : 12,
817
+ bind : 1, // set to 0
818
+ }));
819
+
820
+ //DATA_IN_CODE
821
+
822
+ const data_in_code_entry = {
823
+ offset: xint32, // from header to start of data range
824
+ length: uint16, // number of bytes in data range
825
+ kind: binary.as(uint16, binary.Enum({
826
+ DATA: 0x0001,
827
+ JUMP_TABLE8: 0x0002,
828
+ JUMP_TABLE16: 0x0003,
829
+ JUMP_TABLE32: 0x0004,
830
+ ABS_JUMP_TABLE32: 0x0005,
831
+ })),
832
+ };
833
+
834
+ // Sections of type S_THREAD_LOCAL_VARIABLES contain an array of tlv_descriptor structures.
835
+ /*
836
+ const tlv_descriptor = {
837
+ void* (*thunk)(tlv_descriptor*);
838
+ unsigned long key;
839
+ unsigned long offset;
840
+ };
841
+ */
842
+
843
+ function routines(bits:32|64) {
844
+ const type = binary.UINT(bits);
845
+ return {
846
+ init_address: type, // address of initialization routine
847
+ init_module: type, // index into the module table that the init routine is defined in
848
+ reserved1: type,
849
+ reserved2: type,
850
+ reserved3: type,
851
+ reserved4: type,
852
+ reserved5: type,
853
+ reserved6: type,
854
+ };
855
+ }
856
+
857
+
858
+
859
+ //const cmd_table : {[K in CMD]?: binary.TypeReader2} = {
860
+ const cmd_table = {//: Record<CMD, binary.TypeReader2> = {
861
+ //const cmd_table = {
862
+ [CMD.SEGMENT]: segment(32),
863
+ [CMD.SEGMENT_64]: segment(64),
864
+ [CMD.LOADFVMLIB]: fvmlib,
865
+ [CMD.IDFVMLIB]: fvmlib,
866
+
867
+ [CMD.LOAD_DYLIB]: dylib,
868
+ [CMD.ID_DYLIB]: dylib,
869
+ [CMD.LOAD_WEAK_DYLIB]: dylib,
870
+ [CMD.REEXPORT_DYLIB]: dylib,
871
+ [CMD.LAZY_LOAD_DYLIB]: dylib,
872
+ [CMD.LOAD_UPWARD_DYLIB]: dylib,
873
+
874
+ [CMD.SUB_FRAMEWORK]: str,
875
+ [CMD.SUB_UMBRELLA]: str,
876
+ [CMD.SUB_CLIENT]: str,
877
+ [CMD.SUB_LIBRARY]: str,
878
+ [CMD.LOAD_DYLINKER]: str,
879
+ [CMD.ID_DYLINKER]: str,
880
+ [CMD.DYLD_ENVIRONMENT]: str,
881
+ [CMD.RPATH]: str,
882
+
883
+ [CMD.PREBOUND_DYLIB]: {
884
+ name: str,
885
+ nmodules: uint32,
886
+ linked_modules: str,
887
+ },
888
+
889
+ [CMD.THREAD]: thread_command,
890
+ [CMD.UNIXTHREAD]: thread_command,
891
+
892
+ [CMD.ROUTINES]: routines(32),
893
+ [CMD.ROUTINES_64]: routines(64),
894
+
895
+ [CMD.SYMTAB]: symtab,
896
+
897
+ [CMD.TWOLEVEL_HINTS]: count_table(hint),
898
+
899
+ [CMD.PREBIND_CKSUM]: {
900
+ cksum: uint32,
901
+ },
902
+
903
+ [CMD.UUID]: {
904
+ uuid: binary.Buffer(16),
905
+ },
906
+
907
+ [CMD.CODE_SIGNATURE]: blob,
908
+ [CMD.SEGMENT_SPLIT_INFO]: blob,
909
+ [CMD.FUNCTION_STARTS]: blobT(binary.RemainingArrayType(binary.ULEB128)),
910
+ [CMD.DATA_IN_CODE]: blobT(binary.RemainingArrayType(data_in_code_entry)),
911
+ [CMD.DYLIB_CODE_SIGN_DRS]: blob,
912
+ [CMD.LINKER_OPTIMIZATION_HINT]: blob,
913
+ [CMD.DYLD_EXPORTS_TRIE]: blob,
914
+ [CMD.DYLD_CHAINED_FIXUPS]: blob,//blobT(dyld_chained_fixups),
915
+
916
+ [CMD.ENCRYPTION_INFO]: {
917
+ cryptoff: uint32, // file offset of encrypted range
918
+ cryptsize: uint32, // file size of encrypted range
919
+ cryptid: uint32, // which enryption system, 0 means not-encrypted yet
920
+ },
921
+ [CMD.ENCRYPTION_INFO_64]: {
922
+ cryptoff: uint32, // file offset of encrypted range
923
+ cryptsize: uint32, // file size of encrypted range
924
+ cryptid: uint32, // which enryption system, 0 means not-encrypted yet
925
+ pad: uint32, // must be zero
926
+ },
927
+
928
+ [CMD.VERSION_MIN_MACOSX]: version_min,
929
+ [CMD.VERSION_MIN_IPHONEOS]: version_min,
930
+ [CMD.VERSION_MIN_TVOS]: version_min,
931
+ [CMD.VERSION_MIN_WATCHOS]: version_min,
932
+
933
+ [CMD.DYLD_INFO]: dyldinfo,
934
+ [CMD.DYLD_INFO_ONLY]: dyldinfo,
935
+
936
+ [CMD.SYMSEG]: blob,//OBSOLETE
937
+
938
+ [CMD.IDENT]: {},//OBSOLETE
939
+
940
+ [CMD.FVMFILE]: {//OBSOLETE
941
+ name: str,
942
+ header_addr: uint32,
943
+ },
944
+
945
+ [CMD.MAIN]: {
946
+ entryoff: uint32, // file (__TEXT) offset of entry point
947
+ stacksize: uint32, // if not zero, initialize stack size
948
+ },
949
+
950
+ [CMD.SOURCE_VERSION]: {
951
+ version: binary.as(binary.UINT64_BE, binary.BitFields({a:24, b:10, c:10, d:10, e:10})) // A.B.C.D.E packed as a24.b10.c10.d10.e10
952
+ },
953
+ [CMD.BUILD_VERSION]: {
954
+ platform: binary.asEnum(uint32, PLATFORM),
955
+ minos: version,
956
+ sdk: version,
957
+ tools: binary.objectWithNames(binary.ArrayType(uint32, {tool: binary.as(uint32, binary.Enum(TOOL)), version}), binary.field('tool')),
958
+ },
959
+ [CMD.LINKER_OPTION]: {
960
+ count: uint32, // number of strings following
961
+ },
962
+ [CMD.NOTE]: {
963
+ data_owner: fixed_string16, // owner name for this LC_NOTE
964
+ data: blob
965
+ },
966
+ [CMD.PREPAGE]: {},
967
+ [CMD.DYSYMTAB]: {
968
+ localsym: index_table, // local symbols
969
+ extdefsym: index_table, // externally defined symbols
970
+ undefsym: index_table, // undefined symbols
971
+ toc: count_table(toc_entry), // table of contents
972
+ modtab: count_table(module(64)), // module table
973
+ extrefsym: count_table(symbol_ref), // referenced symbol table
974
+ indirectsym: count_table(symbol_ref), // indirect symbol table
975
+ extrel: count_table({address:uint32, symbol_ref}), // external relocation entries
976
+ locrel: count_table({address:uint32, symbol_ref}), // local relocation entries
977
+ },
978
+ };
979
+
980
+ export class MachFile {
981
+ header: any;
982
+ commands:{cmd:CMD, data:any}[] = [];
983
+ ready: Promise<void>;
984
+
985
+ static check(data: Uint8Array): boolean {
986
+ switch (binary.UINT32_BE.get(new binary.stream(data))) {
987
+ case 0xfeedface:
988
+ case 0xcefaedfe:
989
+ case 0xfeedfacf:
990
+ case 0xcffaedfe:
991
+ return true;
992
+ default:
993
+ return false;
994
+ }
995
+ }
996
+
997
+ constructor(data: Uint8Array, mem?: binary.utils.memory) {
998
+ const magic = binary.UINT32_LE.get(new binary.stream(data));
999
+ switch (magic) {
1000
+ case 0xfeedface: this.ready = this.load(data, false, 32, mem); break;
1001
+ case 0xcefaedfe: this.ready = this.load(data, true, 32, mem); break;
1002
+ case 0xfeedfacf: this.ready = this.load(data, false, 64, mem); break;
1003
+ case 0xcffaedfe: this.ready = this.load(data, true, 64, mem); break;
1004
+ default: throw new Error('not a mach file');
1005
+ }
1006
+ }
1007
+
1008
+ async load(data: Uint8Array, be: boolean, bits: 32|64, mem?: binary.utils.memory) {
1009
+ const file = new binary.stream_endian(data, be);
1010
+ const h = binary.read(file, header);
1011
+ const cpu = CPU_TYPE[h.cputype as keyof typeof CPU_TYPE];
1012
+ h.cpusubtype = binary.Enum(CPU_SUBTYPES[cpu])(+h.cpusubtype);
1013
+ if (bits === 64)
1014
+ file.skip(4);
1015
+
1016
+ for (let i = 0; i < h.ncmds; ++i) {
1017
+ const cmd = binary.read(file, command);
1018
+ const file2 = new mach_stream(data, file.read_buffer(cmd.cmdsize - 8), file.be, mem);
1019
+ const result = await binary.read(file2, cmd_table[cmd.cmd] ?? {});
1020
+ this.commands.push({cmd: cmd.cmd, data: result});
1021
+ }
1022
+ this.header = h;
1023
+
1024
+ const funcs = this.getCommandT(CMD.FUNCTION_STARTS);
1025
+ if (funcs) {
1026
+ const array = funcs.contents;
1027
+ const text = await this.getSegment('__TEXT');
1028
+ let acc = BigInt(text?.vmaddr ?? 0);
1029
+ for (const i in array)
1030
+ array[i] = (acc += BigInt(array[i]));
1031
+ }
1032
+ }
1033
+
1034
+ getCommand(cmd: CMD) {
1035
+ for (const i of this.commands) {
1036
+ if (i.cmd === cmd)
1037
+ return i.data;
1038
+ }
1039
+ }
1040
+
1041
+ getCommandT<T extends CMD>(cmd: T) {
1042
+ const c = this.getCommand(cmd);
1043
+ return c as binary.ReadType<typeof cmd_table[T]>;
1044
+ }
1045
+ getSegment(name: string) : binary.ReadType<ReturnType<typeof segment>> | undefined {
1046
+ for (const i of this.commands) {
1047
+ if ((i.cmd === CMD.SEGMENT || i.cmd === CMD.SEGMENT_64) && i.data.segname === name)
1048
+ return i.data;
1049
+ }
1050
+ }
1051
+ }
1052
+
1053
+ const FAT_MAGIC = 0xcafebabe;
1054
+ const FAT_CIGAM = 0xbebafeca;
1055
+
1056
+ export class FATMachFile {
1057
+ archs: binary.ReadType<typeof fat_arch>[] = [];
1058
+
1059
+ static check(data: Uint8Array): boolean {
1060
+ switch (binary.UINT32_BE.get(new binary.stream(data))) {
1061
+ case FAT_MAGIC:
1062
+ case FAT_CIGAM:
1063
+ return true;
1064
+ default:
1065
+ return false;
1066
+ }
1067
+ }
1068
+
1069
+ constructor(data: Uint8Array, mem?: binary.utils.memory) {
1070
+ switch (binary.UINT32_BE.get(new binary.stream(data))) {
1071
+ case FAT_MAGIC: this.load(new binary.stream_endian(data, false), mem); break;
1072
+ case FAT_CIGAM: this.load(new binary.stream_endian(data, true), mem); break;
1073
+ default:
1074
+ throw new Error('not a fat mach file');
1075
+ }
1076
+ }
1077
+
1078
+ load(file: binary.stream_endian, mem?: binary.utils.memory) {
1079
+ const header = binary.read(file, fat_header);
1080
+ this.archs = header.archs;
1081
+ for (const arch of header.archs) {
1082
+ const cpu = CPU_TYPE[arch.cputype as keyof typeof CPU_TYPE];
1083
+ const data = file.buffer_at(arch.offset, arch. size);
1084
+ arch.cpusubtype = binary.Enum(CPU_SUBTYPES[cpu])(+arch.cpusubtype);
1085
+ arch.contents = new MachFile(data);
1086
+ }
1087
+ }
1088
+ }
1089
+