summaryrefslogtreecommitdiff
path: root/view/macho/machoview.h
blob: 0e0216f96b9050fd70f27f6bc1b7a39dd01b75b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
#pragma once

#include <exception>
#include <vector>
#include <string.h>

#include "binaryninjaapi.h"
#include "objc.h"

//These are laready defined in one of the osx headers we want to override
#undef CPU_SUBTYPE_INTEL
#undef CPU_SUBTYPE_I386_ALL
#undef CPU_SUBTYPE_POWERPC_ALL
#undef LC_MAIN
#undef LC_SOURCE_VERSION
#undef LC_DYLIB_CODE_SIGN_DRS
#undef LC_DYLD_INFO_ONLY

#define MH_MAGIC     0xfeedface
#define MH_MAGIC_64  0xfeedfacf
#define MH_CIGAM     0xcefaedfe
#define MH_CIGAM_64  0xcffaedfe
#define FAT_MAGIC    0xcafebabe
#define FAT_MAGIC_64 0xcafebabf

typedef int32_t cpu_type_t;
typedef int32_t cpu_subtype_t;
typedef int vm_prot_t;

//Cpu types
#define MACHO_CPU_ARCH_ABI64           0x01000000
#define MACHO_CPU_ARCH_ABI64_32        0x02000000

#define MACHO_CPU_TYPE_ANY       ((cpu_type_t) -1)
#define MACHO_CPU_TYPE_VAX       ((cpu_type_t) 1)
#define MACHO_CPU_TYPE_MC680x0	((cpu_type_t) 6)
#define MACHO_CPU_TYPE_X86       ((cpu_type_t) 7)
#define MACHO_CPU_TYPE_X86_64    (MACHO_CPU_TYPE_X86 | MACHO_CPU_ARCH_ABI64)
#define MACHO_CPU_TYPE_MIPS      ((cpu_type_t) 8)
#define MACHO_CPU_TYPE_MC98000	((cpu_type_t) 10)
#define MACHO_CPU_TYPE_HPPA      ((cpu_type_t) 11)
#define MACHO_CPU_TYPE_ARM       ((cpu_type_t) 12)
#define MACHO_CPU_TYPE_ARM64     (MACHO_CPU_TYPE_ARM | MACHO_CPU_ARCH_ABI64)
#define MACHO_CPU_TYPE_ARM64_32  (MACHO_CPU_TYPE_ARM | MACHO_CPU_ARCH_ABI64_32)
#define MACHO_CPU_TYPE_MC88000   ((cpu_type_t) 13)
#define MACHO_CPU_TYPE_SPARC     ((cpu_type_t) 14)
#define MACHO_CPU_TYPE_I860      ((cpu_type_t) 15)
#define MACHO_CPU_TYPE_ALPHA     ((cpu_type_t) 16)
#define MACHO_CPU_TYPE_POWERPC   ((cpu_type_t) 18)
#define MACHO_CPU_TYPE_POWERPC64 (MACHO_CPU_TYPE_POWERPC | MACHO_CPU_ARCH_ABI64)

//Cpu subtype capability bits
#define MACHO_CPU_SUBTYPE_MASK         ((cpu_subtype_t)0xff000000)
#define MACHO_CPU_SUBTYPE_LIB64        ((cpu_subtype_t)0x80000000)

//Cpu subtypes
#define MACHO_CPU_SUBTYPE_INTEL(f,m)   ((cpu_subtype_t) (f)+((m)<<4))
#define MACHO_CPU_SUBTYPE_I386_ALL     MACHO_CPU_SUBTYPE_INTEL(3,0)
#define MACHO_CPU_SUBTYPE_X86_ALL      ((cpu_subtype_t) 3)
#define MACHO_CPU_SUBTYPE_X86_ARCH1    ((cpu_subtype_t) 4)
#define MACHO_CPU_SUBTYPE_X86_64_ALL   ((cpu_subtype_t) 3)
#define MACHO_CPU_SUBTYPE_X86_64_H     ((cpu_subtype_t) 8)

#define MACHO_CPU_SUBTYPE_ARM_ALL      ((cpu_subtype_t) 0)
#define MACHO_CPU_SUBTYPE_ARM_V4T      ((cpu_subtype_t) 5)
#define MACHO_CPU_SUBTYPE_ARM_V6       ((cpu_subtype_t) 6)
#define MACHO_CPU_SUBTYPE_ARM_V5TEJ    ((cpu_subtype_t) 7)
#define MACHO_CPU_SUBTYPE_ARM_XSCALE   ((cpu_subtype_t) 8)
#define MACHO_CPU_SUBTYPE_ARM_V7       ((cpu_subtype_t) 9)
#define MACHO_CPU_SUBTYPE_ARM_V7F      ((cpu_subtype_t) 10)
#define MACHO_CPU_SUBTYPE_ARM_V7S      ((cpu_subtype_t) 11)
#define MACHO_CPU_SUBTYPE_ARM_V7K      ((cpu_subtype_t) 12)
#define MACHO_CPU_SUBTYPE_ARM_V8       ((cpu_subtype_t) 13)
#define MACHO_CPU_SUBTYPE_ARM_V6M      ((cpu_subtype_t) 14)
#define MACHO_CPU_SUBTYPE_ARM_V7M      ((cpu_subtype_t) 15)
#define MACHO_CPU_SUBTYPE_ARM_V7EM     ((cpu_subtype_t) 16)

#define MACHO_CPU_SUBTYPE_ARM64_ALL    ((cpu_subtype_t) 0)
#define MACHO_CPU_SUBTYPE_ARM64_V8     ((cpu_subtype_t) 1)
#define MACHO_CPU_SUBTYPE_ARM64E       ((cpu_subtype_t) 2)

#define MACHO_CPU_SUBTYPE_ARM64_32_ALL ((cpu_subtype_t) 0)
#define MACHO_CPU_SUBTYPE_ARM64_32_V8  ((cpu_subtype_t) 1)

#define MACHO_CPU_SUBTYPE_POWERPC_ALL   ((cpu_subtype_t) 0)
#define MACHO_CPU_SUBTYPE_POWERPC_601   ((cpu_subtype_t) 1)
#define MACHO_CPU_SUBTYPE_POWERPC_602   ((cpu_subtype_t) 2)
#define MACHO_CPU_SUBTYPE_POWERPC_603   ((cpu_subtype_t) 3)
#define MACHO_CPU_SUBTYPE_POWERPC_603e  ((cpu_subtype_t) 4)
#define MACHO_CPU_SUBTYPE_POWERPC_603ev ((cpu_subtype_t) 5)
#define MACHO_CPU_SUBTYPE_POWERPC_604   ((cpu_subtype_t) 6)
#define MACHO_CPU_SUBTYPE_POWERPC_604e  ((cpu_subtype_t) 7)
#define MACHO_CPU_SUBTYPE_POWERPC_620   ((cpu_subtype_t) 8)
#define MACHO_CPU_SUBTYPE_POWERPC_750   ((cpu_subtype_t) 9)
#define MACHO_CPU_SUBTYPE_POWERPC_7400  ((cpu_subtype_t) 10)
#define MACHO_CPU_SUBTYPE_POWERPC_7450  ((cpu_subtype_t) 11)
#define MACHO_CPU_SUBTYPE_POWERPC_970   ((cpu_subtype_t) 100)

//Page protections
#define MACHO_VM_PROT_NONE             ((vm_prot_t) 0x00)
#define MACHO_VM_PROT_READ             ((vm_prot_t) 0x01)
#define MACHO_VM_PROT_WRITE            ((vm_prot_t) 0x02)
#define MACHO_VM_PROT_EXECUTE          ((vm_prot_t) 0x04)
#define MACHO_VM_PROT_DEFAULT          (VM_PROT_READ|VM_PROT_WRITE)
#define MACHO_VM_PROT_ALL              (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE)
#define MACHO_VM_PROT_NO_CHANGE        ((vm_prot_t) 0x08)
#define MACHO_VM_PROT_COPY             ((vm_prot_t) 0x10)
#define MACHO_VM_PROT_WANTS_COPY       ((vm_prot_t) 0x10)

//Segment flags
#define SG_HIGHVM 0x1
#define SG_FVMLIB 0x2
#define SG_NORELOC 0x4
#define SG_PROTECTED_VERSION_1 0x8

