Loading...
   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
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
/*
 * Copyright (c) 2015 Apple Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 *
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */


/*
 *
 *                     THE KCDATA MANIFESTO
 *
 *   Kcdata is a self-describing data serialization format.  It is meant to get
 *   nested data structures out of xnu with minimum fuss, but also for that data
 *   to be easy to parse.  It is also meant to allow us to add new fields and
 *   evolve the data format without breaking old parsers.
 *
 *   Kcdata is a permanent data format suitable for long-term storage including
 *   in files.  It is very important that we continue to be able to parse old
 *   versions of kcdata-based formats.  To this end, there are several
 *   invariants you MUST MAINTAIN if you alter this file.
 *
 *     * None of the magic numbers should ever be a byteswap of themselves or
 *       of any of the other magic numbers.
 *
 *     * Never remove any type.
 *
 *     * All kcdata structs must be packed, and must exclusively use fixed-size
 *        types.
 *
 *     * Never change the definition of any type, except to add new fields to
 *      the end.
 *
 *     * If you do add new fields to the end of a type, do not actually change
 *       the definition of the old structure.  Instead, define a new structure
 *       with the new fields.  See thread_snapshot_v3 as an example.  This
 *       provides source compatibility for old readers, and also documents where
 *       the potential size cutoffs are.
 *
 *     * If you change libkdd, or kcdata.py run the unit tests under libkdd.
 *
 *     * If you add a type or extend an existing one, add a sample test to
 *       libkdd/tests so future changes to libkdd will always parse your struct
 *       correctly.
 *
 *       For example to add a field to this:
 *
 *          struct foobar {
 *              uint32_t baz;
 *              uint32_t quux;
 *          } __attribute__ ((packed));
 *
 *       Define an evolved structure alongside it like this:
 *
 *           struct foobar_v2 {
 *               uint32_t baz;
 *               uint32_t quux;
 *               ///////// This is where the original structure's layout ended! sizeof(struct foobar) was 8 ////////
 *               uint32_t frozzle;
 *           } __attribute__ ((packed));
 *
 *   If you are parsing kcdata formats, you MUST
 *
 *     * Check the length field of each struct, including array elements.   If the
 *       struct is longer than you expect, you must ignore the extra data.
 *
 *     * Ignore any data types you do not understand.
 *
 *   Additionally, we want to be as forward compatible as we can.  Meaning old
 *   tools should still be able to use new data whenever possible.  To this end,
 *   you should:
 *
 *     * Try not to add new versions of types that supplant old ones.  Instead
 *        extend the length of existing types or add supplemental types.
 *
 *     * Try not to remove information from existing kcdata formats, unless
 *        removal was explicitly asked for.  For example it is fine to add a
 *        stackshot flag to remove unwanted information, but you should not
 *        remove it from the default stackshot if the new flag is absent.
 *
 *     * (TBD) If you do break old readers by removing information or
 *        supplanting old structs, then increase the major version number.
 *
 *
 *
 *  The following is a description of the kcdata format.
 *
 *
 * The format for data is setup in a generic format as follows
 *
 * Layout of data structure:
 *
 *   |         8 - bytes         |
 *   |  type = MAGIC |  LENGTH   |
 *   |            0              |
 *   |      type     |  size     |
 *   |          flags            |
 *   |           data            |
 *   |___________data____________|
 *   |      type     |   size    |
 *   |          flags            |
 *   |___________data____________|
 *   |  type = END   |  size=0   |
 *   |            0              |
 *
 *
 * The type field describes what kind of data is passed. For example type = TASK_CRASHINFO_UUID means the following data is a uuid.
 * These types need to be defined in task_corpse.h for easy consumption by userspace inspection tools.
 *
 * Some range of types is reserved for special types like ints, longs etc. A cool new functionality made possible with this
 * extensible data format is that kernel can decide to put more information as required without requiring user space tools to
 * re-compile to be compatible. The case of rusage struct versions could be introduced without breaking existing tools.
 *
 * Feature description: Generic data with description
 * -------------------
 * Further more generic data with description is very much possible now. For example
 *
 *   - kcdata_add_uint64_with_description(cdatainfo, 0x700, "NUM MACH PORTS");
 *   - and more functions that allow adding description.
 * The userspace tools can then look at the description and print the data even if they are not compiled with knowledge of the field apriori.
 *
 *  Example data:
 * 0000  57 f1 ad de 00 00 00 00 00 00 00 00 00 00 00 00  W...............
 * 0010  01 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00  ........0.......
 * 0020  50 49 44 00 00 00 00 00 00 00 00 00 00 00 00 00  PID.............
 * 0030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 * 0040  9c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 * 0050  01 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00  ........0.......
 * 0060  50 41 52 45 4e 54 20 50 49 44 00 00 00 00 00 00  PARENT PID......
 * 0070  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 * 0080  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 * 0090  ed 58 91 f1
 *
 * Feature description: Container markers for compound data
 * ------------------
 * If a given kernel data type is complex and requires adding multiple optional fields inside a container
 * object for a consumer to understand arbitrary data, we package it using container markers.
 *
 * For example, the stackshot code gathers information and describes the state of a given task with respect
 * to many subsystems. It includes data such as io stats, vm counters, process names/flags and syscall counts.
 *
 * kcdata_add_container_marker(kcdata_p, KCDATA_TYPE_CONTAINER_BEGIN, STACKSHOT_KCCONTAINER_TASK, task_uniqueid);
 * // add multiple data, or add_<type>_with_description()s here
 *
 * kcdata_add_container_marker(kcdata_p, KCDATA_TYPE_CONTAINER_END, STACKSHOT_KCCONTAINER_TASK, task_uniqueid);
 *
 * Feature description: Custom Data formats on demand
 * --------------------
 * With the self describing nature of format, the kernel provider can describe a data type (uniquely identified by a number) and use
 * it in the buffer for sending data. The consumer can parse the type information and have knowledge of describing incoming data.
 * Following is an example of how we can describe a kernel specific struct sample_disk_io_stats in buffer.
 *
 * struct sample_disk_io_stats {
 *     uint64_t        disk_reads_count;
 *     uint64_t        disk_reads_size;
 *     uint64_t        io_priority_count[4];
 *     uint64_t        io_priority_size;
 * } __attribute__ ((packed));
 *
 *
 * struct kcdata_subtype_descriptor disk_io_stats_def[] = {
 *     {KCS_SUBTYPE_FLAGS_NONE, KC_ST_UINT64, 0 * sizeof(uint64_t), sizeof(uint64_t), "disk_reads_count"},
 *     {KCS_SUBTYPE_FLAGS_NONE, KC_ST_UINT64, 1 * sizeof(uint64_t), sizeof(uint64_t), "disk_reads_size"},
 *     {KCS_SUBTYPE_FLAGS_ARRAY, KC_ST_UINT64, 2 * sizeof(uint64_t), KCS_SUBTYPE_PACK_SIZE(4, sizeof(uint64_t)), "io_priority_count"},
 *     {KCS_SUBTYPE_FLAGS_ARRAY, KC_ST_UINT64, (2 + 4) * sizeof(uint64_t), sizeof(uint64_t), "io_priority_size"},
 * };
 *
 * Now you can add this custom type definition into the buffer as
 * kcdata_add_type_definition(kcdata_p, KCTYPE_SAMPLE_DISK_IO_STATS, "sample_disk_io_stats",
 *          &disk_io_stats_def[0], sizeof(disk_io_stats_def)/sizeof(struct kcdata_subtype_descriptor));
 *
 * Feature description: Compression
 * --------------------
 * In order to avoid keeping large amounts of memory reserved for a panic stackshot, kcdata has support
 * for compressing the buffer in a streaming fashion. New data pushed to the kcdata buffer will be
 * automatically compressed using an algorithm selected by the API user (currently, we only support
 * pass-through and zlib, in the future we plan to add WKDM support, see: 57913859).
 *
 * To start using compression, call:
 *   kcdata_init_compress(kcdata_p, hdr_tag, memcpy_f, comp_type);
 * where:
 *   `kcdata_p` is the kcdata buffer that will be used
 *   `hdr_tag` is the usual header tag denoting what type of kcdata buffer this will be
 *   `memcpy_f` a memcpy(3) function to use to copy into the buffer, optional.
 *	 `compy_type` is the compression type, see KCDCT_ZLIB for an example.
 *
 * Once compression is initialized:
 *  (1) all self-describing APIs will automatically compress
 *  (2) you can now use the following APIs to compress data into the buffer:
 *    (None of the following will compress unless kcdata_init_compress() has been called)
 *
 * - kcdata_push_data(kcdata_descriptor_t data, uint32_t type, uint32_t size, const void *input_data)
 *   Pushes the buffer of kctype @type at[@input_data, @input_data + @size]
 *   into the kcdata buffer @data, compressing if needed.
 *
 * - kcdata_push_array(kcdata_descriptor_t data, uint32_t type_of_element,
 *            uint32_t size_of_element, uint32_t count, const void *input_data)
 *   Pushes the array found at @input_data, with element type @type_of_element, where
 *   each element is of size @size_of_element and there are @count elements into the kcdata buffer
 *   at @data.
 *
 * - kcdata_compression_window_open/close(kcdata_descriptor_t data)
 *   In case the data you are trying to push to the kcdata buffer @data is difficult to predict,
 *   you can open a "compression window". Between an open and a close, no compression will be done.
 *   Once you close the window, the underlying compression algorithm will compress the data into the buffer
 *   and automatically rewind the current end marker of the kcdata buffer.
 *   There is an ASCII art in kern_cdata.c to aid the reader in understanding
 *   this.
 *
 * - kcdata_finish_compression(kcdata_descriptor_t data)
 *   Must be called at the end to flush any underlying buffers used by the compression algorithms.
 *   This function will also add some statistics about the compression to the buffer which helps with
 *   decompressing later.
 *
 */


#ifndef _KCDATA_H_
#define _KCDATA_H_

#include <stdint.h>
#include <string.h>
#include <uuid/uuid.h>



#define KCDATA_DESC_MAXLEN 32 /* including NULL byte at end */

#define KCDATA_FLAGS_STRUCT_PADDING_MASK 0xf
#define KCDATA_FLAGS_STRUCT_HAS_PADDING 0x80

/*
 * kcdata aligns elements to 16 byte boundaries.
 */
#define KCDATA_ALIGNMENT_SIZE       0x10

struct kcdata_item {
	uint32_t type;
	uint32_t size; /* len(data)  */
	               /* flags.
	                *
	                * For structures:
	                *    padding      = flags & 0xf
	                *    has_padding  = (flags & 0x80) >> 7
	                *
	                * has_padding is needed to disambiguate cases such as
	                * thread_snapshot_v2 and thread_snapshot_v3.  Their
	                * respective sizes are 0x68 and 0x70, and thread_snapshot_v2
	                * was emitted by old kernels *before* we started recording
	                * padding.  Since legacy thread_snapsht_v2 and modern
	                * thread_snapshot_v3 will both record 0 for the padding
	                * flags, we need some other bit which will be nonzero in the
	                * flags to disambiguate.
	                *
	                * This is why we hardcode a special case for
	                * STACKSHOT_KCTYPE_THREAD_SNAPSHOT into the iterator
	                * functions below.  There is only a finite number of such
	                * hardcodings which will ever be needed.  They can occur
	                * when:
	                *
	                *  * We have a legacy structure that predates padding flags
	                *
	                *  * which we want to extend without changing the kcdata type
	                *
	                *  * by only so many bytes as would fit in the space that
	                *  was previously unused padding.
	                *
	                * For containers:
	                *    container_id = flags
	                *
	                * For arrays:
	                *    element_count = flags & UINT32_MAX
	                *    element_type = (flags >> 32) & UINT32_MAX
	                */
	uint64_t flags;
	char data[]; /* must be at the end */
};

typedef struct kcdata_item * kcdata_item_t;

enum KCDATA_SUBTYPE_TYPES { KC_ST_CHAR = 1, KC_ST_INT8, KC_ST_UINT8, KC_ST_INT16, KC_ST_UINT16, KC_ST_INT32, KC_ST_UINT32, KC_ST_INT64, KC_ST_UINT64 };
typedef enum KCDATA_SUBTYPE_TYPES kctype_subtype_t;

