@isopodlabs/binary_libs 0.1.1 → 0.1.2

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 DELETED
@@ -1,1140 +0,0 @@
1
- import * as binary from '@isopodlabs/binary';
2
-
3
- class mach_stream extends binary.endianStream {
4
- constructor(public base: Uint8Array, data: Uint8Array, be: boolean, public mem?: binary.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.asHex(uint32);
21
- const xint64 = binary.asHex(uint64);
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
- } as const;
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
- } as const;
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
- const enum 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 = REQ_DYLD+0x18, // 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 = REQ_DYLD+0x1c, // runpath additions
273
- CODE_SIGNATURE = 0x1d, // local of code signature
274
- SEGMENT_SPLIT_INFO = 0x1e, // local of info to split segments
275
- REEXPORT_DYLIB = REQ_DYLD+0x1f, // 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 = REQ_DYLD+0x22, // compressed dyld information only
280
- LOAD_UPWARD_DYLIB = REQ_DYLD+0x23, // 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 = REQ_DYLD+0x28, // 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 = REQ_DYLD+0x33, // used with linkedit_data_command, payload is trie
297
- DYLD_CHAINED_FIXUPS = REQ_DYLD+0x34, // used with linkedit_data_command
298
- };
299
-
300
- const str = {
301
- get(s: binary.stream) {
302
- const off = uint32.get(s); // offset to the string
303
- return binary.utils.decodeTextTo0(s.buffer_at(off - 8), 'utf8');
304
- }
305
- };
306
-
307
- const index_table = {
308
- first: uint32,
309
- count: uint32,
310
- };
311
-
312
- const blob = {
313
- get(s: mach_stream) {
314
- const offset = uint32.get(s);
315
- const size = uint32.get(s);
316
- if (size)
317
- return s.subdata(offset, size);//.buffer_at(offset, size);
318
- }
319
- };
320
-
321
- function blobT<T extends binary.TypeReader>(type: T) {
322
- return {
323
- get(s: mach_stream) {
324
- const offset = uint32.get(s);
325
- const size = uint32.get(s);
326
- return {
327
- data: s.subdata(offset, size),
328
- contents: binary.read(s.substream(offset, size), type)
329
- };
330
- }
331
- };
332
- }
333
-
334
- function blobArray<T extends binary.Type>(type: T) {
335
- return blobT(binary.RemainingArrayType(type));
336
- }
337
-
338
-
339
- function count_table<T extends binary.TypeReader>(type: T) {
340
- return {
341
- get(s: mach_stream) {
342
- const offset = uint32.get(s);
343
- const count = uint32.get(s);
344
- if (count)
345
- return binary.readn(s.substream(offset), type, count);
346
- }
347
- };
348
- }
349
-
350
- const fixed_string16 = binary.StringType(16);
351
- const version = binary.asFlags(uint32, {major: 0xffff0000, minor: 0xff00, patch: 0xff}, false);
352
-
353
- const command = {
354
- cmd: binary.as(uint32, v => v as CMD),
355
- cmdsize: uint32,
356
- };
357
-
358
- const SECTION_FLAGS = binary.BitFields({
359
- TYPE: [8, binary.Enum({
360
- REGULAR: 0x0, // regular section
361
- ZEROFILL: 0x1, // zero fill on demand section
362
- CSTRING_LITERALS: 0x2, // section with only literal C strings
363
- LITERALS4: 0x3, // section with only 4 byte literals
364
- LITERALS8: 0x4, // section with only 8 byte literals
365
- LITERAL_POINTERS: 0x5, // section with only pointers to literals
366
- NON_LAZY_SYMBOL_POINTERS: 0x6, // section with only non-lazy symbol pointers
367
- LAZY_SYMBOL_POINTERS: 0x7, // section with only lazy symbol pointers
368
- SYMBOL_STUBS: 0x8, // section with only symbol stubs, byte size of stub in the reserved2 field
369
- MOD_INIT_FUNC_POINTERS: 0x9, // section with only function pointers for initialization
370
- MOD_TERM_FUNC_POINTERS: 0xa, // section with only function pointers for termination
371
- COALESCED: 0xb, // section contains symbols that are to be coalesced
372
- GB_ZEROFILL: 0xc, // zero fill on demand section (that can be larger than 4 gigabytes)
373
- INTERPOSING: 0xd, // section with only pairs of function pointers for interposing
374
- LITERALS16: 0xe, // section with only 16 byte literals
375
- DTRACE_DOF: 0xf, // section contains DTrace Object Format
376
- LAZY_DYLIB_SYMBOL_POINTERS: 0x10, // section with only lazy symbol pointers to lazy loaded dylibs
377
- // Section types to support thread local variables
378
- THREAD_LOCAL_REGULAR: 0x11, // template of initial values for TLVs
379
- THREAD_LOCAL_ZEROFILL: 0x12, // template of initial values for TLVs
380
- THREAD_LOCAL_VARIABLES: 0x13, // TLV descriptors
381
- THREAD_LOCAL_VARIABLE_POINTERS: 0x14, // pointers to TLV descriptors
382
- THREAD_LOCAL_INIT_FUNCTION_POINTERS:0x15, // functions to call to initialize TLV values
383
- })],
384
- ATTRIBUTES: [24, binary.BitFields({
385
- SYS: [16, binary.Flags({
386
- SOME_INSTRUCTIONS: 0x0004, // section contains some machine instructions
387
- EXT_RELOC: 0x0002, // section has external relocation entries
388
- LOC_RELOC: 0x0001, // section has local relocation entries
389
- }, true)],
390
- USR: [8, binary.Flags({
391
- PURE_INSTRUCTIONS: 0x80, // section contains only true machine instructions
392
- NO_TOC: 0x40, // section contains coalesced symbols that are not to be in a ranlib table of contents
393
- STRIP_STATIC_SYMS: 0x20, // ok to strip static symbols in this section in files with the MH_DYLDLINK flag
394
- NO_DEAD_STRIP: 0x10, // no dead stripping
395
- LIVE_SUPPORT: 0x08, // blocks are live if they reference live blocks
396
- SELF_MODIFYING_CODE: 0x04, // Used with i386 code stubs written on by dyld
397
- DEBUG: 0x02, // a debug section
398
- }, true)],
399
- })],
400
- });
401
-
402
- function section(bits: 32|64) {
403
- const type = binary.UINT(bits);
404
-
405
- class Section extends binary.Class({
406
- //data: binary.DontRead<binary.utils.MappedMemory>(),
407
- sectname: fixed_string16,
408
- segname: fixed_string16,
409
- addr: type, // memory address of this section
410
- size: type, // size in bytes of this section
411
- offset: xint32, // file offset of this section
412
- align: uint32, // section alignment (power of 2)
413
- reloff: xint32, // file offset of relocation entries
414
- nreloc: uint32, // number of relocation entries
415
- flags: binary.as(uint32, SECTION_FLAGS), // flags (section type and attributes)
416
- reserved1: uint32, // reserved (for offset or index)
417
- reserved2: uint32, // reserved (for count or sizeof)
418
- _: binary.AlignType(bits / 8)
419
- }) {
420
- data: Promise<binary.MappedMemory>;
421
- constructor(s: mach_stream) {
422
- super(s);
423
- const prot = this.flags.ATTRIBUTES.SYS.SOME_INSTRUCTIONS ? binary.MEM.EXECUTE : binary.MEM.NONE;
424
- this.data = (async () =>
425
- //new binary.utils.MappedMemory(await s.file.get(BigInt(this.addr), Number(this.size)), Number(this.addr), prot)
426
- new binary.MappedMemory(s.subdata(+this.offset, Number(this.size)), Number(this.addr), prot)
427
- )();
428
- }
429
- }
430
- return Section;
431
- }
432
-
433
- const SEGMENT_FLAGS = {
434
- 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)
435
- FVMLIB: 0x2, // this segment is the VM that is allocated by a fixed VM library, for overlap checking in the link editor
436
- NORELOC: 0x4, // this segment has nothing that was relocated in it and nothing relocated to it, that is it maybe safely replaced without relocation
437
- 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.
438
- };
439
-
440
- function segment<T extends 32|64>(bits: T) {
441
- const type = binary.UINT(bits);
442
- const fields = {
443
- data: binary.DontRead<binary.MappedMemory>(),
444
- segname: fixed_string16, // segment name
445
- vmaddr: type, // memory address of this segment
446
- vmsize: type, // memory size of this segment
447
- fileoff: type, // file offset of this segment
448
- filesize: type, // amount to map from the file
449
- maxprot: uint32, // maximum VM protection
450
- initprot: uint32, // initial VM protection
451
- nsects: uint32, // number of sections in segment
452
- flags: binary.as(uint32, binary.Flags(SEGMENT_FLAGS,true)), // flags
453
- sections: binary.DontRead<Record<string, any>>(),//binary.ReadType<typeof section(bits)>)),
454
- };
455
- return {
456
- get(s: mach_stream) {
457
- const o = binary.read(s, fields);
458
-
459
- async function load() {
460
- const data = await s.getmem(BigInt(Number(o.vmaddr)), Number(o.filesize)) ?? s.subdata(Number(o.fileoff), Number(o.filesize));
461
- o.data = new binary.MappedMemory(data, Number(o.vmaddr), o.initprot);
462
-
463
- //const sect = section(bits);
464
- if (o.nsects) {
465
- o.sections = binary.objectWithNames(binary.ArrayType(o.nsects, section(bits)), binary.field('sectname')).get(s);
466
- //o.sections = Object.fromEntries(Array.from({length: o.nsects}, (_,i)=>new sect(s)).map(s => [s.sectname, s]));
467
- }
468
- }
469
-
470
- load();
471
- return o;
472
- }
473
- };
474
- }
475
-
476
- /*
477
- function segment(bits: 32|64) {
478
- const type = binary.UINT(bits);
479
- return class extends binary.ReadWriteStruct({
480
- segname: fixed_string16, // segment name
481
- vmaddr: type, // memory address of this segment
482
- vmsize: type, // memory size of this segment
483
- fileoff: type, // file offset of this segment
484
- filesize: type, // amount to map from the file
485
- maxprot: uint32, // maximum VM protection
486
- initprot: uint32, // initial VM protection
487
- nsects: uint32, // number of sections in segment
488
- flags: binary.as(uint32, binary.Flags(SEGMENT_FLAGS,true)), // flags
489
- }) {
490
- data?: binary.MappedMemory;
491
- sections: Record<string, any> = {};
492
-
493
- constructor(s: mach_stream) {
494
- super(s);
495
- this.load(s);
496
- }
497
- async load(s: mach_stream) {
498
- const data = await s.getmem(BigInt(this.vmaddr), Number(this.filesize)) ?? s.subdata(Number(this.fileoff), Number(this.filesize));
499
- this.data = new binary.MappedMemory(data, Number(this.vmaddr), this.initprot);
500
-
501
- //const sect = section(bits);
502
- if (this.nsects) {
503
- this.sections = binary.objectWithNames(binary.ArrayType(this.nsects, section(bits)), binary.field('sectname')).get(s);
504
- //o.sections = Object.fromEntries(Array.from({length: o.nsects}, (_,i)=>new sect(s)).map(s => [s.sectname, s]));
505
- }
506
-
507
- }
508
- };
509
- }
510
- */
511
-
512
- const fvmlib = {
513
- name: str, // library's target pathname
514
- minor_version: xint32, // library's minor version number
515
- header_addr: xint32, // library's header address
516
- };
517
-
518
- const dylib = {
519
- name: str,
520
- timestamp: uint32,
521
- current_version: version,
522
- compatibility_version: version,
523
- };
524
-
525
- const thread_command = {
526
- flavor: uint32, // flavor of thread state
527
- count: uint32, // count of longs in thread state
528
- // struct XXX_thread_state state thread state for this flavor
529
- // ...
530
- };
531
-
532
-
533
- // SYMTAB
534
- const nlist_flags = binary.BitFields({
535
- ext: 1,
536
- type: [3, binary.Enum({
537
- UNDF: 0, // undefined, n_sect == NO_SECT
538
- ABS: 1, // absolute, n_sect == NO_SECT
539
- INDR: 5, // indirect
540
- PBUD: 6, // prebound undefined (defined in a dylib)
541
- SECT: 7, // defined in section number n_sect
542
- })],
543
- pext: 1,
544
- stab: [3, binary.Enum({
545
-
546
- })],
547
- });
548
- /*
549
- //masks
550
- //STAB = 0xe0, // if any of these bits set, a symbolic debugging entry
551
- PEXT = 0x10, // private external symbol bit
552
- //TYPE = 0x0e, // mask for the type bits
553
- EXT = 0x01, // external symbol bit, set for external symbols
554
-
555
- UNDF = 0x00, // undefined, n_sect == NO_SECT
556
- ABS = 0x02, // absolute, n_sect == NO_SECT
557
- INDR = 0x0a, // indirect
558
- PBUD = 0x0c, // prebound undefined (defined in a dylib)
559
- SECT = 0x0e, // defined in section number n_sect
560
- // STAB values
561
- GSYM = 0x20, // global symbol: name,,NO_SECT,type,0
562
- FNAME = 0x22, // procedure name (f77 kludge): name,,NO_SECT,0,0
563
- FUN = 0x24, // procedure: name,,n_sect,linenumber,address
564
- STSYM = 0x26, // static symbol: name,,n_sect,type,address
565
- LCSYM = 0x28, // .lcomm symbol: name,,n_sect,type,address
566
- BNSYM = 0x2e, // begin nsect sym: 0,,n_sect,0,address
567
- OPT = 0x3c, // emitted with gcc2_compiled and in gcc source
568
- RSYM = 0x40, // register sym: name,,NO_SECT,type,register
569
- SLINE = 0x44, // src line: 0,,n_sect,linenumber,address
570
- ENSYM = 0x4e, // end nsect sym: 0,,n_sect,0,address
571
- SSYM = 0x60, // structure elt: name,,NO_SECT,type,struct_offset
572
- SO = 0x64, // source file name: name,,n_sect,0,address
573
- OSO = 0x66, // object file name: name,,0,0,st_mtime
574
- LSYM = 0x80, // local sym: name,,NO_SECT,type,offset
575
- BINCL = 0x82, // include file beginning: name,,NO_SECT,0,sum
576
- SOL = 0x84, // #included file name: name,,n_sect,0,address
577
- PARAMS = 0x86, // compiler parameters: name,,NO_SECT,0,0
578
- VERSION = 0x88, // compiler version: name,,NO_SECT,0,0
579
- OLEVEL = 0x8A, // compiler -O level: name,,NO_SECT,0,0
580
- PSYM = 0xa0, // parameter: name,,NO_SECT,type,offset
581
- EINCL = 0xa2, // include file end: name,,NO_SECT,0,0
582
- ENTRY = 0xa4, // alternate entry: name,,n_sect,linenumber,address
583
- LBRAC = 0xc0, // left bracket: 0,,NO_SECT,nesting level,address
584
- EXCL = 0xc2, // deleted include file: name,,NO_SECT,0,sum
585
- RBRAC = 0xe0, // right bracket: 0,,NO_SECT,nesting level,address
586
- BCOMM = 0xe2, // begin common: name,,NO_SECT,0,0
587
- ECOMM = 0xe4, // end common: name,,n_sect,0,0
588
- ECOML = 0xe8, // end common (local name): 0,,n_sect,0,address
589
- LENG = 0xfe, // second stab entry with length information
590
- }
591
- */
592
- const nlist_desc = binary.BitFields({
593
- ref: [3, binary.Enum({
594
- UNDEFINED_NON_LAZY: 0,
595
- UNDEFINED_LAZY: 1,
596
- DEFINED: 2,
597
- PRIVATE_DEFINED: 3,
598
- PRIVATE_UNDEFINED_NON_LAZY: 4,
599
- PRIVATE_UNDEFINED_LAZY: 5,
600
- })],
601
- flags: [5, binary.Flags({
602
- ARM_THUMB_DEF: 1 << 0, // symbol is a Thumb function (ARM)
603
- REF_DYNAMIC: 1 << 1,
604
- NO_DEAD_STRIP: 1 << 2, // symbol is not to be dead stripped
605
- //DESC_DISCARDE: 1 << 2, // symbol is discarded
606
- WEAK_REF: 1 << 3, // symbol is weak referenced
607
- WEAK_DEF: 1 << 4, // coalesed symbol is a weak definition
608
- //REF_TO_WEA 1 << 4, // reference to a weak symbol
609
- //SYMBOL_RESOLVER: 0x0100,
610
- }, true)],
611
- align: 8
612
- //MAX_LIBRARY_ORDINAL = 0xfd << 8,
613
- //DYNAMIC_LOOKUP_ORDINAL = 0xfe << 8,
614
- //EXECUTABLE_ORDINAL = 0xff << 8,
615
- });
616
-
617
- function nlist(bits:32|64) { return {
618
- strx: uint32, // index into the string table
619
- flags: binary.as(binary.UINT8, nlist_flags),
620
- sect: binary.UINT8,// section number or NO_SECT
621
- desc: binary.as(uint16, nlist_desc),
622
- value: binary.UINT(bits),
623
-
624
- //const char *name(const char *s) const { return s ? s + strx : ""; }
625
- //FLAGS type() const { return FLAGS(flags & TYPE); }
626
- //FLAGS stab() const { return FLAGS(flags & STAB); }
627
- }; }
628
-
629
- const symtab = {
630
- get(s: binary._stream) {
631
- const sym = binary.read(s, count_table(nlist(64)));
632
- const str = binary.read(s, blob) as Uint8Array;
633
- return sym?.map(v => [binary.utils.decodeTextTo0(str.subarray(v.strx), 'utf8'), v]);
634
- }
635
- };
636
-
637
- // DYSYMTAB
638
-
639
- const INDIRECT = {
640
- INDIRECT_SYMBOL_LOCAL: 0x80000000, // non-lazy symbol pointer section for a defined symbol which strip(1) has removed
641
- INDIRECT_SYMBOL_ABS: 0x40000000,
642
- } as const;
643
-
644
- const toc_entry = {
645
- symbol_index: uint32, // the defined external symbol (index into the symbol table)
646
- module_index: uint32, // index into the module table this symbol is defined in
647
- };
648
-
649
- function module(bits:32|64) {
650
- const fields = {
651
- module_name: uint32, // the module name (index into string table)
652
- extdefsym: index_table, // index into externally defined symbols
653
- refsym: index_table, // index into reference symbol table
654
- localsym: index_table, // index into symbols for local symbols
655
- extrel: index_table, // index into external relocation entries
656
- init_iterm: index_table, // low 16 bits are the index into the init section, high 16 bits are the index into the term section
657
- };
658
- return bits == 32 ? {...fields,
659
- objc_module_info_addr: uint32, // for this module address of the start of the (__OBJC,__module_info) section
660
- objc_module_info_size: uint32, // for this module size of the (__OBJC,__module_info) section
661
- } : {...fields,
662
- objc_module_info_size: uint32, // for this module size of the (__OBJC, __module_info) section
663
- objc_module_info_addr: uint64, // for this module address of the start of the (__OBJC, __module_info) section
664
- };
665
- }
666
-
667
- const symbol_ref = binary.as(uint32, binary.BitFields({
668
- symbol_index: 24, // index into the symbol table
669
- flags: 8
670
- }));
671
-
672
- const hint = binary.as(uint32, binary.BitFields({
673
- sub_image: 8, // index into the sub images
674
- toc: 24 // index into the table of contents
675
- }));
676
-
677
- const version_min = {
678
- version,
679
- reserved: uint32, // zero
680
- };
681
-
682
- const REBASE = binary.BitFields({
683
- immediate: 4,
684
- opcode: [4, binary.Enum({
685
- DONE: 0,
686
- SET_TYPE_IMM: 1,
687
- SET_SEGMENT_AND_OFFSET_ULEB: 2,
688
- ADD_ADDR_ULEB: 3,
689
- ADD_ADDR_IMM_SCALED: 4,
690
- DO_REBASE_IMM_TIMES: 5,
691
- DO_REBASE_ULEB_TIMES: 6,
692
- DO_REBASE_ADD_ADDR_ULEB: 7,
693
- DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: 8,
694
- })]
695
- //TYPE_POINTER = 1,
696
- //TYPE_TEXT_ABSOLUTE32 = 2,
697
- //TYPE_TEXT_PCREL32 = 3,
698
- });
699
-
700
- const BIND = binary.BitFields({
701
- immediate: 4,
702
- opcode: [4, binary.Enum({
703
- DONE: 0,
704
- SET_DYLIB_ORDINAL_IMM: 1,
705
- SET_DYLIB_ORDINAL_ULEB: 2,
706
- SET_DYLIB_SPECIAL_IMM: 3,
707
- SET_SYMBOL_TRAILING_FLAGS_IMM: 4,
708
- SET_TYPE_IMM: 5,
709
- SET_ADDEND_SLEB: 6,
710
- SET_SEGMENT_AND_OFFSET_ULEB: 7,
711
- ADD_ADDR_ULEB: 8,
712
- DO_BIND: 9,
713
- DO_BIND_ADD_ADDR_ULEB: 10,
714
- DO_BIND_ADD_ADDR_IMM_SCALED: 11,
715
- DO_BIND_ULEB_TIMES_SKIPPING_ULEB: 12,
716
- })]
717
- //TYPE_POINTER = 1,
718
- //TYPE_TEXT_ABSOLUTE32 = 2,
719
- //TYPE_TEXT_PCREL32 = 3,
720
- //SPECIAL_DYLIB_SELF = 0,
721
- //SPECIAL_DYLIB_MAIN_EXECUTABLE = -1,
722
- //SPECIAL_DYLIB_FLAT_LOOKUP = -2,
723
- //SYMBOL_FLAGS_WEAK_IMPORT = 0x1,
724
- //SYMBOL_FLAGS_NON_WEAK_DEFINITION = 0x8,
725
- });
726
-
727
- const dyld_kind = {
728
- KIND_MASK: 0x03,
729
- KIND_REGULAR: 0x00,
730
- KIND_THREAD_LOCAL: 0x01,
731
- KIND_ABSOLUTE: 0x02,
732
- WEAK_DEFINITION: 0x04,
733
- REEXPORT: 0x08,
734
- STUB_AND_RESOLVER: 0x10,
735
- } as const;
736
-
737
- const dyldinfo = {
738
- rebase: blob,
739
- bind: blob,
740
- weak_bind: blob,
741
- lazy_bind: blob,
742
- exprt: blob,
743
- };
744
-
745
- //BUILD_VERSION
746
- const TOOL = {
747
- CLANG: 1,
748
- SWIFT: 2,
749
- LD: 3,
750
- LLD: 4,
751
- } as const;
752
-
753
- const PLATFORM = {
754
- MACOS: 1,
755
- IOS: 2,
756
- TVOS: 3,
757
- WATCHOS: 4,
758
- BRIDGEOS: 5,
759
- MACCATALYST: 6,
760
- IOSSIMULATOR: 7,
761
- TVOSSIMULATOR: 8,
762
- WATCHOSSIMULATOR: 9,
763
- DRIVERKIT: 10,
764
- } as const;
765
-
766
- //DYLD_CHAINED_FIXUPS
767
-
768
- const dyld_chained_starts_in_segment = {
769
- size: uint32, ///< Size of this, including chain_starts entries
770
- page_size: uint16, ///< Page size in bytes (0x1000 or 0x4000)
771
- pointer_format: binary.asEnum(uint16, {
772
- ARM64E: 1,
773
- '64': 2,
774
- '32': 3,
775
- '32_CACHE': 4,
776
- '32_FIRMWARE': 5,
777
- '64_OFFSET': 6,
778
- ARM64E_KERNEL: 7,
779
- '64_KERNEL_CACHE': 8,
780
- ARM64E_USERLAND: 9,
781
- ARM64E_FIRMWARE: 10,
782
- X86_64_KERNEL_CACHE: 11,
783
- ARM64E_USERLAND24: 12,
784
- }),
785
- segment_offset: xint64, // VM offset from the __TEXT segment
786
- max_valid_pointer: xint32, // Values beyond this are not pointers on 32-bit
787
- pages: binary.ArrayType(uint16, binary.asEnum(uint16, {
788
- NONE: 0xFFFF,
789
- MULTI: 0x8000, // page which has multiple starts
790
- LAST: 0x8000, // last chain_start for a given page
791
- }))
792
- };
793
-
794
- const dyld_chained_starts_in_image = binary.ArrayType(uint32, binary.OffsetType(uint32, dyld_chained_starts_in_segment));
795
-
796
- const dyld_chained_import = binary.as(uint32, binary.BitFields({
797
- lib_ordinal : 8,
798
- weak_import : 1,
799
- name_offset : 23,
800
- }));
801
-
802
- const dyld_chained_import_addend = {
803
- import: dyld_chained_import,
804
- addend: int32,
805
- };
806
-
807
- const dyld_chained_import_addend64 = {
808
- import: binary.as(uint64, binary.BitFields({
809
- lib_ordinal : 16,
810
- weak_import : 1,
811
- reserved : 15,
812
- name_offset : 32,
813
- })),
814
- addend: uint64,
815
- };
816
-
817
- class dyld_chained_fixups extends binary.ReadClass({
818
- fixups_version: uint32, // currently 0
819
- starts: binary.OffsetType(uint32, dyld_chained_starts_in_image),
820
- imports: binary.OffsetType(uint32, binary.Remainder), // offset of imports table in chain_data
821
- symbols: binary.OffsetType(uint32, binary.Remainder), // offset of symbol strings in chain_data
822
- imports_count: uint32, // number of imported symbol names
823
- imports_format: binary.asEnum(uint32, {
824
- IMPORT: 1,
825
- IMPORT_ADDEND: 2,
826
- IMPORT_ADDEND64: 3
827
- }),
828
- symbols_format: binary.asEnum(uint32, {
829
- UNCOMPRESSED: 0,
830
- ZLIB: 1,
831
- }),
832
- }) {
833
- imports2;
834
- constructor(s: binary.endianStream) {
835
- super(s);
836
- const imports = new binary.endianStream(this.imports, s.be);
837
- switch (this.imports_format) {
838
- case 'IMPORT': {
839
- this.imports2 = binary.withNames(binary.readn(imports, dyld_chained_import, this.imports_count), imp => binary.utils.decodeTextTo0(this.symbols.subarray(Number(imp.name_offset))));
840
- break;
841
- }
842
- case 'IMPORT_ADDEND':
843
- 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))));
844
- break;
845
- case 'IMPORT_ADDEND64':
846
- 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))));
847
- break;
848
- }
849
- }
850
- }
851
-
852
- const dyld_chained_ptr_64_bind = binary.as(uint64, binary.BitFields({
853
- ordinal : 24,
854
- addend : 8,
855
- reserved : 19,
856
- next : 12,
857
- bind : 1, // set to 1
858
- }));
859
-
860
- const dyld_chained_ptr_64_rebase = binary.as(uint64, binary.BitFields({
861
- target : 36,
862
- high8 : 8,
863
- reserved : 7,
864
- next : 12,
865
- bind : 1, // set to 0
866
- }));
867
-
868
- //DATA_IN_CODE
869
-
870
- const data_in_code_entry = {
871
- offset: xint32, // from header to start of data range
872
- length: uint16, // number of bytes in data range
873
- kind: binary.as(uint16, binary.Enum({
874
- DATA: 0x0001,
875
- JUMP_TABLE8: 0x0002,
876
- JUMP_TABLE16: 0x0003,
877
- JUMP_TABLE32: 0x0004,
878
- ABS_JUMP_TABLE32: 0x0005,
879
- })),
880
- };
881
-
882
- // Sections of type S_THREAD_LOCAL_VARIABLES contain an array of tlv_descriptor structures.
883
- /*
884
- const tlv_descriptor = {
885
- void* (*thunk)(tlv_descriptor*);
886
- unsigned long key;
887
- unsigned long offset;
888
- };
889
- */
890
-
891
- function routines(bits:32|64) {
892
- const type = binary.UINT(bits);
893
- return {
894
- init_address: type, // address of initialization routine
895
- init_module: type, // index into the module table that the init routine is defined in
896
- reserved1: type,
897
- reserved2: type,
898
- reserved3: type,
899
- reserved4: type,
900
- reserved5: type,
901
- reserved6: type,
902
- };
903
- }
904
-
905
-
906
-
907
- //const cmd_table : {[K in CMD]?: binary.TypeReader2} = {
908
- const cmd_table = {//: Record<CMD, binary.TypeReader2> = {
909
- [CMD.SEGMENT]: segment(32),
910
- [CMD.SEGMENT_64]: segment(64),
911
- [CMD.LOADFVMLIB]: fvmlib,
912
- [CMD.IDFVMLIB]: fvmlib,
913
-
914
- [CMD.LOAD_DYLIB]: dylib,
915
- [CMD.ID_DYLIB]: dylib,
916
- [CMD.LOAD_WEAK_DYLIB]: dylib,
917
- [CMD.REEXPORT_DYLIB]: dylib,
918
- [CMD.LAZY_LOAD_DYLIB]: dylib,
919
- [CMD.LOAD_UPWARD_DYLIB]: dylib,
920
-
921
- [CMD.SUB_FRAMEWORK]: str,
922
- [CMD.SUB_UMBRELLA]: str,
923
- [CMD.SUB_CLIENT]: str,
924
- [CMD.SUB_LIBRARY]: str,
925
- [CMD.LOAD_DYLINKER]: str,
926
- [CMD.ID_DYLINKER]: str,
927
- [CMD.DYLD_ENVIRONMENT]: str,
928
- [CMD.RPATH]: str,
929
-
930
- [CMD.PREBOUND_DYLIB]: {
931
- name: str,
932
- nmodules: uint32,
933
- linked_modules: str,
934
- },
935
-
936
- [CMD.THREAD]: thread_command,
937
- [CMD.UNIXTHREAD]: thread_command,
938
-
939
- [CMD.ROUTINES]: routines(32),
940
- [CMD.ROUTINES_64]: routines(64),
941
-
942
- [CMD.SYMTAB]: symtab,
943
-
944
- [CMD.TWOLEVEL_HINTS]: count_table(hint),
945
-
946
- [CMD.PREBIND_CKSUM]: {
947
- cksum: uint32,
948
- },
949
-
950
- [CMD.UUID]: {
951
- uuid: binary.Buffer(16),
952
- },
953
-
954
- [CMD.CODE_SIGNATURE]: blob,
955
- [CMD.SEGMENT_SPLIT_INFO]: blob,
956
- [CMD.FUNCTION_STARTS]: blobArray(binary.ULEB128),
957
- [CMD.DATA_IN_CODE]: blobArray(data_in_code_entry),
958
- [CMD.DYLIB_CODE_SIGN_DRS]: blob,
959
- [CMD.LINKER_OPTIMIZATION_HINT]: blob,
960
- [CMD.DYLD_EXPORTS_TRIE]: blob,
961
- [CMD.DYLD_CHAINED_FIXUPS]: blob,//blobT(dyld_chained_fixups),
962
-
963
- [CMD.ENCRYPTION_INFO]: {
964
- cryptoff: uint32, // file offset of encrypted range
965
- cryptsize: uint32, // file size of encrypted range
966
- cryptid: uint32, // which enryption system, 0 means not-encrypted yet
967
- },
968
- [CMD.ENCRYPTION_INFO_64]: {
969
- cryptoff: uint32, // file offset of encrypted range
970
- cryptsize: uint32, // file size of encrypted range
971
- cryptid: uint32, // which enryption system, 0 means not-encrypted yet
972
- pad: uint32, // must be zero
973
- },
974
-
975
- [CMD.VERSION_MIN_MACOSX]: version_min,
976
- [CMD.VERSION_MIN_IPHONEOS]: version_min,
977
- [CMD.VERSION_MIN_TVOS]: version_min,
978
- [CMD.VERSION_MIN_WATCHOS]: version_min,
979
-
980
- [CMD.DYLD_INFO]: dyldinfo,
981
- [CMD.DYLD_INFO_ONLY]: dyldinfo,
982
-
983
- [CMD.SYMSEG]: blob,//OBSOLETE
984
-
985
- // [CMD.IDENT]: {},//OBSOLETE
986
-
987
- [CMD.FVMFILE]: {//OBSOLETE
988
- name: str,
989
- header_addr: uint32,
990
- },
991
-
992
- [CMD.MAIN]: {
993
- entryoff: uint32, // file (__TEXT) offset of entry point
994
- stacksize: uint32, // if not zero, initialize stack size
995
- },
996
-
997
- [CMD.SOURCE_VERSION]: {
998
- 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
999
- },
1000
- [CMD.BUILD_VERSION]: {
1001
- platform: binary.asEnum(uint32, PLATFORM),
1002
- minos: version,
1003
- sdk: version,
1004
- tools: binary.objectWithNames(binary.ArrayType(uint32, {tool: binary.as(uint32, binary.Enum(TOOL)), version}), binary.field('tool')),
1005
- },
1006
- [CMD.LINKER_OPTION]: {
1007
- count: uint32, // number of strings following
1008
- },
1009
- [CMD.NOTE]: {
1010
- data_owner: fixed_string16, // owner name for this LC_NOTE
1011
- data: blob
1012
- },
1013
- // [CMD.PREPAGE]: {},
1014
- [CMD.DYSYMTAB]: {
1015
- localsym: index_table, // local symbols
1016
- extdefsym: index_table, // externally defined symbols
1017
- undefsym: index_table, // undefined symbols
1018
- toc: count_table(toc_entry), // table of contents
1019
- modtab: count_table(module(64)), // module table
1020
- extrefsym: count_table(symbol_ref), // referenced symbol table
1021
- indirectsym: count_table(symbol_ref), // indirect symbol table
1022
- extrel: count_table({address:uint32, symbol_ref}), // external relocation entries
1023
- locrel: count_table({address:uint32, symbol_ref}), // local relocation entries
1024
- },
1025
- };
1026
-
1027
- export class MachFile {
1028
- header: any;
1029
- commands:{cmd:CMD, data:any}[] = [];
1030
- ready: Promise<void>;
1031
-
1032
- static check(data: Uint8Array): boolean {
1033
- switch (binary.UINT32_BE.get(new binary.stream(data))) {
1034
- case 0xfeedface:
1035
- case 0xcefaedfe:
1036
- case 0xfeedfacf:
1037
- case 0xcffaedfe:
1038
- return true;
1039
- default:
1040
- return false;
1041
- }
1042
- }
1043
-
1044
- constructor(data: Uint8Array, mem?: binary.memory) {
1045
- const magic = binary.UINT32_LE.get(new binary.stream(data));
1046
- switch (magic) {
1047
- case 0xfeedface: this.ready = this.load(data, false, 32, mem); break;
1048
- case 0xcefaedfe: this.ready = this.load(data, true, 32, mem); break;
1049
- case 0xfeedfacf: this.ready = this.load(data, false, 64, mem); break;
1050
- case 0xcffaedfe: this.ready = this.load(data, true, 64, mem); break;
1051
- default: throw new Error('not a mach file');
1052
- }
1053
- }
1054
-
1055
- async load(data: Uint8Array, be: boolean, bits: 32|64, mem?: binary.memory) {
1056
- const file = new binary.endianStream(data, be);
1057
- const h = binary.read(file, header);
1058
- const cpu = CPU_TYPE[h.cputype as keyof typeof CPU_TYPE];
1059
- h.cpusubtype = binary.Enum(CPU_SUBTYPES[cpu])(+h.cpusubtype);
1060
- if (bits === 64)
1061
- file.skip(4);
1062
-
1063
- for (let i = 0; i < h.ncmds; ++i) {
1064
- const cmd = binary.read(file, command);
1065
- const file2 = new mach_stream(data, file.read_buffer(cmd.cmdsize - 8), file.be, mem);
1066
- const result = await binary.read(file2, cmd_table[cmd.cmd] ?? {});
1067
- this.commands.push({cmd: cmd.cmd, data: result});
1068
- }
1069
- this.header = h;
1070
-
1071
- const funcs = this.getCommand(CMD.FUNCTION_STARTS);
1072
- if (funcs) {
1073
- const array = funcs.contents;
1074
- const text = await this.getSegment('__TEXT');
1075
- let acc = BigInt(text?.vmaddr ?? 0);
1076
- for (const i in array)
1077
- array[i] = (acc += BigInt(array[i]));
1078
- }
1079
- }
1080
-
1081
- getCommand<T extends CMD>(cmd: T) : binary.ReadType<typeof cmd_table[T]>;
1082
- getCommand(cmd: CMD) {
1083
- for (const i of this.commands) {
1084
- if (i.cmd === cmd)
1085
- return i.data;
1086
- }
1087
- }
1088
-
1089
- getSegment(name: string) {
1090
- for (const i of this.commands) {
1091
- if (i.cmd === CMD.SEGMENT && i.data.segname === name)
1092
- return i.data as binary.ReadType<typeof cmd_table[CMD.SEGMENT]>;
1093
- if (i.cmd === CMD.SEGMENT_64 && i.data.segname === name)
1094
- return i.data as binary.ReadType<typeof cmd_table[CMD.SEGMENT_64]>;;
1095
- }
1096
- }
1097
- }
1098
-
1099
- const FAT_MAGIC = 0xcafebabe;
1100
- const FAT_CIGAM = 0xbebafeca;
1101
-
1102
- export class FATMachFile {
1103
- archs: binary.ReadType<typeof fat_arch>[] = [];
1104
-
1105
- static check(data: Uint8Array): boolean {
1106
- switch (binary.UINT32_BE.get(new binary.stream(data))) {
1107
- case FAT_MAGIC:
1108
- case FAT_CIGAM:
1109
- return true;
1110
- default:
1111
- return false;
1112
- }
1113
- }
1114
-
1115
- constructor(data: Uint8Array, mem?: binary.memory) {
1116
- switch (binary.UINT32_BE.get(new binary.stream(data))) {
1117
- case FAT_MAGIC: this.load(new binary.endianStream(data, false), mem); break;
1118
- case FAT_CIGAM: this.load(new binary.endianStream(data, true), mem); break;
1119
- default:
1120
- throw new Error('not a fat mach file');
1121
- }
1122
- }
1123
-
1124
- load(file: binary.endianStream, mem?: binary.memory) {
1125
- const header = binary.read(file, fat_header);
1126
- this.archs = header.archs;
1127
- for (const arch of header.archs) {
1128
- const cpu = CPU_TYPE[arch.cputype as keyof typeof CPU_TYPE];
1129
- const data = file.buffer_at(arch.offset, arch. size);
1130
- arch.cpusubtype = binary.Enum(CPU_SUBTYPES[cpu])(+arch.cpusubtype);
1131
- arch.contents = new MachFile(data, mem);
1132
- }
1133
- }
1134
- }
1135
- /*
1136
- export function freestanding<T extends CMD>(s: binary.stream, cmd: T) : binary.ReadType<typeof cmd_table[T]>;
1137
- export function freestanding(s: binary.stream, cmd: CMD) {
1138
- return binary.read(s, cmd_table[cmd]);
1139
- }
1140
- */