//Section flags
#define S_ATTR_SOME_INSTRUCTIONS              0x00000400
#define S_ATTR_PURE_INSTRUCTIONS              0x80000000 // section contains only true machine instructions
#define S_ATTR_NO_TOC                         0x40000000 // section contains coalesced symbols that are not to be in a ranlib table of contents
#define S_ATTR_STRIP_STATIC_SYMS              0x20000000 // ok to strip static symbols in this section in files with the MH_DYLDLINK flag
#define S_ATTR_NO_DEAD_STRIP                  0x10000000 // no dead stripping
#define S_ATTR_LIVE_SUPPORT                   0x08000000 // blocks are live if they reference live blocks
#define S_ATTR_SELF_MODIFYING_CODE            0x04000000 // Used with i386 code stubs written on by dyld

#define S_REGULAR                             0x0
#define S_ZEROFILL                            0x1
#define S_CSTRING_LITERALS                    0x2
#define S_4BYTE_LITERALS                      0x3
#define S_8BYTE_LITERALS                      0x4
#define S_LITERAL_POINTERS                    0x5
#define S_NON_LAZY_SYMBOL_POINTERS            0x6
#define S_LAZY_SYMBOL_POINTERS                0x7
#define S_SYMBOL_STUBS                        0x8
#define S_MOD_INIT_FUNC_POINTERS              0x9
#define S_MOD_TERM_FUNC_POINTERS              0xa
#define S_COALESCED                           0xb
#define S_GB_ZEROFILL                         0xc
#define S_INTERPOSING                         0xd
#define S_16BYTE_LITERALS                     0xe
#define S_DTRACE_DOF                          0xf
#define S_LAZY_DYLIB_SYMBOL_POINTERS          0x10
#define S_THREAD_LOCAL_REGULAR                0x11
#define S_THREAD_LOCAL_ZEROFILL               0x12
#define S_THREAD_LOCAL_VARIABLES              0x13
#define S_THREAD_LOCAL_VARIABLE_POINTERS      0x14
#define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 0x15
#define S_INIT_FUNC_OFFSETS                   0x16

//Mach-O Commands
#define LC_REQ_DYLD              0x80000000
#define LC_SEGMENT               0x1
#define LC_SYMTAB                0x2
#define LC_SYMSEG                0x3
#define LC_THREAD                0x4
#define LC_UNIXTHREAD            0x5
#define LC_LOADFVMLIB            0x6
#define LC_IDFVMLIB              0x7
#define LC_IDENT                 0x8
#define LC_FVMFILE               0x9
#define LC_PREPAGE               0xa
#define LC_DYSYMTAB              0xb
#define LC_LOAD_DYLIB            0xc
#define LC_ID_DYLIB              0xd
#define LC_LOAD_DYLINKER         0xe
#define LC_ID_DYLINKER           0xf
#define LC_PREBOUND_DYLIB        0x10
#define LC_ROUTINES              0x11
#define LC_SUB_FRAMEWORK         0x12
#define LC_SUB_UMBRELLA          0x13
#define LC_SUB_CLIENT            0x14
#define LC_SUB_LIBRARY           0x15
#define LC_TWOLEVEL_HINTS        0x16
#define LC_PREBIND_CKSUM         0x17
#define LC_LOAD_WEAK_DYLIB       (0x18 | LC_REQ_DYLD)
#define LC_SEGMENT_64            0x19
#define LC_ROUTINES_64           0x1a
#define LC_UUID                  0x1b
#define LC_RPATH                 (0x1c | LC_REQ_DYLD)
#define LC_CODE_SIGNATURE        0x1d
#define LC_SEGMENT_SPLIT_INFO    0x1e
#define LC_REEXPORT_DYLIB        (0x1f | LC_REQ_DYLD)
#define LC_LAZY_LOAD_DYLIB       0x20
#define LC_ENCRYPTION_INFO       0x21
#define LC_DYLD_INFO             0x22
#define LC_DYLD_INFO_ONLY        (0x22 | LC_REQ_DYLD)
#define LC_LOAD_UPWARD_DYLIB     (0x23 | LC_REQ_DYLD)
#define LC_VERSION_MIN_MACOSX    0x24
#define LC_VERSION_MIN_IPHONEOS  0x25
#define LC_FUNCTION_STARTS       0x26
#define LC_DYLD_ENVIRONMENT      0x27
#define LC_MAIN                  (0x28 | LC_REQ_DYLD)
#define LC_DATA_IN_CODE          0x29
#define LC_SOURCE_VERSION        0x2a
#define LC_DYLIB_CODE_SIGN_DRS   0x2b
#define _LC_ENCRYPTION_INFO_64    0x2c /* FIXME: warning defined in .../SDKs/MacOSX10.15.sdk/usr/include/mach-o/loader.h */
#define _LC_LINKER_OPTION         0x2d /* FIXME: warning defined in .../SDKs/MacOSX10.15.sdk/usr/include/mach-o/loader.h */
#define _LC_LINKER_OPTIMIZATION_HINT 0x2e /* FIXME: warning defined in .../SDKs/MacOSX10.15.sdk/usr/include/mach-o/loader.h */
#define _LC_VERSION_MIN_TVOS      0x2f /* FIXME: warning defined in .../SDKs/MacOSX10.15.sdk/usr/include/mach-o/loader.h */
#define LC_VERSION_MIN_WATCHOS   0x30
#define LC_NOTE                  0x31
#define LC_BUILD_VERSION         0x32
#define LC_DYLD_EXPORTS_TRIE     (0x33 | LC_REQ_DYLD)
#define LC_DYLD_CHAINED_FIXUPS   (0x34 | LC_REQ_DYLD)
#define LC_FILESET_ENTRY         (0x35 | LC_REQ_DYLD)

//Mach-O File types
#define  MH_OBJECT                   0x1
#define  MH_EXECUTE                  0x2
#define  MH_FVMLIB                   0x3
#define  MH_CORE                     0x4
#define  MH_PRELOAD                  0x5
#define  MH_DYLIB                    0x6
#define  MH_DYLINKER                 0x7
#define  MH_BUNDLE                   0x8
#define  MH_DYLIB_STUB               0x9
#define  MH_DSYM                     0xa
#define  MH_KEXT_BUNDLE              0xb
#define  MH_FILESET                  0xc

#define  MH_NOUNDEFS                 0x1
#define  MH_INCRLINK                 0x2
#define  MH_DYLDLINK                 0x4
#define  MH_BINDATLOAD               0x8
#define  MH_PREBOUND                 0x10
#define  MH_SPLIT_SEGS               0x20
#define  MH_LAZY_INIT                0x40
#define  MH_TWOLEVEL                 0x80
#define  MH_FORCE_FLAT               0x100
#define  MH_NOMULTIDEFS              0x200
#define  MH_NOFIXPREBINDING          0x400
#define  MH_PREBINDABLE              0x800
#define  MH_ALLMODSBOUND             0x1000
#define  MH_SUBSECTIONS_VIA_SYMBOLS  0x2000
#define  MH_CANONICAL                0x4000
#define  MH_WEAK_DEFINES             0x8000
#define  MH_BINDS_TO_WEAK            0x10000
#define  MH_ALLOW_STACK_EXECUTION    0x20000
#define  MH_ROOT_SAFE                0x40000
#define  MH_SETUID_SAFE              0x80000
#define  MH_NO_REEXPORTED_DYLIBS     0x100000
#define  MH_PIE                      0x200000
#define  MH_DEAD_STRIPPABLE_DYLIB    0x400000
#define  MH_HAS_TLV_DESCRIPTORS      0x800000
#define  MH_NO_HEAP_EXECUTION        0x1000000
#define  _MH_APP_EXTENSION_SAFE       0x2000000 /* FIXME: warning defined in .../SDKs/MacOSX10.15.sdk/usr/include/mach-o/loader.h */
#define  _MH_NLIST_OUTOFSYNC_WITH_DYLDINFO 0x04000000u
#define  _MH_SIM_SUPPORT                   0x08000000u
#define  _MH_DYLIB_IN_CACHE                0x80000000u

//Segment Names
#define  SEG_PAGEZERO       "__PAGEZERO"
#define  SEG_TEXT           "__TEXT"
#define  SECT_TEXT          "__text"
#define  SECT_FVMLIB_INIT0  "__fvmlib_init0"
#define  SECT_FVMLIB_INIT1  "__fvmlib_init1"
#define  SEG_DATA           "__DATA"
#define  SECT_DATA          "__data"
#define  SECT_BSS           "__bss"
#define  SECT_COMMON        "__common"
#define  SEG_OBJC           "__OBJC"
#define  SECT_OBJC_SYMBOLS  "__symbol_table"
#define  SECT_OBJC_MODULES  "__module_info"
#define  SECT_OBJC_STRINGS  "__selector_strs"
#define  SECT_OBJC_REFS     "__selector_refs"
#define  SEG_ICON           "__ICON"
#define  SECT_ICON_HEADER   "__header"
#define  SECT_ICON_TIFF     "__tiff"
#define  SEG_LINKEDIT       "__LINKEDIT"
#define  SEG_UNIXSTACK      "__UNIXSTACK"
#define  SEG_IMPORT         "__IMPORT"