/*
 * A subtype description structure that defines
 * how a compound data is laid out in memory. This
 * provides on the fly definition of types and consumption
 * by the parser.
 */
struct kcdata_subtype_descriptor {
	uint8_t kcs_flags;
#define KCS_SUBTYPE_FLAGS_NONE 0x0
#define KCS_SUBTYPE_FLAGS_ARRAY 0x1
/* Force struct type even if only one element.
 *
 * Normally a kcdata_type_definition is treated as a structure if it has
 * more than one subtype descriptor.  Otherwise it is treated as a simple
 * type.  For example libkdd will represent a simple integer 42 as simply
 * 42, but it will represent a structure containing an integer 42 as
 * {"field_name": 42}..
 *
 * If a kcdata_type_definition has only single subtype, then it will be
 * treated as a structure iff KCS_SUBTYPE_FLAGS_STRUCT is set.  If it has
 * multiple subtypes, it will always be treated as a structure.
 *
 * KCS_SUBTYPE_FLAGS_MERGE has the opposite effect.  If this flag is used then
 * even if there are multiple elements, they will all be treated as individual
 * properties of the parent dictionary.
 */
#define KCS_SUBTYPE_FLAGS_STRUCT 0x2                    /* force struct type even if only one element */
#define KCS_SUBTYPE_FLAGS_MERGE 0x4                     /* treat as multiple elements of parents instead of struct */
	uint8_t kcs_elem_type;                              /* restricted to kctype_subtype_t */
	uint16_t kcs_elem_offset;                           /* offset in struct where data is found */
	uint32_t kcs_elem_size;                             /* size of element (or) packed state for array type */
	char                 kcs_name[KCDATA_DESC_MAXLEN];  /* max 31 bytes for name of field */
};

typedef struct kcdata_subtype_descriptor * kcdata_subtype_descriptor_t;

/*
 * In case of array of basic c types in kctype_subtype_t,
 * size is packed in lower 16 bits and
 * count is packed in upper 16 bits of kcs_elem_size field.
 */
#define KCS_SUBTYPE_PACK_SIZE(e_count, e_size) (((e_count)&0xffffu) << 16 | ((e_size)&0xffffu))

static inline uint32_t
kcs_get_elem_size(kcdata_subtype_descriptor_t d)
{
	if (d->kcs_flags & KCS_SUBTYPE_FLAGS_ARRAY) {
		/* size is composed as ((count &0xffff)<<16 | (elem_size & 0xffff)) */
		return (uint32_t)((d->kcs_elem_size & 0xffff) * ((d->kcs_elem_size & 0xffff0000) >> 16));
	}
	return d->kcs_elem_size;
}

static inline uint32_t
kcs_get_elem_count(kcdata_subtype_descriptor_t d)
{
	if (d->kcs_flags & KCS_SUBTYPE_FLAGS_ARRAY) {
		return (d->kcs_elem_size >> 16) & 0xffff;
	}
	return 1;
}

static inline int
kcs_set_elem_size(kcdata_subtype_descriptor_t d, uint32_t size, uint32_t count)
{
	if (count > 1) {
		/* means we are setting up an array */
		if (size > 0xffff || count > 0xffff) {
			return -1; //invalid argument
		}
		d->kcs_elem_size = ((count & 0xffff) << 16 | (size & 0xffff));
	} else {
		d->kcs_elem_size = size;
	}
	return 0;
}

struct kcdata_type_definition {
	uint32_t kct_type_identifier;
	uint32_t kct_num_elements;
	char kct_name[KCDATA_DESC_MAXLEN];
	struct kcdata_subtype_descriptor kct_elements[];
};


/* chunk type definitions. 0 - 0x7ff are reserved  and defined here
 * NOTE: Please update kcdata/libkdd/kcdtypes.c if you make any changes
 * in STACKSHOT_KCTYPE_* types.
 */

/*
 * Types with description value.
 * these will have KCDATA_DESC_MAXLEN-1 length string description
 * and rest of kcdata_iter_size() - KCDATA_DESC_MAXLEN bytes as data
 */
#define KCDATA_TYPE_INVALID 0x0u
#define KCDATA_TYPE_STRING_DESC 0x1u
#define KCDATA_TYPE_UINT32_DESC 0x2u
#define KCDATA_TYPE_UINT64_DESC 0x3u
#define KCDATA_TYPE_INT32_DESC 0x4u
#define KCDATA_TYPE_INT64_DESC 0x5u
#define KCDATA_TYPE_BINDATA_DESC 0x6u

/*
 * Compound type definitions
 */
#define KCDATA_TYPE_ARRAY 0x11u         /* Array of data OBSOLETE DONT USE THIS*/
#define KCDATA_TYPE_TYPEDEFINTION 0x12u /* Meta type that describes a type on the fly. */
#define KCDATA_TYPE_CONTAINER_BEGIN                                       \
	0x13u /* Container type which has corresponding CONTAINER_END header. \
	       * KCDATA_TYPE_CONTAINER_BEGIN has type in the data segment. \
	       * Both headers have (uint64_t) ID for matching up nested data. \
	       */
#define KCDATA_TYPE_CONTAINER_END 0x14u

#define KCDATA_TYPE_ARRAY_PAD0 0x20u /* Array of data with 0 byte of padding*/
#define KCDATA_TYPE_ARRAY_PAD1 0x21u /* Array of data with 1 byte of padding*/
#define KCDATA_TYPE_ARRAY_PAD2 0x22u /* Array of data with 2 byte of padding*/
#define KCDATA_TYPE_ARRAY_PAD3 0x23u /* Array of data with 3 byte of padding*/
#define KCDATA_TYPE_ARRAY_PAD4 0x24u /* Array of data with 4 byte of padding*/
#define KCDATA_TYPE_ARRAY_PAD5 0x25u /* Array of data with 5 byte of padding*/
#define KCDATA_TYPE_ARRAY_PAD6 0x26u /* Array of data with 6 byte of padding*/
#define KCDATA_TYPE_ARRAY_PAD7 0x27u /* Array of data with 7 byte of padding*/
#define KCDATA_TYPE_ARRAY_PAD8 0x28u /* Array of data with 8 byte of padding*/
#define KCDATA_TYPE_ARRAY_PAD9 0x29u /* Array of data with 9 byte of padding*/
#define KCDATA_TYPE_ARRAY_PADa 0x2au /* Array of data with a byte of padding*/
#define KCDATA_TYPE_ARRAY_PADb 0x2bu /* Array of data with b byte of padding*/
#define KCDATA_TYPE_ARRAY_PADc 0x2cu /* Array of data with c byte of padding*/
#define KCDATA_TYPE_ARRAY_PADd 0x2du /* Array of data with d byte of padding*/
#define KCDATA_TYPE_ARRAY_PADe 0x2eu /* Array of data with e byte of padding*/
#define KCDATA_TYPE_ARRAY_PADf 0x2fu /* Array of data with f byte of padding*/

/*
 * Generic data types that are most commonly used
 */
#define KCDATA_TYPE_LIBRARY_LOADINFO 0x30u   /* struct dyld_uuid_info_32 */
#define KCDATA_TYPE_LIBRARY_LOADINFO64 0x31u /* struct dyld_uuid_info_64 */
#define KCDATA_TYPE_TIMEBASE 0x32u           /* struct mach_timebase_info */
#define KCDATA_TYPE_MACH_ABSOLUTE_TIME 0x33u /* uint64_t */
#define KCDATA_TYPE_TIMEVAL 0x34u            /* struct timeval64 */
#define KCDATA_TYPE_USECS_SINCE_EPOCH 0x35u  /* time in usecs uint64_t */
#define KCDATA_TYPE_PID 0x36u                /* int32_t */
#define KCDATA_TYPE_PROCNAME 0x37u           /* char * */
#define KCDATA_TYPE_NESTED_KCDATA 0x38u      /* nested kcdata buffer */
#define KCDATA_TYPE_LIBRARY_AOTINFO 0x39u    /* struct user64_dyld_aot_info */

#define KCDATA_TYPE_BUFFER_END 0xF19158EDu

/* MAGIC numbers defined for each class of chunked data
 *
 * To future-proof against big-endian arches, make sure none of these magic
 * numbers are byteswaps of each other
 */

#define KCDATA_BUFFER_BEGIN_CRASHINFO 0xDEADF157u            /* owner: corpses/task_corpse.h */
                                                             /* type-range: 0x800 - 0x8ff */
#define KCDATA_BUFFER_BEGIN_STACKSHOT 0x59a25807u            /* owner: sys/stackshot.h */
                                                             /* type-range: 0x900 - 0x93f */
#define KCDATA_BUFFER_BEGIN_COMPRESSED 0x434f4d50u           /* owner: sys/stackshot.h */
                                                             /* type-range: 0x900 - 0x93f */
#define KCDATA_BUFFER_BEGIN_DELTA_STACKSHOT 0xDE17A59Au      /* owner: sys/stackshot.h */
                                                             /* type-range: 0x940 - 0x9ff */
#define KCDATA_BUFFER_BEGIN_BTINFO    0x46414E47u            /* owner: kern/kern_exit.c */
                                                             /* type-range: 0xa01 - 0xaff */
#define KCDATA_BUFFER_BEGIN_OS_REASON 0x53A20900u            /* owner: sys/reason.h */
                                                             /* type-range: 0x1000-0x103f */
#define KCDATA_BUFFER_BEGIN_XNUPOST_CONFIG 0x1e21c09fu       /* owner: osfmk/tests/kernel_tests.c */
                                                             /* type-range: 0x1040-0x105f */

/* next type range number available 0x1060 */
/**************** definitions for XNUPOST *********************/
#define XNUPOST_KCTYPE_TESTCONFIG               0x1040

/**************** definitions for stackshot *********************/

/* This value must always match IO_NUM_PRIORITIES defined in thread_info.h */
#define STACKSHOT_IO_NUM_PRIORITIES     4
/* This value must always match MAXTHREADNAMESIZE used in bsd */
#define STACKSHOT_MAX_THREAD_NAME_SIZE  64

/*
 * NOTE: Please update kcdata/libkdd/kcdtypes.c if you make any changes
 * in STACKSHOT_KCTYPE_* types.
 */
