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 | /* * 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)); * * Make it look like this: * * struct foobar { * uint32_t baz; * uint32_t quux; * ///////// end version 1 of foobar. 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_corpses.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)); * */ #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 emmitted 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_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_DELTA_STACKSHOT 0xDE17A59Au /* owner: sys/stackshot.h */ /* type-range: 0x940 - 0x9ff */ #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 */ #define STACKSHOT_KCCONTAINER_TASK 0x903u #define STACKSHOT_KCCONTAINER_THREAD 0x904u #define STACKSHOT_KCTYPE_TASK_SNAPSHOT 0x905u /* task_snapshot_v2 */ #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 /* same as KCDATA_TYPE_LIBRARY_LOADINFO64 */ #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 */ #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_TASK_DELTA_SNAPSHOT 0x940u /* task_delta_snapshot_v2 */ #define STACKSHOT_KCTYPE_THREAD_DELTA_SNAPSHOT 0x941u /* thread_delta_snapshot_v* */ #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 */ #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 or thread_group_snapshot_v2 */ #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_INSTRS_CYCLES 0x923u /* struct instrs_cycles_snapshot */ #define STACKSHOT_KCTYPE_THREAD_POLICY_VERSION 0x922u /* THREAD_POLICY_INTERNAL_STRUCT_VERSION in uint32 */ 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; }; 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 of image */ }; 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 */ }; enum task_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 */ }; enum thread_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 */ }; 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)); /* 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)); enum thread_group_flags { kThreadGroupEfficient = 0x1, kThreadGroupUIApp = 0x2 }; struct thread_group_snapshot_v2 { uint64_t tgs_id; char tgs_name[16]; uint64_t tgs_flags; } __attribute__((packed)); enum coalition_flags { kCoalitionTermRequested = 0x1, kCoalitionTerminated = 0x2, kCoalitionReaped = 0x4, kCoalitionPrivileged = 0x8, }; 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 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_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 stackshot_cpu_times { uint64_t user_usec; uint64_t system_usec; } __attribute__((packed)); struct stackshot_duration { uint64_t stackshot_duration; uint64_t stackshot_duration_outer; } __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; #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 */ /**************** 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 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_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 *********************/ 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 = 0, .end = 0 }; 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 bits 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 |