/*
 * Symbols with a index into the string table of zero (n_un.n_strx == 0) are
 * defined to have a null, "", name.  Therefore all string indexes to non null
 * names must not have a zero string index.  This is bit historical information
 * that has never been well documented.
 */

/*
 * The n_type field really contains four fields:
 *	unsigned char N_STAB:3,
 *		      N_PEXT:1,
 *		      N_TYPE:3,
 *		      N_EXT:1;
 * which are used via the following masks.
 */
#define	N_STAB	0xe0  /* if any of these bits set, a symbolic debugging entry */
#define	N_PEXT	0x10  /* private external symbol bit */
#define	N_TYPE	0x0e  /* mask for the type bits */
#define	N_EXT	0x01  /* external symbol bit, set for external symbols */

/*
 * Only symbolic debugging entries have some of the N_STAB bits set and if any
 * of these bits are set then it is a symbolic debugging entry (a stab).  In
 * which case then the values of the n_type field (the entire field) are given
 * in <mach-o/stab.h>
 */

/*
 * Values for N_TYPE bits of the n_type field.
 */
#define	N_UNDF	0x0		/* undefined, n_sect == NO_SECT */
#define	N_ABS	0x2		/* absolute, n_sect == NO_SECT */
#define	N_SECT	0xe		/* defined in section number n_sect */
#define	N_PBUD	0xc		/* prebound undefined (defined in a dylib) */
#define N_INDR	0xa		/* indirect */

/* 
 * If the type is N_INDR then the symbol is defined to be the same as another
 * symbol.  In this case the n_value field is an index into the string table
 * of the other symbol's name.  When the other symbol is defined then they both
 * take on the defined type and value.
 */

/*
 * If the type is N_SECT then the n_sect field contains an ordinal of the
 * section the symbol is defined in.  The sections are numbered from 1 and 
 * refer to sections in order they appear in the load commands for the file
 * they are in.  This means the same ordinal may very well refer to different
 * sections in different files.
 *
 * The n_value field for all symbol table entries (including N_STAB's) gets
 * updated by the link editor based on the value of it's n_sect field and where
 * the section n_sect references gets relocated.  If the value of the n_sect 
 * field is NO_SECT then it's n_value field is not changed by the link editor.
 */
#define	NO_SECT		0	/* symbol is not in any section */
#define MAX_SECT	255	/* 1 thru 255 inclusive */

/*
 * The bit 0x0020 of the n_desc field is used for two non-overlapping purposes
 * and has two different symbolic names, N_NO_DEAD_STRIP and N_DESC_DISCARDED.
 */

/*
 * The N_NO_DEAD_STRIP bit of the n_desc field only ever appears in a 
 * relocatable .o file (MH_OBJECT filetype). And is used to indicate to the
 * static link editor it is never to dead strip the symbol.
 */
#define N_NO_DEAD_STRIP 0x0020 /* symbol is not to be dead stripped */

/*
 * The N_DESC_DISCARDED bit of the n_desc field never appears in linked image.
 * But is used in very rare cases by the dynamic link editor to mark an in
 * memory symbol as discared and longer used for linking.
 */
#define N_DESC_DISCARDED 0x0020	/* symbol is discarded */

/*
 * The N_WEAK_REF bit of the n_desc field indicates to the dynamic linker that
 * the undefined symbol is allowed to be missing and is to have the address of
 * zero when missing.
 */
#define N_WEAK_REF	0x0040 /* symbol is weak referenced */

/*
 * The N_WEAK_DEF bit of the n_desc field indicates to the static and dynamic
 * linkers that the symbol definition is weak, allowing a non-weak symbol to
 * also be used which causes the weak definition to be discared.  Currently this
 * is only supported for symbols in coalesed sections.
 */
#define N_WEAK_DEF	0x0080 /* coalesed symbol is a weak definition */

/*
 * The N_REF_TO_WEAK bit of the n_desc field indicates to the dynamic linker
 * that the undefined symbol should be resolved using flat namespace searching.
 */
#define	N_REF_TO_WEAK	0x0080 /* reference to a weak symbol */

/*
 * The N_ARM_THUMB_DEF bit of the n_desc field indicates that the symbol is
 * a defintion of a Thumb function.
 */
#define N_ARM_THUMB_DEF	0x0008 /* symbol is a Thumb function (ARM) */

/*
 * The N_SYMBOL_RESOLVER bit of the n_desc field indicates that the
 * that the function is actually a resolver function and should
 * be called to get the address of the real function to use.
 * This bit is only available in .o files (MH_OBJECT filetype)
 */
#define N_SYMBOL_RESOLVER  0x0100 

/*
 * The N_ALT_ENTRY bit of the n_desc field indicates that the
 * symbol is pinned to the previous content.
 */
#define N_ALT_ENTRY 0x0200

/*
 * The N_COLD_FUNC bit of the n_desc field indicates that the symbol is used
 * infrequently and the linker should order it towards the end of the section.
 */
#define N_COLD_FUNC 0x0400

/*
 * An indirect symbol table entry is simply a 32bit index into the symbol table
 * to the symbol that the pointer or stub is referring to.  Unless it is for a
 * non-lazy symbol pointer section for a defined symbol which strip(1) as
 * removed.  In which case it has the value INDIRECT_SYMBOL_LOCAL.  If the
 * symbol was also absolute INDIRECT_SYMBOL_ABS is or'ed with that.
 */
#define INDIRECT_SYMBOL_ABS   0x40000000
#define INDIRECT_SYMBOL_LOCAL 0x80000000

#define SECTION_TYPE		 0x000000ff	/* 256 section types */
#define SECTION_ATTRIBUTES	 0xffffff00	/*  24 section attributes */

#define BINARYNINJA_MANUAL_RELOCATION ((uint64_t)-2)

enum MachoRelocationType
{
	GENERIC_RELOC_VANILLA = 0,
	GENERIC_RELOC_PAIR = 1,
	GENERIC_RELOC_SECTDIFF = 2,
	GENERIC_RELOC_PB_LA_PTR = 3,
	GENERIC_RELOC_LOCAL_SECTDIFF = 4,
	GENERIC_RELOC_TLV = 5
};


namespace BinaryNinja
{
	class MachoFormatException: public std::exception
	{
		std::string m_message;

	public:
		MachoFormatException(const std::string& msg = "invalid format"): m_message(msg) {}
		virtual const char* what() const NOEXCEPT { return m_message.c_str(); }
	};

	struct FatHeader {
		uint32_t magic;
		uint32_t nfat_arch;
	};

	struct FatArch32 {
		cpu_type_t cputype;
		cpu_subtype_t cpusubtype;
		uint32_t offset;
		uint32_t size;
		uint32_t align;
	};

	struct FatArch64 {
		cpu_type_t cputype;
		cpu_subtype_t cpusubtype;
		uint64_t offset;
		uint64_t size;
		uint32_t align;
		uint32_t reserved;
	};

	struct mach_header {
		uint32_t	magic;
		cpu_type_t	cputype;
		cpu_subtype_t	cpusubtype;
		uint32_t	filetype;
		uint32_t	ncmds;
		uint32_t	sizeofcmds;
		uint32_t	flags;
	};

	struct mach_header_64 {
		uint32_t	magic;
		cpu_type_t	cputype;
		cpu_subtype_t	cpusubtype;
		uint32_t	filetype;
		uint32_t	ncmds;
		uint32_t	sizeofcmds;
		uint32_t	flags;
		uint32_t	reserved;
	};

	struct load_command {
		uint32_t	cmd;
		uint32_t	cmdsize;
	};

	struct segment_command {
		uint32_t	cmd;
		uint32_t	cmdsize;
		char		segname[16];
		uint32_t	vmaddr;
		uint32_t	vmsize;
		uint32_t	fileoff;
		uint32_t	filesize;
		vm_prot_t	maxprot;
		vm_prot_t	initprot;
		uint32_t	nsects;
		uint32_t	flags;
	};