#define STACKSHOT_KCTYPE_IOSTATS                     0x901u /* io_stats_snapshot */
#define STACKSHOT_KCTYPE_GLOBAL_MEM_STATS            0x902u /* struct mem_and_io_snapshot_v2 */
#define STACKSHOT_KCCONTAINER_TASK                   0x903u
#define STACKSHOT_KCCONTAINER_THREAD                 0x904u
#define STACKSHOT_KCTYPE_TASK_SNAPSHOT               0x905u /* task_snapshot_v2, task_snapshot_v3 */
#define STACKSHOT_KCTYPE_THREAD_SNAPSHOT             0x906u /* thread_snapshot_v2, thread_snapshot_v3 */
#define STACKSHOT_KCTYPE_DONATING_PIDS               0x907u /* int[] */
#define STACKSHOT_KCTYPE_SHAREDCACHE_LOADINFO        0x908u /* dyld_shared_cache_loadinfo */
#define STACKSHOT_KCTYPE_THREAD_NAME                 0x909u /* char[] */
#define STACKSHOT_KCTYPE_KERN_STACKFRAME             0x90Au /* struct stack_snapshot_frame32 */
#define STACKSHOT_KCTYPE_KERN_STACKFRAME64           0x90Bu /* struct stack_snapshot_frame64 */
#define STACKSHOT_KCTYPE_USER_STACKFRAME             0x90Cu /* struct stack_snapshot_frame32 */
#define STACKSHOT_KCTYPE_USER_STACKFRAME64           0x90Du /* struct stack_snapshot_frame64 */
#define STACKSHOT_KCTYPE_BOOTARGS                    0x90Eu /* boot args string */
#define STACKSHOT_KCTYPE_OSVERSION                   0x90Fu /* os version string, same as running uname -a */
#define STACKSHOT_KCTYPE_KERN_PAGE_SIZE              0x910u /* kernel page size in uint32_t */
#define STACKSHOT_KCTYPE_JETSAM_LEVEL                0x911u /* jetsam level in uint32_t */
#define STACKSHOT_KCTYPE_DELTA_SINCE_TIMESTAMP       0x912u /* timestamp used for the delta stackshot */
#define STACKSHOT_KCTYPE_KERN_STACKLR                0x913u /* uint32_t */
#define STACKSHOT_KCTYPE_KERN_STACKLR64              0x914u /* uint64_t */
#define STACKSHOT_KCTYPE_USER_STACKLR                0x915u /* uint32_t */
#define STACKSHOT_KCTYPE_USER_STACKLR64              0x916u /* uint64_t */
#define STACKSHOT_KCTYPE_NONRUNNABLE_TIDS            0x917u /* uint64_t */
#define STACKSHOT_KCTYPE_NONRUNNABLE_TASKS           0x918u /* uint64_t */
#define STACKSHOT_KCTYPE_CPU_TIMES                   0x919u /* struct stackshot_cpu_times or stackshot_cpu_times_v2 */
#define STACKSHOT_KCTYPE_STACKSHOT_DURATION          0x91au /* struct stackshot_duration */
#define STACKSHOT_KCTYPE_STACKSHOT_FAULT_STATS       0x91bu /* struct stackshot_fault_stats */
#define STACKSHOT_KCTYPE_KERNELCACHE_LOADINFO        0x91cu /* kernelcache UUID -- same as KCDATA_TYPE_LIBRARY_LOADINFO64 */
#define STACKSHOT_KCTYPE_THREAD_WAITINFO             0x91du /* struct stackshot_thread_waitinfo */
#define STACKSHOT_KCTYPE_THREAD_GROUP_SNAPSHOT       0x91eu /* struct thread_group_snapshot{,_v2,_v3} */
#define STACKSHOT_KCTYPE_THREAD_GROUP                0x91fu /* uint64_t */
#define STACKSHOT_KCTYPE_JETSAM_COALITION_SNAPSHOT   0x920u /* struct jetsam_coalition_snapshot */
#define STACKSHOT_KCTYPE_JETSAM_COALITION            0x921u /* uint64_t */
#define STACKSHOT_KCTYPE_THREAD_POLICY_VERSION       0x922u /* THREAD_POLICY_INTERNAL_STRUCT_VERSION in uint32 */
#define STACKSHOT_KCTYPE_INSTRS_CYCLES               0x923u /* struct instrs_cycles_snapshot_v2 */
#define STACKSHOT_KCTYPE_USER_STACKTOP               0x924u /* struct stack_snapshot_stacktop */
#define STACKSHOT_KCTYPE_ASID                        0x925u /* uint32_t */
#define STACKSHOT_KCTYPE_PAGE_TABLES                 0x926u /* uint64_t */
#define STACKSHOT_KCTYPE_SYS_SHAREDCACHE_LAYOUT      0x927u /* same as KCDATA_TYPE_LIBRARY_LOADINFO64 */
#define STACKSHOT_KCTYPE_THREAD_DISPATCH_QUEUE_LABEL 0x928u /* dispatch queue label */
#define STACKSHOT_KCTYPE_THREAD_TURNSTILEINFO        0x929u /* struct stackshot_thread_turnstileinfo */
#define STACKSHOT_KCTYPE_TASK_CPU_ARCHITECTURE       0x92au /* struct stackshot_cpu_architecture */
#define STACKSHOT_KCTYPE_LATENCY_INFO                0x92bu /* struct stackshot_latency_collection_v2 */
#define STACKSHOT_KCTYPE_LATENCY_INFO_TASK           0x92cu /* struct stackshot_latency_task */
#define STACKSHOT_KCTYPE_LATENCY_INFO_THREAD         0x92du /* struct stackshot_latency_thread */
#define STACKSHOT_KCTYPE_LOADINFO64_TEXT_EXEC        0x92eu /* TEXT_EXEC load info -- same as KCDATA_TYPE_LIBRARY_LOADINFO64 */
#define STACKSHOT_KCTYPE_AOTCACHE_LOADINFO           0x92fu /* struct dyld_aot_cache_uuid_info */
#define STACKSHOT_KCTYPE_TRANSITIONING_TASK_SNAPSHOT 0x930u /* transitioning_task_snapshot */
#define STACKSHOT_KCCONTAINER_TRANSITIONING_TASK     0x931u
#define STACKSHOT_KCTYPE_USER_ASYNC_START_INDEX      0x932u /* uint32_t index in user_stack of beginning of async stack */
#define STACKSHOT_KCTYPE_USER_ASYNC_STACKLR64        0x933u /* uint64_t async stack pointers */
#define STACKSHOT_KCCONTAINER_PORTLABEL              0x934u /* container for port label info */
#define STACKSHOT_KCTYPE_PORTLABEL                   0x935u /* struct stackshot_portlabel */
#define STACKSHOT_KCTYPE_PORTLABEL_NAME              0x936u /* string port name */
#define STACKSHOT_KCTYPE_DYLD_COMPACTINFO            0x937u /* binary blob of dyld info (variable size) */
#define STACKSHOT_KCTYPE_SUSPENSION_INFO             0x938u /* struct stackshot_suspension_info */
#define STACKSHOT_KCTYPE_SUSPENSION_SOURCE           0x939u /* struct stackshot_suspension_source */

#define STACKSHOT_KCTYPE_TASK_DELTA_SNAPSHOT         0x940u /* task_delta_snapshot_v2 */
#define STACKSHOT_KCTYPE_THREAD_DELTA_SNAPSHOT       0x941u /* thread_delta_snapshot_v* */
#define STACKSHOT_KCCONTAINER_SHAREDCACHE            0x942u /* container for shared cache info */
#define STACKSHOT_KCTYPE_SHAREDCACHE_INFO            0x943u /* dyld_shared_cache_loadinfo_v2 */
#define STACKSHOT_KCTYPE_SHAREDCACHE_AOTINFO         0x944u /* struct dyld_aot_cache_uuid_info */
#define STACKSHOT_KCTYPE_SHAREDCACHE_ID              0x945u /* uint32_t in task: if we aren't attached to Primary, which one */
#define STACKSHOT_KCTYPE_CODESIGNING_INFO            0x946u /* struct stackshot_task_codesigning_info */
#define STACKSHOT_KCTYPE_OS_BUILD_VERSION            0x947u /* os build version string (ex: 20A123) */
#define STACKSHOT_KCTYPE_KERN_EXCLAVES_THREADINFO    0x948u /* struct thread_exclaves_info */
#define STACKSHOT_KCCONTAINER_EXCLAVES               0x949u /* exclave threads info */
#define STACKSHOT_KCCONTAINER_EXCLAVE_SCRESULT       0x94au /* exclave thread container for one scid */
#define STACKSHOT_KCTYPE_EXCLAVE_SCRESULT_INFO       0x94bu /* struct exclave_scresult_info */
#define STACKSHOT_KCCONTAINER_EXCLAVE_IPCSTACKENTRY  0x94cu /* container for one chunk of exclave IPC chain */
#define STACKSHOT_KCTYPE_EXCLAVE_IPCSTACKENTRY_INFO  0x94du /* struct exclave_ipcstackentry_info */
#define STACKSHOT_KCTYPE_EXCLAVE_IPCSTACKENTRY_ECSTACK 0x94eu /* exclave_ecstackentry_addr_t */
#define STACKSHOT_KCCONTAINER_EXCLAVE_ADDRESSSPACE   0x94fu /* exclave address space container */
#define STACKSHOT_KCTYPE_EXCLAVE_ADDRESSSPACE_INFO   0x950u /* struct exclave_addressspace_info */
#define STACKSHOT_KCTYPE_EXCLAVE_ADDRESSSPACE_NAME   0x951u /* exclave component name */
#define STACKSHOT_KCCONTAINER_EXCLAVE_TEXTLAYOUT     0x952u /* exclave text layout container */
#define STACKSHOT_KCTYPE_EXCLAVE_TEXTLAYOUT_INFO     0x953u /* struct exclave_textlayout_info */
#define STACKSHOT_KCTYPE_EXCLAVE_TEXTLAYOUT_SEGMENTS 0x954u /* struct exclave_textlayout_segment_v2 */
#define STACKSHOT_KCTYPE_KERN_EXCLAVES_CRASH_THREADINFO 0x955u /* struct thread_crash_exclaves_info */
#define STACKSHOT_KCTYPE_LATENCY_INFO_CPU            0x956u /* struct stackshot_latency_cpu */
#define STACKSHOT_KCTYPE_TASK_EXEC_META              0x957u /* struct task_exec_meta */
#define STACKSHOT_KCTYPE_TASK_MEMORYSTATUS           0x958u /* struct task_memorystatus_snapshot */
#define STACKSHOT_KCTYPE_MTEINFO_CELL                0x959u /* struct mteinfo_cell */
#define STACKSHOT_KCTYPE_LATENCY_INFO_BUFFER         0x95au /* struct stackshot_latency_buffer */
#define STACKSHOT_KCTYPE_VMRL_BLOCKING_RELS          0x95bu /* struct stackshot_vmrl_blocking_relationship */
#define STACKSHOT_KCTYPE_LOCK_STATE                  0x95cu /* struct stackshot_device_lock_state */

struct stack_snapshot_frame32 {
	uint32_t lr;
	uint32_t sp;
};

struct stack_snapshot_frame64 {
	uint64_t lr;
	uint64_t sp;
};

struct dyld_uuid_info_32 {
	uint32_t imageLoadAddress; /* base address image is mapped at */
	uuid_t   imageUUID;
};

struct dyld_uuid_info_64 {
	uint64_t imageLoadAddress; /* XXX image slide */
	uuid_t   imageUUID;
};

/*
 * N.B.: Newer kernels output dyld_shared_cache_loadinfo structures
 * instead of this, since the field names match their contents better.
 */
struct dyld_uuid_info_64_v2 {
	uint64_t imageLoadAddress; /* XXX image slide */
	uuid_t   imageUUID;
	/* end of version 1 of dyld_uuid_info_64. sizeof v1 was 24 */
	uint64_t imageSlidBaseAddress; /* slid base address or slid first mapping of image */
};

enum dyld_shared_cache_flags {
	kSharedCacheSystemPrimary = 0x1, /* primary shared cache on the system; attached tasks will have kTaskSharedRegionSystem set */
	kSharedCacheDriverkit = 0x2, /* driverkit shared cache */
	kSharedCacheAOT = 0x4,    /* Rosetta shared cache */
};

/*
 * This is the renamed version of dyld_uuid_info_64 with more accurate
 * field names, for STACKSHOT_KCTYPE_SHAREDCACHE_LOADINFO.  Any users
 * must be aware of the dyld_uuid_info_64* version history and ensure
 * the fields they are accessing are within the actual bounds.
 *
 * OLD_FIELD              NEW_FIELD
 * imageLoadAddress       sharedCacheSlide
 * imageUUID              sharedCacheUUID
 * imageSlidBaseAddress   sharedCacheUnreliableSlidBaseAddress
 * -                      sharedCacheSlidFirstMapping
 * -                      sharedCacheID
 * -                      sharedCacheFlags
 */
struct dyld_shared_cache_loadinfo_v2 {
	uint64_t sharedCacheSlide;      /* image slide value */
	uuid_t   sharedCacheUUID;
	/* end of version 1 of dyld_uuid_info_64. sizeof v1 was 24 */
	uint64_t sharedCacheUnreliableSlidBaseAddress;  /* for backwards-compatibility; use sharedCacheSlidFirstMapping if available */
	/* end of version 2 of dyld_uuid_info_64. sizeof v2 was 32 */
	uint64_t sharedCacheSlidFirstMapping; /* slid base address of first mapping */
	/* end of version 1 of dyld_shared_cache_loadinfo. sizeof was 40 */
	uint32_t sharedCacheID; /* ID of shared cache */
	uint32_t sharedCacheFlags;
};

