@isopodlabs/binary_libs 0.1.1 → 0.1.3

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