	struct section { 				// for 32-bit architectures
		char		sectname[16];	// name of this section
		char		segname[16];	// segment this section goes in
		uint32_t	addr;			// memory address of this section
		uint32_t	size;			// size in bytes of this section
		uint32_t	offset;			// file offset of this section
		uint32_t	align;			// section alignment (power of 2)
		uint32_t	reloff;			// file offset of relocation entries
		uint32_t	nreloc;			// number of relocation entries
		uint32_t	flags;			// flags (section type and attributes)
		uint32_t	reserved1;		// reserved (for offset or index)
		uint32_t	reserved2;		// reserved (for count or sizeof)
	};

	struct section_64 { 			// for 64-bit architectures
		char		sectname[16];	// name of this section
		char		segname[16];	// segment this section goes in
		uint64_t	addr;			// memory address of this section
		uint64_t	size;			// size in bytes of this section
		uint32_t	offset;			// file offset of this section
		uint32_t	align;			// section alignment (power of 2)
		uint32_t	reloff;			// file offset of relocation entries
		uint32_t	nreloc;			// number of relocation entries
		uint32_t	flags;			// flags (section type and attributes)
		uint32_t	reserved1;		// reserved (for offset or index)
		uint32_t	reserved2;		// reserved (for count or sizeof)
		uint32_t	reserved3;		// reserved
	};

	struct segment_command_64 {
		uint32_t	cmd;
		uint32_t	cmdsize;
		char		segname[16];
		uint64_t	vmaddr;
		uint64_t	vmsize;
		uint64_t	fileoff;
		uint64_t	filesize;
		vm_prot_t	maxprot;
		vm_prot_t	initprot;
		uint32_t	nsects;
		uint32_t	flags;
	};

	struct uuid_command {
		uint32_t	cmd;
		uint32_t	cmdsize;
		char		uuid[16];
	};

	struct fvmlib_command {
		uint32_t	cmd;
		uint32_t	cmdsize;
		char		segname[16];
		uint32_t	minor_version;
		uint32_t	header_addr;
	};

	struct dylib {
		uint32_t	name;
		uint32_t	timestamp;
		uint32_t	current_version;
		uint32_t	compatibility_version;
	};

	struct dylib_command {
		uint32_t		cmd;
		uint32_t		cmdsize;
		struct dylib	dylib;
	};

	struct sub_framework_command {
		uint32_t	cmd;		// LC_SUB_FRAMEWORK
		uint32_t	cmdsize;	// includes umbrella string
		uint32_t	umbrella;	// the umbrella framework name
	};

	struct sub_client_command {
		uint32_t	cmd;		// LC_SUB_CLIENT
		uint32_t	cmdsize;	// includes client string
		uint32_t	client;		// offset to the string
	};

	struct sub_umbrella_command {
		uint32_t	cmd;		// LC_SUB_UMBRELLA
		uint32_t	cmdsize;	// includes sub_umbrella string
		uint32_t	sub_umbrella;	// the sub_umbrella framework name
	};

	struct sub_library_command {
		uint32_t	cmd;		// LC_SUB_LIBRARY
		uint32_t	cmdsize;	// includes sub_library string
		uint32_t	sub_library;	// the sub_library name
	};

	struct prebound_dylib_command {
		uint32_t	cmd;			// LC_PREBOUND_DYLIB
		uint32_t	cmdsize;		// includes strings
		uint32_t	name;			// library's path name
		uint32_t	nmodules;		// number of modules in library
		uint32_t	linked_modules;	// bit vector of linked modules
	};

	struct dylinker_command {
		uint32_t	cmd;		// LC_ID_DYLINKER or LC_LOAD_DYLINKER
		uint32_t	cmdsize;	// includes pathname string
		uint32_t	name;		// dynamic linker's path name
	};

	struct x86_thread_state64 {
		uint64_t	rax;
		uint64_t	rbx;
		uint64_t	rcx;
		uint64_t	rdx;
		uint64_t	rdi;
		uint64_t	rsi;
		uint64_t	rbp;
		uint64_t	rsp;
		uint64_t	r8;
		uint64_t	r9;
		uint64_t	r10;
		uint64_t	r11;
		uint64_t	r12;
		uint64_t	r13;
		uint64_t	r14;
		uint64_t	r15;
		uint64_t	rip;
		uint64_t	rflags;
		uint64_t	cs;
		uint64_t	fs;
		uint64_t	gs;
	};

	struct x86_thread_state32 {
		uint32_t	eax;
		uint32_t	ebx;
		uint32_t	ecx;
		uint32_t	edx;
		uint32_t	edi;
		uint32_t	esi;
		uint32_t	ebp;
		uint32_t	esp;
		uint32_t	ss;
		uint32_t	eflags;
		uint32_t	eip;
		uint32_t	cs;
		uint32_t	ds;
		uint32_t	es;
		uint32_t	fs;
		uint32_t	gs;
	};

	struct armv7_thread_state {
		uint32_t	r0;
		uint32_t	r1;
		uint32_t	r2;
		uint32_t	r3;
		uint32_t	r4;
		uint32_t	r5;
		uint32_t	r6;
		uint32_t	r7;
		uint32_t	r8;
		uint32_t	r9;
		uint32_t	r10;
		uint32_t	r11;
		uint32_t	r12;
		uint32_t	r13;
		uint32_t	r14; //SP
		uint32_t	r15; //PC
	};

	struct arm_thread_state64 {
		uint64_t	x[29];		// GPR x0-x28
		uint64_t	fp;			// x29
		uint64_t	lr;			// x30
		uint64_t	sp;			// x31
		uint64_t	pc;			// Program Counter
		uint32_t	cpsr;		// Current program status register
	};

	struct ppc_thread_state {
		uint32_t	srr0; //Machine state register (PC)
		uint32_t	srr1;
		uint32_t	r0;
		uint32_t	r1; //Stack pointer
		uint32_t	r2;
		uint32_t	r3;
		uint32_t	r4;
		uint32_t	r5;
		uint32_t	r6;
		uint32_t	r7;
		uint32_t	r8;
		uint32_t	r9;
		uint32_t	r10;
		uint32_t	r11;
		uint32_t	r12;
		uint32_t	r13;
		uint32_t	r14;
		uint32_t	r15;
		uint32_t	r16;
		uint32_t	r17;
		uint32_t	r18;
		uint32_t	r19;
		uint32_t	r20;
		uint32_t	r21;
		uint32_t	r22;
		uint32_t	r23;
		uint32_t	r24;
		uint32_t	r25;
		uint32_t	r26;
		uint32_t	r27;
		uint32_t	r28;
		uint32_t	r29;
		uint32_t	r30;
		uint32_t	r31;
		uint32_t	cr;
		uint32_t	xer;
		uint32_t	lr;
		uint32_t	ctr;
		uint32_t	mq;
		uint32_t	vrsave;
	};

	#pragma pack(push, 4)
	struct ppc_thread_state64 {
		uint64_t	srr0;  //Machine state register (PC)
		uint64_t	srr1;
		uint64_t	r0; //Stack pointer
		uint64_t	r1;
		uint64_t	r2;
		uint64_t	r3;
		uint64_t	r4;
		uint64_t	r5;
		uint64_t	r6;
		uint64_t	r7;
		uint64_t	r8;
		uint64_t	r9;
		uint64_t	r10;
		uint64_t	r11;
		uint64_t	r12;
		uint64_t	r13;
		uint64_t	r14;
		uint64_t	r15;
		uint64_t	r16;
		uint64_t	r17;
		uint64_t	r18;
		uint64_t	r19;
		uint64_t	r20;
		uint64_t	r21;
		uint64_t	r22;
		uint64_t	r23;
		uint64_t	r24;
		uint64_t	r25;
		uint64_t	r26;
		uint64_t	r27;
		uint64_t	r28;
		uint64_t	r29;
		uint64_t	r30;
		uint64_t	r31;
		uint32_t	cr;     // Condition register
		uint64_t	xer;    // User's integer exception register
		uint64_t	lr;     // Link register
		uint64_t	ctr;    // Count register
		uint32_t	vrsave; // Vector Save Register
	};
	#pragma pack(pop)

	struct thread_command {
		uint32_t	cmd;		// LC_THREAD or  LC_UNIXTHREAD
		uint32_t	cmdsize;	// total size of this command
		uint32_t	flavor;	// flavor of thread state
		uint32_t	count;		//count of longs in thread state
		union {
			x86_thread_state64 statex64;
			x86_thread_state32 statex86;
			armv7_thread_state statearmv7;
			arm_thread_state64 stateaarch64;
			ppc_thread_state   stateppc;
			ppc_thread_state64 stateppc64;
		};
	};