struct dyld_shared_cache_loadinfo {
	uint64_t sharedCacheSlide;      /* image slide value */
	uuid_t   sharedCacheUUID;
	/* end of version 1 of dyld_uuid_info_64. sizeof v1 was 24 */
	uint64_t sharedCacheUnreliableSlidBaseAddress;  /* for backwards-compatibility; use sharedCacheSlidFirstMapping if available */
	/* end of version 2 of dyld_uuid_info_64. sizeof v2 was 32 */
	uint64_t sharedCacheSlidFirstMapping; /* slid base address of first mapping */
};

struct dyld_aot_cache_uuid_info {
	uint64_t x86SlidBaseAddress; /* slid first mapping address of x86 shared cache */
	uuid_t x86UUID; /* UUID of x86 shared cache */
	uint64_t aotSlidBaseAddress; /* slide first mapping address of aot cache */
	uuid_t aotUUID; /* UUID of aot shared cache */
};

struct user32_dyld_uuid_info {
	uint32_t        imageLoadAddress;       /* base address image is mapped into */
	uuid_t                  imageUUID;                      /* UUID of image */
};

struct user64_dyld_uuid_info {
	uint64_t        imageLoadAddress;       /* base address image is mapped into */
	uuid_t                  imageUUID;                      /* UUID of image */
};

#define DYLD_AOT_IMAGE_KEY_SIZE 32

struct user64_dyld_aot_info {
	uint64_t x86LoadAddress;
	uint64_t aotLoadAddress;
	uint64_t aotImageSize;
	uint8_t  aotImageKey[DYLD_AOT_IMAGE_KEY_SIZE];
};

enum task_snapshot_flags {
	/* k{User,Kernel}64_p (values 0x1 and 0x2) are defined in generic_snapshot_flags */
	kTaskRsrcFlagged                            = 0x4, // In the EXC_RESOURCE danger zone?
	kTerminatedSnapshot                         = 0x8,
	kPidSuspended                               = 0x10, // true for suspended task
	kFrozen                                     = 0x20, // true for hibernated task (along with pidsuspended)
	kTaskDarwinBG                               = 0x40,
	kTaskExtDarwinBG                            = 0x80,
	kTaskVisVisible                             = 0x100,
	kTaskVisNonvisible                          = 0x200,
	kTaskIsForeground                           = 0x400,
	kTaskIsBoosted                              = 0x800,
	kTaskIsSuppressed                           = 0x1000,
	kTaskIsTimerThrottled                       = 0x2000, /* deprecated */
	kTaskIsImpDonor                             = 0x4000,
	kTaskIsLiveImpDonor                         = 0x8000,
	kTaskIsDirty                                = 0x10000,
	kTaskWqExceededConstrainedThreadLimit       = 0x20000,
	kTaskWqExceededTotalThreadLimit             = 0x40000,
	kTaskWqFlagsAvailable                       = 0x80000,
	kTaskUUIDInfoFaultedIn                      = 0x100000, /* successfully faulted in some UUID info */
	kTaskUUIDInfoMissing                        = 0x200000, /* some UUID info was paged out */
	kTaskUUIDInfoTriedFault                     = 0x400000, /* tried to fault in UUID info */
	kTaskSharedRegionInfoUnavailable            = 0x800000,  /* shared region info unavailable */
	kTaskTALEngaged                             = 0x1000000,
	/* 0x2000000 unused */
	kTaskIsDirtyTracked                         = 0x4000000,
	kTaskAllowIdleExit                          = 0x8000000,
	kTaskIsTranslated                           = 0x10000000,
	kTaskSharedRegionNone                       = 0x20000000,     /* task doesn't have a shared region */
	kTaskSharedRegionSystem                     = 0x40000000,     /* task attached to region with kSharedCacheSystemPrimary set */
	kTaskSharedRegionOther                      = 0x80000000,     /* task is attached to a different shared region */
	kTaskDyldCompactInfoNone                    = 0x100000000,
	kTaskDyldCompactInfoTooBig                  = 0x200000000,
	kTaskDyldCompactInfoFaultedIn               = 0x400000000,
	kTaskDyldCompactInfoMissing                 = 0x800000000,
	kTaskDyldCompactInfoTriedFault              = 0x1000000000,
	kTaskWqExceededCooperativeThreadLimit       = 0x2000000000,
	kTaskWqExceededActiveConstrainedThreadLimit = 0x4000000000,
	kTaskRunawayMitigation                      = 0x8000000000,
	kTaskIsActive                               = 0x10000000000,
	kTaskIsManaged                              = 0x20000000000,
	kTaskHasAssertion                           = 0x40000000000,
}; // Note: Add any new flags to kcdata.py (ts_ss_flags)

enum task_transition_type {
	kTaskIsTerminated                      = 0x1,// Past LPEXIT
};

/* See kcdata_private.h for more flag definitions */
enum task_exec_flags : uint64_t {
	kTaskExecTranslated     = 0x01,     /* Task is running under translation (eg, Rosetta) */
	kTaskExecHardenedHeap   = 0x02,     /* Task has the hardened heap security feature */
	kTaskExecReserved00     = 0x04,
	kTaskExecReserved01     = 0x08,
	kTaskExecReserved02     = 0x10,
	kTaskExecReserved03     = 0x20
};

/* metadata about a task that is fixed at spawn/exec time */
struct task_exec_meta {
	uint64_t tem_flags; /* task_exec_flags */
} __attribute__((packed));


/* MTE info cell state, must match mte_cell_state_t */
__enum_closed_decl(mte_info_cell_state_t, uint8_t, {
	MTE_INFO_STATE_DISABLED,
	MTE_INFO_STATE_PINNED,
	MTE_INFO_STATE_DEACTIVATING,
	MTE_INFO_STATE_CLAIMED,
	MTE_INFO_STATE_INACTIVE,
	MTE_INFO_STATE_RECLAIMING,
	MTE_INFO_STATE_ACTIVATING,
	MTE_INFO_STATE_ACTIVE,
});

/* MTE info cell data */
struct mte_info_cell {
	uint8_t mic_state;
	uint8_t mic_tagged_count;              /* Number of tagged pages in this tag storage page */
	uint8_t mic_free_count;                /* Number of free pages in this tag storage page */
	uint8_t mic_wired_count;               /* Number of wired pages in this tag storage page, regardless of tagging */
	uint8_t mic_wired_tagged_count;        /* Number of tagged pages wired that aren't used by kernel memory allocators */
	uint8_t mic_kernel_wired_tagged_count; /* Number of tagged pages wired for use by the kernel memory allocators, kmem and zalloc */
} __attribute__((packed));

enum thread_snapshot_flags {
	/* k{User,Kernel}64_p (values 0x1 and 0x2) are defined in generic_snapshot_flags */
	kHasDispatchSerial      = 0x4,
	kStacksPCOnly           = 0x8,     /* Stack traces have no frame pointers. */
	kThreadDarwinBG         = 0x10,    /* Thread is darwinbg */
	kThreadIOPassive        = 0x20,    /* Thread uses passive IO */
	kThreadSuspended        = 0x40,    /* Thread is suspended */
	kThreadTruncatedBT      = 0x80,    /* Unmapped pages caused truncated backtrace */
	kGlobalForcedIdle       = 0x100,   /* Thread performs global forced idle */
	kThreadFaultedBT        = 0x200,   /* Some thread stack pages were faulted in as part of BT */
	kThreadTriedFaultBT     = 0x400,   /* We tried to fault in thread stack pages as part of BT */
	kThreadOnCore           = 0x800,   /* Thread was on-core when we entered debugger context */
	kThreadIdleWorker       = 0x1000,  /* Thread is an idle libpthread worker thread */
	kThreadMain             = 0x2000,  /* Thread is the main thread */
	kThreadTruncKernBT      = 0x4000,  /* Unmapped pages caused truncated kernel BT */
	kThreadTruncUserBT      = 0x8000,  /* Unmapped pages caused truncated user BT */
	kThreadTruncUserAsyncBT = 0x10000, /* Unmapped pages caused truncated user async BT */
}; // Note: Add any new flags to kcdata.py (ths_ss_flags)

struct mem_and_io_snapshot {
	uint32_t        snapshot_magic;
	uint32_t        free_pages;
	uint32_t        active_pages;
	uint32_t        inactive_pages;
	uint32_t        purgeable_pages;
	uint32_t        wired_pages;
	uint32_t        speculative_pages;
	uint32_t        throttled_pages;
	uint32_t        filebacked_pages;
	uint32_t        compressions;
	uint32_t        decompressions;
	uint32_t        compressor_size;
	int32_t         busy_buffer_count;
	uint32_t        pages_wanted;
	uint32_t        pages_reclaimed;
	uint8_t         pages_wanted_reclaimed_valid; // did mach_vm_pressure_monitor succeed?
} __attribute__((packed));

struct mem_and_io_snapshot_v2 {
	uint32_t        snapshot_magic;
	uint32_t        free_pages;
	uint32_t        active_pages;
	uint32_t        inactive_pages;
	uint32_t        purgeable_pages;
	uint32_t        wired_pages;
	uint32_t        speculative_pages;
	uint32_t        throttled_pages;
	uint32_t        filebacked_pages;
	uint32_t        compressions;
	uint32_t        decompressions;
	uint32_t        compressor_size;
	int32_t         busy_buffer_count;
	uint32_t        pages_wanted;
	uint32_t        pages_reclaimed;
	uint8_t         pages_wanted_reclaimed_valid; // did mach_vm_pressure_monitor succeed?
	uint32_t        shared_region_pages;
	uint32_t        compressed_pages;
	uint32_t        swapped_pages;
} __attribute__((packed));

/* SS_TH_* macros are for ths_state */
#define SS_TH_WAIT 0x01       /* queued for waiting */
#define SS_TH_SUSP 0x02       /* stopped or requested to stop */
#define SS_TH_RUN 0x04        /* running or on runq */
#define SS_TH_UNINT 0x08      /* waiting uninteruptibly */
#define SS_TH_TERMINATE 0x10  /* halted at termination */
#define SS_TH_TERMINATE2 0x20 /* added to termination queue */
#define SS_TH_IDLE 0x80       /* idling processor */

struct thread_snapshot_v2 {
	uint64_t  ths_thread_id;
	uint64_t  ths_wait_event;
	uint64_t  ths_continuation;
	uint64_t  ths_total_syscalls;
	uint64_t  ths_voucher_identifier;
	uint64_t  ths_dqserialnum;
	uint64_t  ths_user_time;
	uint64_t  ths_sys_time;
	uint64_t  ths_ss_flags;
	uint64_t  ths_last_run_time;
	uint64_t  ths_last_made_runnable_time;
	uint32_t  ths_state;
	uint32_t  ths_sched_flags;
	int16_t   ths_base_priority;
	int16_t   ths_sched_priority;
	uint8_t   ths_eqos;
	uint8_t ths_rqos;
	uint8_t ths_rqos_override;
	uint8_t ths_io_tier;
} __attribute__((packed));

struct thread_snapshot_v3 {
	uint64_t ths_thread_id;
	uint64_t ths_wait_event;
	uint64_t ths_continuation;
	uint64_t ths_total_syscalls;
	uint64_t ths_voucher_identifier;
	uint64_t ths_dqserialnum;
	uint64_t ths_user_time;
	uint64_t ths_sys_time;
	uint64_t ths_ss_flags;
	uint64_t ths_last_run_time;
	uint64_t ths_last_made_runnable_time;
	uint32_t ths_state;
	uint32_t ths_sched_flags;
	int16_t ths_base_priority;
	int16_t ths_sched_priority;
	uint8_t ths_eqos;
	uint8_t ths_rqos;
	uint8_t ths_rqos_override;
	uint8_t ths_io_tier;
	uint64_t ths_thread_t;
} __attribute__((packed));


struct thread_snapshot_v4 {
	uint64_t ths_thread_id;
	uint64_t ths_wait_event;
	uint64_t ths_continuation;
	uint64_t ths_total_syscalls;
	uint64_t ths_voucher_identifier;
	uint64_t ths_dqserialnum;
	uint64_t ths_user_time;
	uint64_t ths_sys_time;
	uint64_t ths_ss_flags;
	uint64_t ths_last_run_time;
	uint64_t ths_last_made_runnable_time;
	uint32_t ths_state;
	uint32_t ths_sched_flags;
	int16_t ths_base_priority;
	int16_t ths_sched_priority;
	uint8_t ths_eqos;
	uint8_t ths_rqos;
	uint8_t ths_rqos_override;
	uint8_t ths_io_tier;
	uint64_t ths_thread_t;
	uint64_t ths_requested_policy;
	uint64_t ths_effective_policy;
} __attribute__((packed));


struct thread_group_snapshot {
	uint64_t tgs_id;
	char tgs_name[16];
} __attribute__((packed));

/*
 * In general these flags mirror their THREAD_GROUP_FLAGS_ counterparts.
 * THREAD_GROUP_FLAGS_UI_APP was repurposed and THREAD_GROUP_FLAGS_APPLICATION
 * introduced to take its place. To remain compatible, kThreadGroupUIApp is
 * kept around and kThreadGroupUIApplication introduced.
 */
enum thread_group_flags {
	kThreadGroupEfficient     = 0x1,
	kThreadGroupApplication   = 0x2,
	kThreadGroupUIApp         = 0x2,
	kThreadGroupCritical      = 0x4,
	kThreadGroupBestEffort    = 0x8,
	kThreadGroupUIApplication = 0x100,
	kThreadGroupManaged       = 0x200,
	kThreadGroupStrictTimers  = 0x400,
}; // Note: Add any new flags to kcdata.py (tgs_flags)

struct thread_group_snapshot_v2 {
	uint64_t tgs_id;
	char tgs_name[16];
	uint64_t tgs_flags;
} __attribute__((packed));

struct thread_group_snapshot_v3 {
	uint64_t tgs_id;
	char tgs_name[16];
	uint64_t tgs_flags;
	char tgs_name_cont[16];
} __attribute__((packed));

enum coalition_flags {
	kCoalitionTermRequested = 0x1,
	kCoalitionTerminated    = 0x2,
	kCoalitionReaped        = 0x4,
	kCoalitionPrivileged    = 0x8,
}; // Note: Add any new flags to kcdata.py (jcs_flags)

struct jetsam_coalition_snapshot {
	uint64_t jcs_id;
	uint64_t jcs_flags;
	uint64_t jcs_thread_group;
	uint64_t jcs_leader_task_uniqueid;
} __attribute__((packed));

struct instrs_cycles_snapshot {
	uint64_t ics_instructions;
	uint64_t ics_cycles;
} __attribute__((packed));

struct instrs_cycles_snapshot_v2 {
	uint64_t ics_instructions;
	uint64_t ics_cycles;
	uint64_t ics_p_instructions;
	uint64_t ics_p_cycles;
} __attribute__((packed));

struct thread_delta_snapshot_v2 {
	uint64_t  tds_thread_id;
	uint64_t  tds_voucher_identifier;
	uint64_t  tds_ss_flags;
	uint64_t  tds_last_made_runnable_time;
	uint32_t  tds_state;
	uint32_t  tds_sched_flags;
	int16_t   tds_base_priority;
	int16_t   tds_sched_priority;
	uint8_t   tds_eqos;
	uint8_t   tds_rqos;
	uint8_t   tds_rqos_override;
	uint8_t   tds_io_tier;
} __attribute__ ((packed));

struct thread_delta_snapshot_v3 {
	uint64_t  tds_thread_id;
	uint64_t  tds_voucher_identifier;
	uint64_t  tds_ss_flags;
	uint64_t  tds_last_made_runnable_time;
	uint32_t  tds_state;
	uint32_t  tds_sched_flags;
	int16_t   tds_base_priority;
	int16_t   tds_sched_priority;
	uint8_t   tds_eqos;
	uint8_t   tds_rqos;
	uint8_t   tds_rqos_override;
	uint8_t   tds_io_tier;
	uint64_t  tds_requested_policy;
	uint64_t  tds_effective_policy;
} __attribute__ ((packed));

struct io_stats_snapshot {
	/*
	 * I/O Statistics
	 * XXX: These fields must be together.
	 */
	uint64_t         ss_disk_reads_count;
	uint64_t         ss_disk_reads_size;
	uint64_t         ss_disk_writes_count;
	uint64_t         ss_disk_writes_size;
	uint64_t         ss_io_priority_count[STACKSHOT_IO_NUM_PRIORITIES];
	uint64_t         ss_io_priority_size[STACKSHOT_IO_NUM_PRIORITIES];
	uint64_t         ss_paging_count;
	uint64_t         ss_paging_size;
	uint64_t         ss_non_paging_count;
	uint64_t         ss_non_paging_size;
	uint64_t         ss_data_count;
	uint64_t         ss_data_size;
	uint64_t         ss_metadata_count;
	uint64_t         ss_metadata_size;
	/* XXX: I/O Statistics end */
} __attribute__ ((packed));

struct task_snapshot_v2 {
	uint64_t  ts_unique_pid;
	uint64_t  ts_ss_flags;
	uint64_t  ts_user_time_in_terminated_threads;
	uint64_t  ts_system_time_in_terminated_threads;
	uint64_t  ts_p_start_sec;
	uint64_t  ts_task_size;
	uint64_t  ts_max_resident_size;
	uint32_t  ts_suspend_count;
	uint32_t  ts_faults;
	uint32_t  ts_pageins;
	uint32_t  ts_cow_faults;
	uint32_t  ts_was_throttled;
	uint32_t  ts_did_throttle;
	uint32_t  ts_latency_qos;
	int32_t   ts_pid;
	char      ts_p_comm[32];
} __attribute__ ((packed));

struct task_snapshot_v3 {
	uint64_t  ts_unique_pid;
	uint64_t  ts_ss_flags;
	uint64_t  ts_user_time_in_terminated_threads;
	uint64_t  ts_system_time_in_terminated_threads;
	uint64_t  ts_p_start_sec;
	uint64_t  ts_task_size;
	uint64_t  ts_max_resident_size;
	uint32_t  ts_suspend_count;
	uint32_t  ts_faults;
	uint32_t  ts_pageins;
	uint32_t  ts_cow_faults;
	uint32_t  ts_was_throttled;
	uint32_t  ts_did_throttle;
	uint32_t  ts_latency_qos;
	int32_t   ts_pid;
	char      ts_p_comm[32];
	uint32_t  ts_uid;
	uint32_t  ts_gid;
} __attribute__ ((packed));

struct transitioning_task_snapshot {
	uint64_t  tts_unique_pid;
	uint64_t  tts_ss_flags;
	uint64_t  tts_transition_type;
	int32_t   tts_pid;
	char      tts_p_comm[32];
} __attribute__ ((packed));

struct task_delta_snapshot_v2 {
	uint64_t  tds_unique_pid;
	uint64_t  tds_ss_flags;
	uint64_t  tds_user_time_in_terminated_threads;
	uint64_t  tds_system_time_in_terminated_threads;
	uint64_t  tds_task_size;
	uint64_t  tds_max_resident_size;
	uint32_t  tds_suspend_count;
	uint32_t  tds_faults;
	uint32_t  tds_pageins;
	uint32_t  tds_cow_faults;
	uint32_t  tds_was_throttled;
	uint32_t  tds_did_throttle;
	uint32_t  tds_latency_qos;
} __attribute__ ((packed));

struct task_memorystatus_snapshot {
	int32_t  tms_current_memlimit;
	int32_t  tms_effectivepriority;
	int32_t  tms_requestedpriority;
	int32_t  tms_assertionpriority;
} __attribute__ ((packed));

#define KCDATA_INVALID_CS_TRUST_LEVEL 0xffffffff
struct stackshot_task_codesigning_info {
	uint64_t csflags;
	uint32_t cs_trust_level;
} __attribute__ ((packed));

struct stackshot_cpu_times {
	uint64_t user_usec;
	uint64_t system_usec;
} __attribute__((packed));

struct stackshot_cpu_times_v2 {
	uint64_t user_usec;
	uint64_t system_usec;
	uint64_t runnable_usec;
} __attribute__((packed));

struct stackshot_duration {
	uint64_t stackshot_duration;
	uint64_t stackshot_duration_outer;
} __attribute__((packed));

struct stackshot_duration_v2 {
	uint64_t stackshot_duration;
	uint64_t stackshot_duration_outer;
	uint64_t stackshot_duration_prior;
} __attribute__((packed));

struct stackshot_fault_stats {
	uint32_t sfs_pages_faulted_in;      /* number of pages faulted in using KDP fault path */
	uint64_t sfs_time_spent_faulting;   /* MATUs spent faulting */
	uint64_t sfs_system_max_fault_time; /* MATUs fault time limit per stackshot */
	uint8_t  sfs_stopped_faulting;      /* we stopped decompressing because we hit the limit */
} __attribute__((packed));

typedef struct stackshot_thread_waitinfo {
	uint64_t owner;         /* The thread that owns the object */
	uint64_t waiter;        /* The thread that's waiting on the object */
	uint64_t context;       /* A context uniquely identifying the object */
	uint8_t wait_type;      /* The type of object that the thread is waiting on */
} __attribute__((packed)) thread_waitinfo_t;

typedef struct stackshot_thread_waitinfo_v2 {
	uint64_t owner;         /* The thread that owns the object */
	uint64_t waiter;        /* The thread that's waiting on the object */
	uint64_t context;       /* A context uniquely identifying the object */
	uint8_t wait_type;      /* The type of object that the thread is waiting on */
	int16_t portlabel_id;   /* matches to a stackshot_portlabel, or NONE or MISSING */
	uint32_t wait_flags;    /* info about the wait */
#define STACKSHOT_WAITINFO_FLAGS_SPECIALREPLY 0x1  /* We're waiting on a special reply port */
#define STACKSHOT_WAITINFO_FLAGS_BOOTSTRAP 0x2  /* We're waiting on a bootstrap port */
} __attribute__((packed)) thread_waitinfo_v2_t;


typedef struct stackshot_vmrl_blocking_relationship {
	uint64_t waiter_tid;
	uint64_t blocker_tid;
	uint64_t entry_hash;
	uint32_t flags;
} __attribute__((packed)) vmrl_blocking_relationship_t;

#define STACKSHOT_WAITER_VMRL_SHARED                    0x01
#define STACKSHOT_BLOCKER_VMRL_SHARED                   0x02
#define STACKSHOT_WAITER_VMRL_EXCLUSIVE                 0x04
#define STACKSHOT_BLOCKER_VMRL_EXCLUSIVE                0x08

#define STACKSHOT_WAITER_VMRL_STREAMING                 0x10
#define STACKSHOT_BLOCKER_VMRL_STREAMING                0x20
#define STACKSHOT_WAITER_VMRL_ATOMIC                    0x40
#define STACKSHOT_BLOCKER_VMRL_ATOMIC                   0x80

typedef struct stackshot_thread_turnstileinfo {
	uint64_t waiter;        /* The thread that's waiting on the object */
	uint64_t turnstile_context; /* Associated data (either thread id, or workq addr) */
	uint8_t turnstile_priority;
	uint8_t number_of_hops;
	uint64_t turnstile_flags;               /* see below */
} __attribute__((packed)) thread_turnstileinfo_t;

typedef struct stackshot_thread_turnstileinfo_v2 {
	uint64_t waiter;        /* The thread that's waiting on the object */
	uint64_t turnstile_context; /* Associated data (either thread id, or workq addr) */
	uint8_t turnstile_priority;
	uint8_t number_of_hops;
#define STACKSHOT_TURNSTILE_STATUS_UNKNOWN         0x01   /* The final inheritor is unknown (bug?) */
#define STACKSHOT_TURNSTILE_STATUS_LOCKED_WAITQ    0x02   /* A waitq was found to be locked */
#define STACKSHOT_TURNSTILE_STATUS_WORKQUEUE       0x04   /* The final inheritor is a workqueue */
#define STACKSHOT_TURNSTILE_STATUS_THREAD          0x08   /* The final inheritor is a thread */
#define STACKSHOT_TURNSTILE_STATUS_BLOCKED_ON_TASK 0x10   /* blocked on task, dind't find thread */
#define STACKSHOT_TURNSTILE_STATUS_HELD_IPLOCK     0x20   /* the ip_lock was held */
#define STACKSHOT_TURNSTILE_STATUS_SENDPORT        0x40   /* port_labelid was from a send port */
#define STACKSHOT_TURNSTILE_STATUS_RECEIVEPORT     0x80   /* port_labelid was from a receive port */
	uint64_t turnstile_flags; // Note: Add any new flags to kcdata.py (turnstile_flags)
	int16_t portlabel_id;   /* matches to a stackshot_portlabel, or NONE or MISSING */
} __attribute__((packed)) thread_turnstileinfo_v2_t;