	struct linkedit_data_command {
		uint32_t cmd;
		uint32_t cmdsize;
		uint32_t dataoff;
		uint32_t datasize;
	};


	enum MachOArchitecture {
		MachOABIMask	= 0xff000000,
		MachOABI64	= 0x01000000, // 64 bit ABI
		MachOABI6432	= 0x02000000, // "ABI for 64-bit hardware with 32-bit types; LP32"

		// Constants for the cputype field.
		MachOx86	= 7,
		MachOx64	= MachOx86 | MachOABI64,
		MachOArm	= 0xc,
		MachOAarch64	= MachOABI64 | MachOArm,
		MachOAarch6432	= MachOABI6432 | MachOArm,
		MachOSPARC	= 0xe,
		MachOPPC	= 0x12,
		MachOPPC64	= MachOABI64 | MachOPPC,
	};

	enum RebaseType {
		RebaseTypeInvalid = 0,
		RebaseTypePointer = 1,
		RebaseTypeTextAbsolute32 = 2,
		RebaseTypeTextPCRel32 = 3
	};

	enum RebaseOpcode {
		RebaseOpcodeMask                            = 0xF0u, // REBASE_OPCODE_MASK
		RebaseImmediateMask                         = 0x0Fu, // REBASE_IMMEDIATE_MASK
		RebaseOpcodeDone                            = 0x00u, // REBASE_OPCODE_DONE
		RebaseOpcodeSetTypeImmediate                = 0x10u, // REBASE_OPCODE_SET_TYPE_IMM
		RebaseOpcodeSetSegmentAndOffsetUleb         = 0x20u, // REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
		RebaseOpcodeAddAddressUleb                  = 0x30u, // REBASE_OPCODE_ADD_ADDR_ULEB
		RebaseOpcodeAddAddressImmediateScaled       = 0x40u, // REBASE_OPCODE_ADD_ADDR_IMM_SCALED
		RebaseOpcodeDoRebaseImmediateTimes          = 0x50u, // REBASE_OPCODE_DO_REBASE_IMM_TIMES
		RebaseOpcodeDoRebaseUlebTimes               = 0x60u, // REBASE_OPCODE_DO_REBASE_ULEB_TIMES
		RebaseOpcodeDoRebaseAddAddressUleb          = 0x70u, // REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
		RebaseOpcodeDoRebaseUlebTimesSkippingUleb   = 0x80u, // REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
	};

	enum BindSpecial {
		BindSpecialDylibSelf = 0, // BIND_SPECIAL_DYLIB_SELF
		BindSpecialDylibMainExecutable = -1, // BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
		BindSpecialDylibFlatLookup = -2, // BIND_SPECIAL_DYLIB_FLAT_LOOKUP
		BindSpecialDylibWeakLookup = -3 // BIND_SPECIAL_DYLIB_WEAK_LOOKUP
	};

	enum BindOpcode {
		BindOpcodeMask                            = 0xF0u, // BIND_OPCODE_MASK
		BindImmediateMask                         = 0x0Fu, // BIND_IMMEDIATE_MASK
		BindOpcodeDone                            = 0x00u, // BIND_OPCODE_DONE
		BindOpcodeSetDylibOrdinalImmediate        = 0x10u, // BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
		BindOpcodeSetDylibOrdinalULEB             = 0x20u, // BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
		BindOpcodeSetDylibSpecialImmediate        = 0x30u, // BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
		BindOpcodeSetSymbolTrailingFlagsImmediate = 0x40u, // BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
		BindOpcodeSetTypeImmediate                = 0x50u, // BIND_OPCODE_SET_TYPE_IMM
		BindOpcodeSetAddendSLEB                   = 0x60u, // BIND_OPCODE_SET_ADDEND_SLEB
		BindOpcodeSetSegmentAndOffsetULEB         = 0x70u, // BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
		BindOpcodeAddAddressULEB                  = 0x80u, // BIND_OPCODE_ADD_ADDR_ULEB
		BindOpcodeDoBind                          = 0x90u, // BIND_OPCODE_DO_BIND
		BindOpcodeDoBindAddAddressULEB            = 0xA0u, // BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
		BindOpcodeDoBindAddAddressImmediateScaled = 0xB0u, // BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
		BindOpcodeDoBindULEBTimesSkippingULEB     = 0xC0u, // BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
	};

	enum X86ThreadFlavor {
		X86_THREAD_STATE32      = 0x1,
		X86_FLOAT_STATE32       = 0x2,
		X86_EXCEPTION_STATE32   = 0x3,
		X86_THREAD_STATE64      = 0x4,
		X86_FLOAT_STATE64       = 0x5,
		X86_EXCEPTION_STATE64   = 0x6,
		X86_THREAD_STATE        = 0x7,
		X86_FLOAT_STATE         = 0x8,
		X86_EXCEPTION_STATE     = 0x9,
		X86_DEBUG_STATE32       = 0xA,
		X86_DEBUG_STATE64       = 0xB,
		X86_DEBUG_STATE         = 0xC,
		_THREAD_STATE_NONE      = 0xD
	};

	enum PPCThreadFlavor {
		PPC_THREAD_STATE        = 0x1,
		PPC_FLOAT_STATE         = 0x2,
		PPC_EXCEPTION_STATE     = 0x3,
		PPC_VECTOR_STATE        = 0x4,
		PPC_THREAD_STATE64      = 0x5,
		PPC_EXCEPTION_STATE64   = 0x6
	};

	enum ARMThreadFlavor
	{
		_ARM_THREAD_STATE      = 1,
		_ARM_VFP_STATE         = 2,
		_ARM_EXCEPTION_STATE   = 3,
		_ARM_DEBUG_STATE       = 4, /* pre-armv8 */
		_ARM_THREAD_STATE64    = 6,
		_ARM_EXCEPTION_STATE64 = 7
	};

	struct routines_command { // for 32-bit architectures
		uint32_t	cmd;			// LC_ROUTINES
		uint32_t	cmdsize;		// total size of this command
		uint32_t	init_address;	// address of initialization routine
		uint32_t	init_module;	// index into the module table that the init routine is defined in
		uint32_t	reserved1;
		uint32_t	reserved2;
		uint32_t	reserved3;
		uint32_t	reserved4;
		uint32_t	reserved5;
		uint32_t	reserved6;
	};

	struct routines_command_64 { 	// for 64-bit architectures
		uint32_t	cmd;			// LC_ROUTINES_64
		uint32_t	cmdsize;		// total size of this command
		uint64_t	init_address;	// address of initialization routine
		uint64_t	init_module;	// index into the module table that the init routine is defined in
		uint64_t	reserved1;
		uint64_t	reserved2;
		uint64_t	reserved3;
		uint64_t	reserved4;
		uint64_t	reserved5;
		uint64_t	reserved6;
	};

	struct symtab_command {
		uint32_t	cmd;		// LC_SYMTAB
		uint32_t	cmdsize;	// sizeof(struct symtab_command)
		uint32_t	symoff;		// symbol table offset
		uint32_t	nsyms;		// number of symbol table entries
		uint32_t	stroff;		// string table offset
		uint32_t	strsize;	// string table size in bytes
	};

	// Lots of good information on how to use dysymtab for relocations
	// https://opensource.apple.com/source/cctools/cctools-795/include/mach-o/loader.h
	struct dysymtab_command {
		uint32_t cmd;			// LC_DYSYMTAB
		uint32_t cmdsize;		// sizeof(struct dysymtab_command)
		uint32_t ilocalsym;		// index to local symbols
		uint32_t nlocalsym;		// number of local symbols
		uint32_t iextdefsym;	// index to externally defined symbols
		uint32_t nextdefsym;	// number of externally defined symbols
		uint32_t iundefsym;		// index to undefined symbols
		uint32_t nundefsym;		// number of undefined symbols
		uint32_t tocoff;		// file offset to table of contents
		uint32_t ntoc;			// number of entries in table of contents
		uint32_t modtaboff;		// file offset to module table
		uint32_t nmodtab;		// number of module table entries
		uint32_t extrefsymoff;	// offset to referenced symbol table
		uint32_t nextrefsyms;	// number of referenced symbol table entries
		uint32_t indirectsymoff; // file offset to the indirect symbol table
		uint32_t nindirectsyms;  // number of indirect symbol table entries
		uint32_t extreloff;		// offset to external relocation entries
		uint32_t nextrel;		// number of external relocation entries
		uint32_t locreloff;		// offset to local relocation entries
		uint32_t nlocrel;		// number of local relocation entries
	};