#define STACKSHOT_TURNSTILE_STATUS_PORTFLAGS (STACKSHOT_TURNSTILE_STATUS_SENDPORT | STACKSHOT_TURNSTILE_STATUS_RECEIVEPORT)

#define STACKSHOT_PORTLABELID_NONE    (0)  /* No port label found */
#define STACKSHOT_PORTLABELID_MISSING (-1) /* portlabel found, but stackshot ran out of space to track it */

#define STACKSHOT_WAITOWNER_KERNEL         (UINT64_MAX - 1)
#define STACKSHOT_WAITOWNER_PORT_LOCKED    (UINT64_MAX - 2)
#define STACKSHOT_WAITOWNER_PSET_LOCKED    (UINT64_MAX - 3)
#define STACKSHOT_WAITOWNER_INTRANSIT      (UINT64_MAX - 4)
#define STACKSHOT_WAITOWNER_MTXSPIN        (UINT64_MAX - 5)
#define STACKSHOT_WAITOWNER_THREQUESTED    (UINT64_MAX - 6) /* workloop waiting for a new worker thread */
#define STACKSHOT_WAITOWNER_SUSPENDED      (UINT64_MAX - 7) /* workloop is suspended */

#define STACKSHOT_PORTLABEL_READFAILED     0x1  /* could not read port information */
#define STACKSHOT_PORTLABEL_THROTTLED      0x2  /* service port is marked as throttled */

struct portlabel_info {
	int16_t portlabel_id;         /* kcdata-specific ID for this port label  */
	uint16_t portlabel_flags;           /* STACKSHOT_PORTLABEL_* */
	uint8_t portlabel_domain;           /* launchd domain */
} __attribute__((packed));

struct stackshot_cpu_architecture {
	int32_t cputype;
	int32_t cpusubtype;
} __attribute__((packed));

struct stack_snapshot_stacktop {
	uint64_t sp;
	uint8_t stack_contents[8];
};

/* only collected if STACKSHOT_COLLECTS_LATENCY_INFO is set to !0 */
struct stackshot_latency_collection {
	uint64_t latency_version;
	uint64_t setup_latency;
	uint64_t total_task_iteration_latency;
	uint64_t total_terminated_task_iteration_latency;
} __attribute__((packed));

/* only collected if STACKSHOT_COLLECTS_LATENCY_INFO is set to !0 */
struct stackshot_latency_collection_v2 {
	uint64_t latency_version;
	uint64_t setup_latency_mt;
	uint64_t total_task_iteration_latency_mt;
	uint64_t total_terminated_task_iteration_latency_mt;
	uint64_t task_queue_building_latency_mt;
	uint64_t terminated_task_queue_building_latency_mt;
	uint64_t cpu_wait_latency_mt;
	int32_t  main_cpu_number;
	int32_t  calling_cpu_number;
	uint64_t buffer_size;
	uint64_t buffer_used;
	uint64_t buffer_overhead;
	uint64_t buffer_count;
} __attribute__((packed));

/* only collected if STACKSHOT_COLLECTS_LATENCY_INFO is set to !0 */
struct stackshot_latency_cpu {
	int32_t  cpu_number;
	int32_t  cluster_type;
	uint64_t init_latency_mt;
	uint64_t workqueue_latency_mt;
	uint64_t total_latency_mt;
	uint64_t total_cycles;
	uint64_t total_instrs;
	uint64_t tasks_processed;
	uint64_t threads_processed;
	uint64_t faulting_time_mt;
	uint64_t total_buf;
	uint64_t intercluster_buf_used;
} __attribute__((packed));

/* only collected if STACKSHOT_COLLECTS_LATENCY_INFO is set to !0 */
struct stackshot_latency_buffer {
	int32_t  cluster_type;
	uint64_t size;
	uint64_t used;
	uint64_t overhead;
} __attribute__ ((packed));

/* only collected if STACKSHOT_COLLECTS_LATENCY_INFO is set to !0 */
struct stackshot_latency_task {
	uint64_t task_uniqueid;
	uint64_t setup_latency;
	uint64_t task_thread_count_loop_latency;
	uint64_t task_thread_data_loop_latency;
	uint64_t cur_tsnap_latency;
	uint64_t pmap_latency;
	uint64_t bsd_proc_ids_latency;
	uint64_t misc_latency;
	uint64_t misc2_latency;
	uint64_t end_latency;
} __attribute__((packed));

/* only collected if STACKSHOT_COLLECTS_LATENCY_INFO is set to !0 */
struct stackshot_latency_thread {
	uint64_t thread_id;
	uint64_t cur_thsnap1_latency;
	uint64_t dispatch_serial_latency;
	uint64_t dispatch_label_latency;
	uint64_t cur_thsnap2_latency;
	uint64_t thread_name_latency;
	uint64_t sur_times_latency;
	uint64_t user_stack_latency;
	uint64_t kernel_stack_latency;
	uint64_t misc_latency;
} __attribute__((packed));

struct stackshot_suspension_info {
	uint64_t tss_last_start; /* mach_absolute_time of beginning of last suspension*/
	uint64_t tss_last_end;   /* mach_absolute_time of end of last suspension */
	uint64_t tss_count;      /* number of times this task has been suspended */
	uint64_t tss_duration;   /* sum(mach_absolute_time) of time spend suspended */
} __attribute__((packed));

struct stackshot_suspension_source {
	uint64_t tss_time;     /* mach_absolute_time of suspend */
	uint64_t tss_tid;      /* tid of suspending thread */
	int tss_pid;           /* pid of suspending task */
	char tss_procname[65]; /* name of suspending task */
} __attribute__((packed));

struct stackshot_device_lock_state {
	uint8_t flags;           /* interpret as a stackshot_device_lock_flags_t */
	uint8_t passcode_status; /* interpret as a passcode_status_t */
	uint8_t lock_state;      /* interpret as a device_lock_state_t */
} __attribute__((packed));

/**************** definitions for exclaves *********************/

enum thread_exclaves_flags : uint32_t {
	kExclaveRPCActive = 0x1,          /* Thread is handling RPC call in secure world */
	kExclaveUpcallActive = 0x2,       /* Thread has upcalled back into xnu while handling RPC */
	kExclaveSchedulerRequest = 0x4,   /* Thread is handling scheduler request */
};

struct thread_exclaves_info {
	uint64_t tei_scid;              /* Scheduling context for exclave IPC stack */
	uint32_t tei_thread_offset;     /* # frames from top of stack exclave frames should be inserted */
	uint32_t tei_flags;             /* A combination of enum thread_exclaves_flags values */
} __attribute__((packed));

struct thread_crash_exclaves_info {
	uint64_t tcei_scid;              /* Scheduling context for exclave IPC stack */
	uint64_t tcei_thread_id;         /* Corresponding xnu thread id */
	uint32_t tcei_flags;             /* A combination of enum thread_exclaves_flags values */
} __attribute__((packed));

enum exclave_scresult_flags : uint64_t {
	kExclaveScresultHaveIPCStack = 0x1,
};

struct exclave_scresult_info {
	uint64_t esc_id;
	uint64_t esc_flags;             /* A combination of enum exclave_scresult_flags values */
} __attribute__((packed));

enum exclave_ipcstackentry_flags : uint64_t {
	kExclaveIpcStackEntryHaveInvocationID = 0x1,
	kExclaveIpcStackEntryHaveStack = 0x2,
};

struct exclave_ipcstackentry_info {
	uint64_t eise_asid;                     /* ASID */
	uint64_t eise_tnid;                     /* Thread numeric ID, may be UINT64_MAX if ommitted */
	uint64_t eise_invocationid;             /* Invocation ID, may be UINT64_MAX if ommitted */
	uint64_t eise_flags;                    /* A combination of enum exclave_ipcstackentry_flags values */
} __attribute__((packed));

typedef uint64_t exclave_ecstackentry_addr_t;

enum exclave_addressspace_flags : uint64_t {
	kExclaveAddressSpaceHaveSlide = 0x1,    /* slide info provided */
};

struct exclave_addressspace_info {
	uint64_t eas_id;                        /* ASID */
	uint64_t eas_flags;                     /* A combination of enum exclave_addressspace_flags values */
	uint64_t eas_layoutid;                  /* textLayout for this address space */
	uint64_t eas_slide;                     /* slide to apply to textlayout, or UINT64_MAX if omitted */
	uint64_t eas_asroot;                    /* ASRoot/TTBR0 value used as an identifier for the address space by cL4 */
} __attribute__((packed));

enum exclave_textlayout_flags : uint64_t {
	kExclaveTextLayoutLoadAddressesSynthetic = 0x1, /* Load Addresses are synthetic */
	kExclaveTextLayoutLoadAddressesUnslid = 0x2, /* Load Addresses are accurate and unslid */
	kExclaveTextLayoutHasSharedCache = 0x4, /* sharedcache_index is valid, refers to entry # in STACKSHOT_KCTYPE_EXCLAVE_TEXTLAYOUT_SEGMENTS array */
};

struct exclave_textlayout_info_v1 {
	uint64_t layout_id;
	uint64_t etl_flags;                     /* A combination of enum exclave_textlayout_flags values */
} __attribute__((packed));

struct exclave_textlayout_info {
	uint64_t layout_id;
	uint64_t etl_flags;                     /* A combination of enum exclave_textlayout_flags values */
	uint32_t sharedcache_index;             /* index in SEGMENTs, or UINT32_MAX */
} __attribute__((packed));

struct exclave_textlayout_segment {
	uuid_t layoutSegment_uuid;
	uint64_t layoutSegment_loadAddress;     /* Synthetic Load Address */
} __attribute__((packed));

struct exclave_textlayout_segment_v2 {
	uuid_t layoutSegment_uuid;
	uint64_t layoutSegment_loadAddress;     /* Synthetic Load Address */
	uint64_t layoutSegment_rawLoadAddress;  /* Raw Load Address when unslided */
} __attribute__((packed));

/**************** definitions for crashinfo *********************/

/*
 * NOTE: Please update kcdata/libkdd/kcdtypes.c if you make any changes
 * in TASK_CRASHINFO_* types.
 */

/* FIXME some of these types aren't clean (fixed width,  packed, and defined *here*) */

struct crashinfo_proc_uniqidentifierinfo {
	uint8_t                 p_uuid[16];             /* UUID of the main executable */
	uint64_t                p_uniqueid;             /* 64 bit unique identifier for process */
	uint64_t                p_puniqueid;            /* unique identifier for process's parent */
	uint64_t                p_reserve2;             /* reserved for future use */
	uint64_t                p_reserve3;             /* reserved for future use */
	uint64_t                p_reserve4;             /* reserved for future use */
} __attribute__((packed));

#define MAX_TRIAGE_STRING_LEN   (128)

struct kernel_triage_info_v1 {
	char triage_string1[MAX_TRIAGE_STRING_LEN];
	char triage_string2[MAX_TRIAGE_STRING_LEN];
	char triage_string3[MAX_TRIAGE_STRING_LEN];
	char triage_string4[MAX_TRIAGE_STRING_LEN];
	char triage_string5[MAX_TRIAGE_STRING_LEN];
} __attribute__((packed));

struct crashinfo_jit_address_range {
	uint64_t start_address;
	uint64_t end_address;
} __attribute__((packed));

struct crashinfo_mb {
	uint64_t start_address;
	uint64_t data[64];
} __attribute__((packed));

struct crashinfo_task_security_config {
	uint32_t task_security_config; /* struct task_security_config */
} __attribute__((packed));

struct crashinfo_voucher {
	uint64_t thread_id;
	uint32_t originator_pid;
	uint32_t proximate_pid;
} __attribute__((packed));