	struct twolevel_hints_command {
		uint32_t cmd;		// LC_TWOLEVEL_HINTS
		uint32_t cmdsize;	// sizeof(struct twolevel_hints_command)
		uint32_t offset;	// offset to the hint table
		uint32_t nhints;	// number of hints in the hint table
	};

	struct dyld_info_command {
		uint32_t   cmd;				// LC_DYLD_INFO or LC_DYLD_INFO_ONLY
		uint32_t   cmdsize;			// sizeof(struct dyld_info_command)
		uint32_t   rebase_off;		// file offset to rebase info
		uint32_t   rebase_size;		// size of rebase info
		uint32_t   bind_off;		// file offset to binding info
		uint32_t   bind_size;		// size of binding info
		uint32_t   weak_bind_off;	// file offset to weak binding info
		uint32_t   weak_bind_size;  // size of weak binding info
		uint32_t   lazy_bind_off;	// file offset to lazy binding info
		uint32_t   lazy_bind_size;  // size of lazy binding infs
		uint32_t   export_off;		// file offset to lazy binding info
		uint32_t   export_size;		// size of lazy binding infs
	};

	struct function_starts_command {
		uint32_t cmd;		//LC_FUNCTION_STARTS
		uint32_t cmdsize;   //sizeof(struct function_starts_command)
		uint32_t funcoff;   //offset to function starts list
		uint32_t funcsize;  //sizeof function starts list
	};

	enum MachoPlatform {
		MACHO_PLATFORM_MACOS    = 1,
		MACHO_PLATFORM_IOS      = 2,
		MACHO_PLATFORM_TVOS     = 3,
		MACHO_PLATFORM_WATCHOS  = 4,
		MACHO_PLATFORM_BRIDGEOS = 5
	};

	enum MachoBuildTool {
		MACHO_TOOL_CLANG  = 1,
		MACHO_TOOL_SWIFT  = 2,
		MACHO_TOOL_LD     = 3
	};

	struct build_tool_version {
		uint32_t tool;
		uint32_t version;
	};

	struct build_version_command {
		uint32_t cmd;       // LC_BUILD_VERSION
		uint32_t cmdsize;   // sizeof(build_version_command) + (ntools * sizeof(build_tool_version)
		uint32_t platform;  // MachoPlatform
		uint32_t minos;     // X.Y.Z is encoded in nibbles xxxx.yy.zz
		uint32_t sdk;       // X.Y.Z is encoded in nibbles xxxx.yy.zz
		uint32_t ntools;    // number build_tool_version entries
	};

#pragma pack(push, 1)
	struct nlist {
		int32_t n_strx;
		uint8_t n_type;
		uint8_t n_sect;
		int16_t n_desc;
		uint32_t n_value;
	};

	struct nlist_64 {
		uint32_t n_strx;
		uint8_t n_type;
		uint8_t n_sect;
		uint16_t n_desc;
		uint64_t n_value;
	};
#pragma pack(pop)

#define	R_ABS 0
	struct relocation_info
	{
		int32_t r_address;
		uint32_t r_symbolnum:24;
		uint32_t r_pcrel:1;
		uint32_t r_length:2;
		uint32_t r_extern:1;
		uint32_t r_type:4;
	};
#define R_SCATTERED 0x80000000
	struct scattered_relocation_info_be_64 {
		uint32_t r_scattered:1; // 1=scattered, 0=non-scattered (see above)
		uint32_t r_pcrel:1;     // was relocated pc relative already
		uint32_t r_length:2;    // 0=byte, 1=word, 2=long
		uint32_t r_type:4;      // if not 0, machine specific relocation type
		uint32_t r_address:24;  // offset in the section to what is being relocated
		int64_t r_value;        // the value the item to be relocated is refering to (without any offset added)
	};
	struct scattered_relocation_info_le_64 {
		uint32_t r_address:24;  // offset in the section to what is being relocated
		uint32_t r_type:4;      // if not 0, machine specific relocation type
		uint32_t r_length:2;    // 0=byte, 1=word, 2=long
		uint32_t r_pcrel:1;     // was relocated pc relative already
		uint32_t r_scattered:1; // 1=scattered, 0=non-scattered (see above)
		int64_t r_value;        // the value the item to be relocated is refering to (without any offset added)
	};
	struct scattered_relocation_info_be {
		uint32_t r_scattered:1; // 1=scattered, 0=non-scattered (see above)
		uint32_t r_pcrel:1;     // was relocated pc relative already
		uint32_t r_length:2;    // 0=byte, 1=word, 2=long
		uint32_t r_type:4;      // if not 0, machine specific relocation type
		uint32_t r_address:24;  // offset in the section to what is being relocated
		int32_t r_value;        // the value the item to be relocated is refering to (without any offset added)
	};
	struct scattered_relocation_info_le {
		uint32_t r_address:24;  // offset in the section to what is being relocated
		uint32_t r_type:4;      // if not 0, machine specific relocation type
		uint32_t r_length:2;    // 0=byte, 1=word, 2=long
		uint32_t r_pcrel:1;     // was relocated pc relative already
		uint32_t r_scattered:1; // 1=scattered, 0=non-scattered (see above)
		int32_t r_value;        // the value the item to be relocated is refering to (without any offset added)
	};

	enum reloc_type_generic
	{
		GENERIC_RELOC_VANILLA,   // generic relocation as discribed above
		GENERIC_RELOC_PAIR,      // Only follows a GENRIC_RELOC_SECTDIFF
		GENERIC_RELOC_SECTDIFF,
		GENERIC_RELOC_PB_LA_PTR  // prebound lazy pointer
	};

	struct dyld_chained_fixups_header
	{
		uint32_t    fixups_version;    // 0
		uint32_t    starts_offset;     // offset of dyld_chained_starts_in_image in chain_data
		uint32_t    imports_offset;    // offset of imports table in chain_data
		uint32_t    symbols_offset;    // offset of symbol strings in chain_data
		uint32_t    imports_count;     // number of imported symbol names
		uint32_t    imports_format;    // DYLD_CHAINED_IMPORT*
		uint32_t    symbols_format;    // 0 => uncompressed, 1 => zlib compressed
	};

	// This struct is embedded in LC_DYLD_CHAINED_FIXUPS payload
	struct dyld_chained_starts_in_image
	{
		uint32_t    seg_count;
		uint32_t    seg_info_offset[1];  // each entry is offset into this struct for that segment
		// followed by pool of dyld_chain_starts_in_segment data
	};

	// This struct is embedded in dyld_chain_starts_in_image
	// and passed down to the kernel for page-in linking
	struct dyld_chained_starts_in_segment
	{
		uint32_t    size;               // size of this (amount kernel needs to copy)
		uint16_t    page_size;          // 0x1000 or 0x4000
		uint16_t    pointer_format;     // DYLD_CHAINED_PTR_*
		uint64_t    segment_offset;     // offset in memory to start of segment
		uint32_t    max_valid_pointer;  // for 32-bit OS, any value beyond this is not a pointer
		uint16_t    page_count;         // how many pages are in array
		uint16_t    page_start[1];      // each entry is offset in each page of first element in chain
										// or DYLD_CHAINED_PTR_START_NONE if no fixups on page

		// uint16_t    chain_starts[1];  // some 32-bit formats may require multiple starts per page.
										 // for those, if high bit is set in page_starts[], then it
										 // is index into chain_starts[] which is a list of starts
										 // the last of which has the high bit set
	};

	enum {
		DYLD_CHAINED_PTR_START_NONE   = 0xFFFF, // used in page_start[] to denote a page with no fixups
		DYLD_CHAINED_PTR_START_MULTI  = 0x8000, // used in page_start[] to denote a page which has multiple starts
		DYLD_CHAINED_PTR_START_LAST   = 0x8000, // used in chain_starts[] to denote last start in list for page
	};

	// This struct is embedded in __TEXT,__chain_starts section in firmware
	struct dyld_chained_starts_offsets
	{
		uint32_t    pointer_format;     // DYLD_CHAINED_PTR_32_FIRMWARE
		uint32_t    starts_count;       // number of starts in array
		uint32_t    chain_starts[1];    // array chain start offsets
	};

	// values for dyld_chained_starts_in_segment.pointer_format
	enum {
		DYLD_CHAINED_PTR_ARM64E                 =  1,    // stride 8, unauth target is vmaddr
		DYLD_CHAINED_PTR_64                     =  2,    // target is vmaddr
		DYLD_CHAINED_PTR_32                     =  3,
		DYLD_CHAINED_PTR_32_CACHE               =  4,
		DYLD_CHAINED_PTR_32_FIRMWARE            =  5,
		DYLD_CHAINED_PTR_64_OFFSET              =  6,    // target is vm offset
		DYLD_CHAINED_PTR_ARM64E_OFFSET          =  7,    // old name
		DYLD_CHAINED_PTR_ARM64E_KERNEL          =  7,    // stride 4, unauth target is vm offset
		DYLD_CHAINED_PTR_64_KERNEL_CACHE        =  8,
		DYLD_CHAINED_PTR_ARM64E_USERLAND        =  9,    // stride 8, unauth target is vm offset
		DYLD_CHAINED_PTR_ARM64E_FIRMWARE        = 10,    // stride 4, unauth target is vmaddr
		DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE    = 11,    // stride 1, x86_64 kernel caches
		DYLD_CHAINED_PTR_ARM64E_USERLAND24      = 12,    // stride 8, unauth target is vm offset, 24-bit bind
		DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE    = 13,    // stride 8, regular/auth targets both vm offsets.  Only A keys supported
		DYLD_CHAINED_PTR_ARM64E_SEGMENTED       = 14,    // stride 4, rebase offsets use segIndex and segOffset
	};

	// DYLD_CHAINED_PTR_ARM64E
	struct dyld_chained_ptr_arm64e_rebase
	{
		uint64_t    target   : 43,
			high8    :  8,
			next     : 11,    // 4 or 8-byte stide
			bind     :  1,    // == 0
			auth     :  1;    // == 0
	};

	// DYLD_CHAINED_PTR_ARM64E
	struct dyld_chained_ptr_arm64e_bind
	{
		uint64_t    ordinal   : 16,
			zero      : 16,
			addend    : 19,    // +/-256K
			next      : 11,    // 4 or 8-byte stide
			bind      :  1,    // == 1
			auth      :  1;    // == 0
	};

	// DYLD_CHAINED_PTR_ARM64E
	struct dyld_chained_ptr_arm64e_auth_rebase
	{
		uint64_t    target    : 32,   // runtimeOffset
			diversity : 16,
			addrDiv   :  1,
			key       :  2,
			next      : 11,    // 4 or 8-byte stide
			bind      :  1,    // == 0
			auth      :  1;    // == 1
	};

	// DYLD_CHAINED_PTR_ARM64E
	struct dyld_chained_ptr_arm64e_auth_bind
	{
		uint64_t    ordinal   : 16,
			zero      : 16,
			diversity : 16,
			addrDiv   :  1,
			key       :  2,
			next      : 11,    // 4 or 8-byte stide
			bind      :  1,    // == 1
			auth      :  1;    // == 1
	};

	// DYLD_CHAINED_PTR_64/DYLD_CHAINED_PTR_64_OFFSET
	struct dyld_chained_ptr_64_rebase
	{
		uint64_t    target    : 36,    // 64GB max image size (DYLD_CHAINED_PTR_64 => vmAddr, DYLD_CHAINED_PTR_64_OFFSET => runtimeOffset)
			high8     :  8,    // top 8 bits set to this (DYLD_CHAINED_PTR_64 => after slide added, DYLD_CHAINED_PTR_64_OFFSET => before slide added)
			reserved  :  7,    // all zeros
			next      : 12,    // 4-byte stride
			bind      :  1;    // == 0
	};


	// DYLD_CHAINED_PTR_ARM64E_USERLAND24
	struct dyld_chained_ptr_arm64e_bind24
	{
		uint64_t    ordinal   : 24,
			zero      :  8,
			addend    : 19,    // +/-256K
			next      : 11,    // 8-byte stide
			bind      :  1,    // == 1
			auth      :  1;    // == 0
	};

	// DYLD_CHAINED_PTR_ARM64E_USERLAND24
	struct dyld_chained_ptr_arm64e_auth_bind24
	{
		uint64_t    ordinal   : 24,
			zero      :  8,
			diversity : 16,
			addrDiv   :  1,
			key       :  2,
			next      : 11,    // 8-byte stide
			bind      :  1,    // == 1
			auth      :  1;    // == 1
	};


	// DYLD_CHAINED_PTR_64
	struct dyld_chained_ptr_64_bind
	{
		uint64_t    ordinal   : 24,
			addend    :  8,   // 0 thru 255
			reserved  : 19,   // all zeros
			next      : 12,   // 4-byte stride
			bind      :  1;   // == 1
	};

	// DYLD_CHAINED_PTR_64_KERNEL_CACHE, DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE
	struct dyld_chained_ptr_64_kernel_cache_rebase
	{
		uint64_t    target     : 30,   // basePointers[cacheLevel] + target
			cacheLevel :  2,   // what level of cache to bind to (indexes a mach_header array)
			diversity  : 16,
			addrDiv    :  1,
			key        :  2,
			next       : 12,    // 1 or 4-byte stide
			isAuth     :  1;    // 0 -> not authenticated.  1 -> authenticated
	};

	// DYLD_CHAINED_PTR_32
	// Note: for DYLD_CHAINED_PTR_32 some non-pointer values are co-opted into the chain
	// as out of range rebases.  If an entry in the chain is > max_valid_pointer, then it
	// is not a pointer.  To restore the value, subtract off the bias, which is
	// (64MB+max_valid_pointer)/2.
	struct dyld_chained_ptr_32_rebase
	{
		uint32_t    target    : 26,   // vmaddr, 64MB max image size
			next      :  5,   // 4-byte stride
			bind      :  1;   // == 0
	};

	// DYLD_CHAINED_PTR_32
	struct dyld_chained_ptr_32_bind
	{
		uint32_t    ordinal   : 20,
			addend    :  6,   // 0 thru 63
			next      :  5,   // 4-byte stride
			bind      :  1;   // == 1
	};

	// DYLD_CHAINED_PTR_32_CACHE
	struct dyld_chained_ptr_32_cache_rebase
	{
		uint32_t    target    : 30,   // 1GB max dyld cache TEXT and DATA
			next      :  2;   // 4-byte stride
	};


	// DYLD_CHAINED_PTR_32_FIRMWARE
	struct dyld_chained_ptr_32_firmware_rebase
	{
		uint32_t    target   : 26,   // 64MB max firmware TEXT and DATA
			next     :  6;   // 4-byte stride
	};

	enum ChainedFixupPointerGeneric {
		GenericArm64eFixupFormat,
		Generic64FixupFormat,
		Generic32FixupFormat,
		Firmware32FixupFormat,
		Kernel64Format
	};

	union Arm64e {
		dyld_chained_ptr_arm64e_auth_rebase authRebase;
		dyld_chained_ptr_arm64e_auth_bind   authBind;
		dyld_chained_ptr_arm64e_rebase      rebase;
		dyld_chained_ptr_arm64e_bind        bind;
		dyld_chained_ptr_arm64e_bind24      bind24;
		dyld_chained_ptr_arm64e_auth_bind24 authBind24;
	};

	union Generic64 {
		dyld_chained_ptr_64_rebase rebase;
		dyld_chained_ptr_64_bind   bind;
	};

	union Generic32 {
		dyld_chained_ptr_32_rebase rebase;
		dyld_chained_ptr_32_bind   bind;
	};

	union ChainedFixupPointer
	{
		dyld_chained_ptr_64_kernel_cache_rebase kernel64;
		dyld_chained_ptr_32_firmware_rebase firmware32;

		uint64_t            raw64;
		Arm64e              arm64e;
		Generic64           generic64;

		uint32_t            raw32;
		Generic32           generic32;
		dyld_chained_ptr_32_cache_rebase             cache32;
	};

	// values for dyld_chained_fixups_header.imports_format
	enum {
		DYLD_CHAINED_IMPORT          = 1,
		DYLD_CHAINED_IMPORT_ADDEND   = 2,
		DYLD_CHAINED_IMPORT_ADDEND64 = 3,
	};

	// DYLD_CHAINED_IMPORT
	struct dyld_chained_import
	{
		uint32_t    lib_ordinal :  8,
			weak_import :  1,
			name_offset : 23;
	};

	// DYLD_CHAINED_IMPORT_ADDEND
	struct dyld_chained_import_addend
	{
		uint32_t    lib_ordinal :  8,
			weak_import :  1,
			name_offset : 23;
		int32_t     addend;
	};