#define MAX_CRASHINFO_SIGNING_ID_LEN 64
#define MAX_CRASHINFO_TEAM_ID_LEN 32
#define MAX_CRASHINFO_SANDBOX_PROFILE_LEN 32

#define TASK_CRASHINFO_BEGIN                KCDATA_BUFFER_BEGIN_CRASHINFO
#define TASK_CRASHINFO_STRING_DESC          KCDATA_TYPE_STRING_DESC
#define TASK_CRASHINFO_UINT32_DESC          KCDATA_TYPE_UINT32_DESC
#define TASK_CRASHINFO_UINT64_DESC          KCDATA_TYPE_UINT64_DESC

#define TASK_CRASHINFO_EXTMODINFO           0x801
#define TASK_CRASHINFO_BSDINFOWITHUNIQID    0x802 /* struct crashinfo_proc_uniqidentifierinfo */
#define TASK_CRASHINFO_TASKDYLD_INFO        0x803
#define TASK_CRASHINFO_UUID                 0x804
#define TASK_CRASHINFO_PID                  0x805
#define TASK_CRASHINFO_PPID                 0x806
#define TASK_CRASHINFO_RUSAGE               0x807  /* struct rusage DEPRECATED do not use.
	                                            *                                                      This struct has longs in it */
#define TASK_CRASHINFO_RUSAGE_INFO          0x808  /* struct rusage_info_v3 from resource.h */
#define TASK_CRASHINFO_PROC_NAME            0x809  /* char * */
#define TASK_CRASHINFO_PROC_STARTTIME       0x80B  /* struct timeval64 */
#define TASK_CRASHINFO_USERSTACK            0x80C  /* uint64_t */
#define TASK_CRASHINFO_ARGSLEN              0x80D
#define TASK_CRASHINFO_EXCEPTION_CODES      0x80E  /* mach_exception_data_t */
#define TASK_CRASHINFO_PROC_PATH            0x80F  /* string of len MAXPATHLEN */
#define TASK_CRASHINFO_PROC_CSFLAGS         0x810  /* uint32_t */
#define TASK_CRASHINFO_PROC_STATUS          0x811  /* char */
#define TASK_CRASHINFO_UID                  0x812  /* uid_t */
#define TASK_CRASHINFO_GID                  0x813  /* gid_t */
#define TASK_CRASHINFO_PROC_ARGC            0x814  /* int */
#define TASK_CRASHINFO_PROC_FLAGS           0x815  /* unsigned int */
#define TASK_CRASHINFO_CPUTYPE              0x816  /* cpu_type_t */
#define TASK_CRASHINFO_WORKQUEUEINFO        0x817  /* struct proc_workqueueinfo */
#define TASK_CRASHINFO_RESPONSIBLE_PID      0x818  /* pid_t */
#define TASK_CRASHINFO_DIRTY_FLAGS          0x819  /* int */
#define TASK_CRASHINFO_CRASHED_THREADID     0x81A  /* uint64_t */
#define TASK_CRASHINFO_COALITION_ID         0x81B  /* uint64_t */
#define TASK_CRASHINFO_UDATA_PTRS           0x81C  /* uint64_t */
#define TASK_CRASHINFO_MEMORY_LIMIT         0x81D  /* uint64_t */

#define TASK_CRASHINFO_LEDGER_INTERNAL                          0x81E /* uint64_t */
#define TASK_CRASHINFO_LEDGER_INTERNAL_COMPRESSED               0x81F /* uint64_t */
#define TASK_CRASHINFO_LEDGER_IOKIT_MAPPED                      0x820 /* uint64_t */
#define TASK_CRASHINFO_LEDGER_ALTERNATE_ACCOUNTING              0x821 /* uint64_t */
#define TASK_CRASHINFO_LEDGER_ALTERNATE_ACCOUNTING_COMPRESSED   0x822 /* uint64_t */
#define TASK_CRASHINFO_LEDGER_PURGEABLE_NONVOLATILE             0x823 /* uint64_t */
#define TASK_CRASHINFO_LEDGER_PURGEABLE_NONVOLATILE_COMPRESSED  0x824 /* uint64_t */
#define TASK_CRASHINFO_LEDGER_PAGE_TABLE                        0x825 /* uint64_t */
#define TASK_CRASHINFO_LEDGER_PHYS_FOOTPRINT                    0x826 /* uint64_t */
#define TASK_CRASHINFO_LEDGER_PHYS_FOOTPRINT_LIFETIME_MAX       0x827 /* uint64_t */
#define TASK_CRASHINFO_LEDGER_NETWORK_NONVOLATILE               0x828 /* uint64_t */
#define TASK_CRASHINFO_LEDGER_NETWORK_NONVOLATILE_COMPRESSED    0x829 /* uint64_t */
#define TASK_CRASHINFO_LEDGER_WIRED_MEM                         0x82A /* uint64_t */
#define TASK_CRASHINFO_PROC_PERSONA_ID                          0x82B /* uid_t */
#define TASK_CRASHINFO_MEMORY_LIMIT_INCREASE                    0x82C /* uint32_t */
#define TASK_CRASHINFO_LEDGER_TAGGED_FOOTPRINT                  0x82D /* uint64_t */
#define TASK_CRASHINFO_LEDGER_TAGGED_FOOTPRINT_COMPRESSED       0x82E /* uint64_t */
#define TASK_CRASHINFO_LEDGER_MEDIA_FOOTPRINT                   0x82F /* uint64_t */
#define TASK_CRASHINFO_LEDGER_MEDIA_FOOTPRINT_COMPRESSED        0x830 /* uint64_t */
#define TASK_CRASHINFO_LEDGER_GRAPHICS_FOOTPRINT                0x831 /* uint64_t */
#define TASK_CRASHINFO_LEDGER_GRAPHICS_FOOTPRINT_COMPRESSED     0x832 /* uint64_t */
#define TASK_CRASHINFO_LEDGER_NEURAL_FOOTPRINT                  0x833 /* uint64_t */
#define TASK_CRASHINFO_LEDGER_NEURAL_FOOTPRINT_COMPRESSED       0x834 /* uint64_t */
#define TASK_CRASHINFO_MEMORYSTATUS_EFFECTIVE_PRIORITY          0x835 /* int32_t */
#define TASK_CRASHINFO_KERNEL_TRIAGE_INFO_V1                    0x836 /* struct kernel_triage_info_v1 */

#define TASK_CRASHINFO_TASK_IS_CORPSE_FORK                      0x837 /* boolean_t */
#define TASK_CRASHINFO_EXCEPTION_TYPE                           0x838 /* int */

#define TASK_CRASHINFO_CRASH_COUNT                              0x839 /* int */
#define TASK_CRASHINFO_THROTTLE_TIMEOUT                         0x83A /* int */

#define TASK_CRASHINFO_CS_SIGNING_ID                            0x83B /* string of len MAX_CRASHINFO_SIGNING_ID_LEN */
#define TASK_CRASHINFO_CS_TEAM_ID                               0x83C /* string of len MAX_CRASHINFO_TEAM_ID_LEN */
#define TASK_CRASHINFO_CS_VALIDATION_CATEGORY                   0x83D /* uint32_t */
#define TASK_CRASHINFO_CS_TRUST_LEVEL                           0x83E /* uint32_t */
#define TASK_CRASHINFO_PROC_CPUTYPE                             0x83F /* cpu_type_t */
#define TASK_CRASHINFO_JIT_ADDRESS_RANGE                        0x840 /* struct crashinfo_jit_address_range */
#define TASK_CRASHINFO_MB                                       0x841 /* struct crashinfo_mb */
#define TASK_CRASHINFO_CS_AUXILIARY_INFO                        0x842 /* uint64_t */
#define TASK_CRASHINFO_RLIM_CORE                                0x843 /* rlim_t */
#define TASK_CRASHINFO_CORE_ALLOWED                             0x844 /* uint8_t */
#define TASK_CRASHINFO_TASK_SECURITY_CONFIG                     0x845 /* struct task_security_config */
#define TASK_CRASHINFO_VOUCHER_INFO                             0x846 /* struct crashinfo_voucher */
#define TASK_CRASHINFO_SANDBOX_PROFILE                          0x847 /* string of len MAX_CRASHINFO_SANDBOX_PROFILE_LEN */

#define TASK_CRASHINFO_END                  KCDATA_TYPE_BUFFER_END

/**************** definitions for backtrace info *********************/

/* tstate is variable length with count elements */
struct btinfo_thread_state_data_t {
	uint32_t flavor;
	uint32_t count;
	int tstate[];
};

struct btinfo_sc_load_info64 {
	uint64_t sharedCacheSlide;
	uuid_t   sharedCacheUUID;
	uint64_t sharedCacheBaseAddress;
};

struct btinfo_sc_load_info {
	uint32_t sharedCacheSlide;
	uuid_t   sharedCacheUUID;
	uint32_t sharedCacheBaseAddress;
};

#define TASK_BTINFO_BEGIN                                       KCDATA_BUFFER_BEGIN_BTINFO

/* Shared keys with CRASHINFO */
#define TASK_BTINFO_PID                                         0xA01
#define TASK_BTINFO_PPID                                        0xA02
#define TASK_BTINFO_PROC_NAME                                   0xA03
#define TASK_BTINFO_PROC_PATH                                   0xA04
#define TASK_BTINFO_UID                                         0xA05
#define TASK_BTINFO_GID                                         0xA06
#define TASK_BTINFO_PROC_FLAGS                                  0xA07
#define TASK_BTINFO_CPUTYPE                                     0xA08
#define TASK_BTINFO_EXCEPTION_CODES                             0xA09
#define TASK_BTINFO_EXCEPTION_TYPE                              0xA0A
#define TASK_BTINFO_RUSAGE_INFO                                 0xA0B
#define TASK_BTINFO_COALITION_ID                                0xA0C
#define TASK_BTINFO_CRASH_COUNT                                 0xA0D
#define TASK_BTINFO_THROTTLE_TIMEOUT                            0xA0E

/* Only in BTINFO */
#define TASK_BTINFO_THREAD_ID                                   0xA20 /* uint64_t */
#define TASK_BTINFO_THREAD_NAME                                 0xA21 /* string of len MAXTHREADNAMESIZE */
#define TASK_BTINFO_THREAD_STATE                                0xA22 /* struct btinfo_thread_state_data_t */
#define TASK_BTINFO_THREAD_EXCEPTION_STATE                      0xA23 /* struct btinfo_thread_state_data_t */
#define TASK_BTINFO_BACKTRACE                                   0xA24 /* array of uintptr_t */
#define TASK_BTINFO_BACKTRACE64                                 0xA25 /* array of uintptr_t */
#define TASK_BTINFO_ASYNC_BACKTRACE64                           0xA26 /* array of uintptr_t */
#define TASK_BTINFO_ASYNC_START_INDEX                           0xA27 /* uint32_t */
#define TASK_BTINFO_PLATFORM                                    0xA28 /* uint32_t */
#define TASK_BTINFO_SC_LOADINFO                                 0xA29 /* struct btinfo_sc_load_info */
#define TASK_BTINFO_SC_LOADINFO64                               0xA2A /* struct btinfo_sc_load_info64 */

#define TASK_BTINFO_DYLD_LOADINFO                               KCDATA_TYPE_LIBRARY_LOADINFO
#define TASK_BTINFO_DYLD_LOADINFO64                             KCDATA_TYPE_LIBRARY_LOADINFO64

/* Last one */
#define TASK_BTINFO_FLAGS                                       0xAFF /* uint32_t */
#define TASK_BTINFO_FLAG_BT_TRUNCATED                           0x1
#define TASK_BTINFO_FLAG_ASYNC_BT_TRUNCATED                     0x2
#define TASK_BTINFO_FLAG_TASK_TERMINATED                        0x4 /* task is terminated */
#define TASK_BTINFO_FLAG_KCDATA_INCOMPLETE                      0x8 /* lw corpse collection is incomplete */

#define TASK_BTINFO_END                                         KCDATA_TYPE_BUFFER_END

/**************** definitions for os reasons *********************/