	// DYLD_CHAINED_IMPORT_ADDEND64
	struct dyld_chained_import_addend64
	{
		uint64_t    lib_ordinal : 16,
			weak_import :  1,
			reserved    : 15,
			name_offset : 32;
		uint64_t    addend;
	};

	// When we preload the table, we store them in this format.
	struct import_entry
	{
		uint64_t lib_ordinal;
		uint64_t addend;
		bool weak;
		std::string name;
	};

#ifndef EXPORT_SYMBOL_FLAGS_KIND_MASK
	enum EXPORT_SYMBOL_FLAGS {
		EXPORT_SYMBOL_FLAGS_KIND_MASK           = 0x03u, ///< Mask to access to EXPORT_SYMBOL_KINDS
		EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION     = 0x04u,
		EXPORT_SYMBOL_FLAGS_REEXPORT            = 0x08u,
		EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER   = 0x10u
	};

	enum EXPORT_SYMBOL_KINDS {
		EXPORT_SYMBOL_FLAGS_KIND_REGULAR        = 0x00u,
		EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL   = 0x01u,
		EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE       = 0x02u
	};
#endif

	struct fileset_entry_command {
		uint32_t cmd;
		uint32_t cmdsize;
		uint64_t vmaddr;
		uint64_t fileoff;
		uint32_t nameEntryOffsetFromBaseOfCommand;
		uint32_t reserved;
	};

	struct BoundRelocation
	{
		BNRelocationInfo info;
		std::string name;
		int64_t ordinal;
	};

	struct MachOHeader {
		bool isMainHeader = false;

		uint64_t textBase = 0;
		uint64_t loadCommandOffset = 0;
		mach_header_64 ident;
		std::string identifierPrefix;

		std::vector<std::pair<uint64_t, bool>> entryPoints;
		std::vector<uint64_t> m_entryPoints; //list of entrypoints

		std::vector<BoundRelocation> bindingRelocations;
		std::vector<BNRelocationInfo> rebaseRelocations;

		symtab_command symtab;
		dysymtab_command dysymtab;
		dyld_info_command dyldInfo;
		routines_command_64 routines64;
		function_starts_command functionStarts;
		std::vector<section_64> moduleInitSections;
		linkedit_data_command exportTrie;
		linkedit_data_command chainedFixups {};
		section_64 chainStarts {};

		DataBuffer stringList;
		size_t stringListSize = 0;

		uint64_t relocationBase = 0;
		// Section and program headers, internally use 64-bit form as it is a superset of 32-bit
		std::vector<segment_command_64> segments; //only three types of sections __TEXT, __DATA, __IMPORT
		std::vector<section_64> sections;
		std::vector<std::string> sectionNames;

		std::vector<section_64> symbolStubSections;
		std::vector<section_64> symbolPointerSections;

		std::vector<std::pair<std::string, std::string>> dylibs;

		build_version_command buildVersion;
		std::vector<build_tool_version> buildToolVersions;

		bool dysymPresent = false;
		bool dyldInfoPresent = false;
		bool exportTriePresent = false;
		bool chainedFixupsPresent = false;
		bool chainStartsPresent = false;
		bool routinesPresent = false;
		bool functionStartsPresent = false;
		bool relocatable = false;
	};

	class MachoView: public BinaryView
	{
		MachOHeader m_header;
		std::map<uint64_t, MachOHeader> m_subHeaders; // Used for MH_FILESET entries.

		struct HeaderQualifiedNames {
			QualifiedName cpuTypeEnumQualName;
			QualifiedName fileTypeEnumQualName;
			QualifiedName flagsTypeEnumQualName;
			QualifiedName headerQualName;
			QualifiedName cmdTypeEnumQualName;
			QualifiedName loadCommandQualName;
			QualifiedName protTypeEnumQualName;
			QualifiedName segFlagsTypeEnumQualName;
			QualifiedName loadSegmentCommandQualName;
			QualifiedName loadSegment64CommandQualName;
			QualifiedName sectionQualName;
			QualifiedName section64QualName;
			QualifiedName symtabQualName;
			QualifiedName dynsymtabQualName;
			QualifiedName uuidQualName;
			QualifiedName linkeditDataQualName;
			QualifiedName encryptionInfoQualName;
			QualifiedName versionMinQualName;
			QualifiedName dyldInfoQualName;
			QualifiedName dylibQualName;
			QualifiedName dylibCommandQualName;
			QualifiedName filesetEntryCommandQualName;
		} m_typeNames;

		uint64_t m_universalImageOffset;
		bool m_parseOnly, m_backedByDatabase;
		int64_t m_imageBaseAdjustment;
		size_t m_addressSize;	 //Address size in bytes 4/8
		BNEndianness m_endian;
		uint32_t m_archId;
		Ref<Architecture> m_arch;
		Ref<Platform> m_plat = nullptr;
		bool m_dylibFile;
		bool m_objectFile;
		std::vector<std::string> m_symbols;

		bool m_relocatable = false;

		bool m_extractMangledTypes;
		bool m_simplifyTemplates;

		SymbolQueue* m_symbolQueue = nullptr;
		Ref<Logger> m_logger;

		std::vector<segment_command_64> m_allSegments; //only three types of sections __TEXT, __DATA, __IMPORT
		std::vector<section_64> m_allSections;

		MachOHeader HeaderForAddress(BinaryView* data, uint64_t address, bool isMainHeader, std::string identifierPrefix = "");
		bool InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_t preferredImageBase,
			std::string preferredImageBaseDesc, bool platformSetByUser);

		void RebaseThreadStarts(BinaryReader& virtualReader, std::vector<uint32_t>& threadStarts, uint64_t stepMultiplier);
		Ref<Symbol> DefineMachoSymbol(
			BNSymbolType type, const std::string& name, uint64_t addr, BNSymbolBinding binding, bool deferred);
		void ParseSymbolTable(BinaryReader& reader, MachOHeader& header, const symtab_command& symtab,
			const std::vector<uint32_t>& symbolStubsList, MachoObjCProcessor*,
			std::unordered_map<std::string, std::string>& symbolLibraryMapping);
		bool IsValidFunctionStart(uint64_t addr);
		void ParseFunctionStarts(Platform* platform, uint64_t textBase, function_starts_command functionStarts);
		bool ParseRelocationEntry(const relocation_info& info, uint64_t start, BNRelocationInfo& result);

		bool AddExportTerminalSymbol(const std::string& symbolName, uint64_t symbolFlags, uint64_t imageOffset);
		void ParseExportTrie(BinaryReader& reader, linkedit_data_command exportTrie);
		void ReadExportNode(uint64_t viewStart, DataBuffer& buffer, const std::string& currentText,
			size_t cursor, uint32_t endGuard);

		void ParseRebaseTable(BinaryReader& reader, MachOHeader& header, uint32_t tableOffset, uint32_t tableSize);
		void ParseDynamicTable(BinaryReader& reader, MachOHeader& header, BNSymbolType type, uint32_t tableOffset, uint32_t tableSize,
			BNSymbolBinding binding);
		bool GetSectionPermissions(MachOHeader& header, uint64_t address, uint32_t &flags);
		bool GetSegmentPermissions(MachOHeader& header, uint64_t address, uint32_t &flags);
		void ParseChainedFixups(MachOHeader& header, linkedit_data_command chainedFixups, MachoObjCProcessor*);
		void ParseChainedStarts(MachOHeader& header, section_64 chainedStarts, MachoObjCProcessor*);

		virtual uint64_t PerformGetEntryPoint() const override;

		virtual bool PerformIsExecutable() const override { return true; }
		virtual BNEndianness PerformGetDefaultEndianness() const override;
		virtual bool PerformIsRelocatable() const override;
		virtual size_t PerformGetAddressSize() const override;
	public:
		MachoView(const std::string& typeName, BinaryView* data, bool parseOnly = false);

		virtual bool Init() override;
	};

	class MachoViewType: public BinaryViewType
	{
		Ref<Logger> m_logger;
	public:
		MachoViewType();
		virtual Ref<BinaryView> Create(BinaryView* data) override;
		virtual Ref<BinaryView> Parse(BinaryView* data) override;
		virtual bool IsTypeValidForData(BinaryView* data) override;
		virtual uint64_t ParseHeaders(BinaryView* data, uint64_t imageOffset, mach_header_64& ident, Ref<Architecture>* arch, Ref<Platform>* platform, std::string& errorMsg);
		virtual Ref<Settings> GetLoadSettingsForData(BinaryView* data) override;
	};

	void InitMachoViewType();
}