#define EXIT_REASON_SNAPSHOT            0x1001
#define EXIT_REASON_USER_DESC           0x1002 /* string description of reason */
#define EXIT_REASON_USER_PAYLOAD        0x1003 /* user payload data */
#define EXIT_REASON_CODESIGNING_INFO    0x1004
#define EXIT_REASON_WORKLOOP_ID         0x1005
#define EXIT_REASON_DISPATCH_QUEUE_NO   0x1006

struct exit_reason_snapshot {
	uint32_t ers_namespace;
	uint64_t ers_code;
	/* end of version 1 of exit_reason_snapshot. sizeof v1 was 12 */
	uint64_t ers_flags;
} __attribute__((packed));

#define EXIT_REASON_CODESIG_PATH_MAX    1024

struct codesigning_exit_reason_info {
	uint64_t  ceri_virt_addr;
	uint64_t  ceri_file_offset;
	char      ceri_pathname[EXIT_REASON_CODESIG_PATH_MAX];
	char      ceri_filename[EXIT_REASON_CODESIG_PATH_MAX];
	uint64_t  ceri_codesig_modtime_secs;
	uint64_t  ceri_codesig_modtime_nsecs;
	uint64_t  ceri_page_modtime_secs;
	uint64_t  ceri_page_modtime_nsecs;
	uint8_t   ceri_path_truncated;
	uint8_t   ceri_object_codesigned;
	uint8_t   ceri_page_codesig_validated;
	uint8_t   ceri_page_codesig_tainted;
	uint8_t   ceri_page_codesig_nx;
	uint8_t   ceri_page_wpmapped;
	uint8_t   ceri_page_slid;
	uint8_t   ceri_page_dirty;
	uint32_t  ceri_page_shadow_depth;
} __attribute__((packed));

#define EXIT_REASON_USER_DESC_MAX_LEN   1024
#define EXIT_REASON_PAYLOAD_MAX_LEN     2048
/**************** safe iterators *********************/
#if !__has_ptrcheck

typedef struct kcdata_iter {
	kcdata_item_t item;
	void *end;
} kcdata_iter_t;


static inline
kcdata_iter_t
kcdata_iter(void *buffer, unsigned long size)
{
	kcdata_iter_t iter;
	iter.item = (kcdata_item_t) buffer;
	iter.end = (void*) (((uintptr_t)buffer) + size);
	return iter;
}

static inline
kcdata_iter_t kcdata_iter_unsafe(void *buffer) __attribute__((deprecated));

static inline
kcdata_iter_t
kcdata_iter_unsafe(void *buffer)
{
	kcdata_iter_t iter;
	iter.item = (kcdata_item_t) buffer;
	iter.end = (void*) (uintptr_t) ~0;
	return iter;
}

static const kcdata_iter_t kcdata_invalid_iter = { .item = NULL, .end = NULL };

static inline
int
kcdata_iter_valid(kcdata_iter_t iter)
{
	return
	        ((uintptr_t)iter.item + sizeof(struct kcdata_item) <= (uintptr_t)iter.end) &&
	        ((uintptr_t)iter.item + sizeof(struct kcdata_item) + iter.item->size <= (uintptr_t)iter.end);
}


static inline
kcdata_iter_t
kcdata_iter_next(kcdata_iter_t iter)
{
	iter.item = (kcdata_item_t) (((uintptr_t)iter.item) + sizeof(struct kcdata_item) + (iter.item->size));
	return iter;
}

static inline uint32_t
kcdata_iter_type(kcdata_iter_t iter)
{
	if ((iter.item->type & ~0xfu) == KCDATA_TYPE_ARRAY_PAD0) {
		return KCDATA_TYPE_ARRAY;
	} else {
		return iter.item->type;
	}
}

static inline uint32_t
kcdata_calc_padding(uint32_t size)
{
	/* calculate number of bytes to add to size to get something divisible by 16 */
	return (-size) & 0xf;
}

static inline uint32_t
kcdata_flags_get_padding(uint64_t flags)
{
	return flags & KCDATA_FLAGS_STRUCT_PADDING_MASK;
}

/* see comment above about has_padding */
static inline int
kcdata_iter_is_legacy_item(kcdata_iter_t iter, uint32_t legacy_size)
{
	uint32_t legacy_size_padded = legacy_size + kcdata_calc_padding(legacy_size);
	return iter.item->size == legacy_size_padded &&
	       (iter.item->flags & (KCDATA_FLAGS_STRUCT_PADDING_MASK | KCDATA_FLAGS_STRUCT_HAS_PADDING)) == 0;
}

static inline uint32_t
kcdata_iter_size(kcdata_iter_t iter)
{
	uint32_t legacy_size = 0;

	switch (kcdata_iter_type(iter)) {
	case KCDATA_TYPE_ARRAY:
	case KCDATA_TYPE_CONTAINER_BEGIN:
		return iter.item->size;
	case STACKSHOT_KCTYPE_THREAD_SNAPSHOT: {
		legacy_size = sizeof(struct thread_snapshot_v2);
		if (kcdata_iter_is_legacy_item(iter, legacy_size)) {
			return legacy_size;
		}

		goto not_legacy;
	}
	case STACKSHOT_KCTYPE_SHAREDCACHE_LOADINFO: {
		legacy_size = sizeof(struct dyld_uuid_info_64);
		if (kcdata_iter_is_legacy_item(iter, legacy_size)) {
			return legacy_size;
		}

		goto not_legacy;
	}
not_legacy:
	default:
		if (iter.item->size < kcdata_flags_get_padding(iter.item->flags)) {
			return 0;
		} else {
			return iter.item->size - kcdata_flags_get_padding(iter.item->flags);
		}
	}
}

static inline uint64_t
kcdata_iter_flags(kcdata_iter_t iter)
{
	return iter.item->flags;
}

static inline
void *
kcdata_iter_payload(kcdata_iter_t iter)
{
	return &iter.item->data;
}


static inline
uint32_t
kcdata_iter_array_elem_type(kcdata_iter_t iter)
{
	return (iter.item->flags >> 32) & UINT32_MAX;
}

static inline
uint32_t
kcdata_iter_array_elem_count(kcdata_iter_t iter)
{
	return (iter.item->flags) & UINT32_MAX;
}

/* KCDATA_TYPE_ARRAY is ambiguous about the size of the array elements.  Size is
 * calculated as total_size / elements_count, but total size got padded out to a
 * 16 byte alignment.  New kernels will generate KCDATA_TYPE_ARRAY_PAD* instead
 * to explicitly tell us how much padding was used.  Here we have a fixed, never
 * to be altered list of the sizes of array elements that were used before I
 * discovered this issue.  If you find a KCDATA_TYPE_ARRAY that is not one of
 * these types, treat it as invalid data. */

static inline
uint32_t
kcdata_iter_array_size_switch(kcdata_iter_t iter)
{
	switch (kcdata_iter_array_elem_type(iter)) {
	case KCDATA_TYPE_LIBRARY_LOADINFO:
		return sizeof(struct dyld_uuid_info_32);
	case KCDATA_TYPE_LIBRARY_LOADINFO64:
		return sizeof(struct dyld_uuid_info_64);
	case STACKSHOT_KCTYPE_KERN_STACKFRAME:
	case STACKSHOT_KCTYPE_USER_STACKFRAME:
		return sizeof(struct stack_snapshot_frame32);
	case STACKSHOT_KCTYPE_KERN_STACKFRAME64:
	case STACKSHOT_KCTYPE_USER_STACKFRAME64:
		return sizeof(struct stack_snapshot_frame64);
	case STACKSHOT_KCTYPE_DONATING_PIDS:
		return sizeof(int32_t);
	case STACKSHOT_KCTYPE_THREAD_DELTA_SNAPSHOT:
		return sizeof(struct thread_delta_snapshot_v2);
	// This one is only here to make some unit tests work. It should be OK to
	// remove.
	case TASK_CRASHINFO_CRASHED_THREADID:
		return sizeof(uint64_t);
	default:
		return 0;
	}
}

static inline
int
kcdata_iter_array_valid(kcdata_iter_t iter)
{
	if (!kcdata_iter_valid(iter)) {
		return 0;
	}
	if (kcdata_iter_type(iter) != KCDATA_TYPE_ARRAY) {
		return 0;
	}
	if (kcdata_iter_array_elem_count(iter) == 0) {
		return iter.item->size == 0;
	}
	if (iter.item->type == KCDATA_TYPE_ARRAY) {
		uint32_t elem_size = kcdata_iter_array_size_switch(iter);
		if (elem_size == 0) {
			return 0;
		}
		/* sizes get aligned to the nearest 16. */
		return
		        kcdata_iter_array_elem_count(iter) <= iter.item->size / elem_size &&
		        iter.item->size % kcdata_iter_array_elem_count(iter) < 16;
	} else {
		return
		        (iter.item->type & 0xf) <= iter.item->size &&
		        kcdata_iter_array_elem_count(iter) <= iter.item->size - (iter.item->type & 0xf) &&
		        (iter.item->size - (iter.item->type & 0xf)) % kcdata_iter_array_elem_count(iter) == 0;
	}
}


static inline
uint32_t
kcdata_iter_array_elem_size(kcdata_iter_t iter)
{
	if (iter.item->type == KCDATA_TYPE_ARRAY) {
		return kcdata_iter_array_size_switch(iter);
	}
	if (kcdata_iter_array_elem_count(iter) == 0) {
		return 0;
	}
	return (iter.item->size - (iter.item->type & 0xf)) / kcdata_iter_array_elem_count(iter);
}

static inline
int
kcdata_iter_container_valid(kcdata_iter_t iter)
{
	return
	        kcdata_iter_valid(iter) &&
	        kcdata_iter_type(iter) == KCDATA_TYPE_CONTAINER_BEGIN &&
	        iter.item->size >= sizeof(uint32_t);
}

static inline
uint32_t
kcdata_iter_container_type(kcdata_iter_t iter)
{
	return *(uint32_t *) kcdata_iter_payload(iter);
}

static inline
uint64_t
kcdata_iter_container_id(kcdata_iter_t iter)
{
	return iter.item->flags;
}


#define KCDATA_ITER_FOREACH(iter) for(; kcdata_iter_valid(iter) && iter.item->type != KCDATA_TYPE_BUFFER_END; iter = kcdata_iter_next(iter))
#define KCDATA_ITER_FOREACH_FAILED(iter) (!kcdata_iter_valid(iter) || (iter).item->type != KCDATA_TYPE_BUFFER_END)

static inline
kcdata_iter_t
kcdata_iter_find_type(kcdata_iter_t iter, uint32_t type)
{
	KCDATA_ITER_FOREACH(iter)
	{
		if (kcdata_iter_type(iter) == type) {
			return iter;
		}
	}
	return kcdata_invalid_iter;
}

static inline
int
kcdata_iter_data_with_desc_valid(kcdata_iter_t iter, uint32_t minsize)
{
	return
	        kcdata_iter_valid(iter) &&
	        kcdata_iter_size(iter) >= KCDATA_DESC_MAXLEN + minsize &&
	        ((char*)kcdata_iter_payload(iter))[KCDATA_DESC_MAXLEN - 1] == 0;
}

static inline
char *
kcdata_iter_string(kcdata_iter_t iter, uint32_t offset)
{
	if (offset > kcdata_iter_size(iter)) {
		return NULL;
	}
	uint32_t maxlen = kcdata_iter_size(iter) - offset;
	char *s = ((char*)kcdata_iter_payload(iter)) + offset;
	if (strnlen(s, maxlen) < maxlen) {
		return s;
	} else {
		return NULL;
	}
}

static inline void
kcdata_iter_get_data_with_desc(kcdata_iter_t iter, char **desc_ptr, void **data_ptr, uint32_t *size_ptr)
{
	if (desc_ptr) {
		*desc_ptr = (char *)kcdata_iter_payload(iter);
	}
	if (data_ptr) {
		*data_ptr = (void *)((uintptr_t)kcdata_iter_payload(iter) + KCDATA_DESC_MAXLEN);
	}
	if (size_ptr) {
		*size_ptr = kcdata_iter_size(iter) - KCDATA_DESC_MAXLEN;
	}
}

#endif /* !__has_ptrcheck */
#endif