1*94d3b452SApple OSS Distributions#include <darwintest.h> 2*94d3b452SApple OSS Distributions#include <darwintest_utils.h> 3*94d3b452SApple OSS Distributions#include <darwintest_multiprocess.h> 4*94d3b452SApple OSS Distributions#include <kern/debug.h> 5*94d3b452SApple OSS Distributions#include <kern/kern_cdata.h> 6*94d3b452SApple OSS Distributions#include <kern/block_hint.h> 7*94d3b452SApple OSS Distributions#include <kdd.h> 8*94d3b452SApple OSS Distributions#include <libproc.h> 9*94d3b452SApple OSS Distributions#include <os/atomic_private.h> 10*94d3b452SApple OSS Distributions#include <mach-o/dyld.h> 11*94d3b452SApple OSS Distributions#include <mach-o/dyld_images.h> 12*94d3b452SApple OSS Distributions#include <mach-o/dyld_priv.h> 13*94d3b452SApple OSS Distributions#include <sys/syscall.h> 14*94d3b452SApple OSS Distributions#include <sys/stackshot.h> 15*94d3b452SApple OSS Distributions#include <uuid/uuid.h> 16*94d3b452SApple OSS Distributions#include <servers/bootstrap.h> 17*94d3b452SApple OSS Distributions#include <pthread/workqueue_private.h> 18*94d3b452SApple OSS Distributions#include <dispatch/private.h> 19*94d3b452SApple OSS Distributions#include <stdalign.h> 20*94d3b452SApple OSS Distributions 21*94d3b452SApple OSS Distributions#import <zlib.h> 22*94d3b452SApple OSS Distributions#import <IOKit/IOKitLib.h> 23*94d3b452SApple OSS Distributions#import <IOKit/IOKitLibPrivate.h> 24*94d3b452SApple OSS Distributions#import <IOKit/IOKitKeysPrivate.h> 25*94d3b452SApple OSS Distributions 26*94d3b452SApple OSS Distributions 27*94d3b452SApple OSS Distributions 28*94d3b452SApple OSS DistributionsT_GLOBAL_META( 29*94d3b452SApple OSS Distributions T_META_NAMESPACE("xnu.stackshot"), 30*94d3b452SApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"), 31*94d3b452SApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("stackshot"), 32*94d3b452SApple OSS Distributions T_META_OWNER("jonathan_w_adams"), 33*94d3b452SApple OSS Distributions T_META_CHECK_LEAKS(false), 34*94d3b452SApple OSS Distributions T_META_ASROOT(true) 35*94d3b452SApple OSS Distributions ); 36*94d3b452SApple OSS Distributions 37*94d3b452SApple OSS Distributionsstatic const char *current_process_name(void); 38*94d3b452SApple OSS Distributionsstatic void verify_stackshot_sharedcache_layout(struct dyld_uuid_info_64 *uuids, uint32_t uuid_count); 39*94d3b452SApple OSS Distributionsstatic void parse_stackshot(uint64_t stackshot_parsing_flags, void *ssbuf, size_t sslen, NSDictionary *extra); 40*94d3b452SApple OSS Distributionsstatic void parse_thread_group_stackshot(void **sbuf, size_t sslen); 41*94d3b452SApple OSS Distributionsstatic uint64_t stackshot_timestamp(void *ssbuf, size_t sslen); 42*94d3b452SApple OSS Distributionsstatic void initialize_thread(void); 43*94d3b452SApple OSS Distributions 44*94d3b452SApple OSS Distributionsstatic uint64_t global_flags = 0; 45*94d3b452SApple OSS Distributions 46*94d3b452SApple OSS Distributions#define DEFAULT_STACKSHOT_BUFFER_SIZE (1024 * 1024) 47*94d3b452SApple OSS Distributions#define MAX_STACKSHOT_BUFFER_SIZE (6 * 1024 * 1024) 48*94d3b452SApple OSS Distributions 49*94d3b452SApple OSS Distributions#define SRP_SERVICE_NAME "com.apple.xnu.test.stackshot.special_reply_port" 50*94d3b452SApple OSS Distributions 51*94d3b452SApple OSS Distributions/* bit flags for parse_stackshot */ 52*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_DELTA 0x01 53*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_ZOMBIE 0x02 54*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_SHAREDCACHE_LAYOUT 0x04 55*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_DISPATCH_QUEUE_LABEL 0x08 56*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_TURNSTILEINFO 0x10 57*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_POSTEXEC 0x20 58*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_WAITINFO_CSEG 0x40 59*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_WAITINFO_SRP 0x80 60*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_TRANSLATED 0x100 61*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_SHAREDCACHE_FLAGS 0x200 62*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_EXEC_INPROGRESS 0x400 63*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_TRANSITIONING 0x800 64*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_ASYNCSTACK 0x1000 65*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_COMPACTINFO 0x2000 /* TODO: rdar://88789261 */ 66*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_DRIVERKIT 0x4000 67*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_THROTTLED_SP 0x8000 68*94d3b452SApple OSS Distributions#define PARSE_STACKSHOT_SUSPENDINFO 0x10000 69*94d3b452SApple OSS Distributions 70*94d3b452SApple OSS Distributions/* keys for 'extra' dictionary for parse_stackshot */ 71*94d3b452SApple OSS Distributionsstatic const NSString* zombie_child_pid_key = @"zombie_child_pid"; // -> @(pid), required for PARSE_STACKSHOT_ZOMBIE 72*94d3b452SApple OSS Distributionsstatic const NSString* postexec_child_unique_pid_key = @"postexec_child_unique_pid"; // -> @(unique_pid), required for PARSE_STACKSHOT_POSTEXEC 73*94d3b452SApple OSS Distributionsstatic const NSString* cseg_expected_threadid_key = @"cseg_expected_threadid"; // -> @(tid), required for PARSE_STACKSHOT_WAITINFO_CSEG 74*94d3b452SApple OSS Distributionsstatic const NSString* srp_expected_threadid_key = @"srp_expected_threadid"; // -> @(tid), this or ..._pid required for PARSE_STACKSHOT_WAITINFO_SRP 75*94d3b452SApple OSS Distributionsstatic const NSString* srp_expected_pid_key = @"srp_expected_pid"; // -> @(pid), this or ..._threadid required for PARSE_STACKSHOT_WAITINFO_SRP 76*94d3b452SApple OSS Distributionsstatic const NSString* translated_child_pid_key = @"translated_child_pid"; // -> @(pid), required for PARSE_STACKSHOT_TRANSLATED 77*94d3b452SApple OSS Distributionsstatic const NSString* sharedcache_child_pid_key = @"sharedcache_child_pid"; // @(pid), required for PARSE_STACKSHOT_SHAREDCACHE_FLAGS 78*94d3b452SApple OSS Distributionsstatic const NSString* sharedcache_child_sameaddr_key = @"sharedcache_child_sameaddr"; // @(0 or 1), required for PARSE_STACKSHOT_SHAREDCACHE_FLAGS 79*94d3b452SApple OSS Distributionsstatic const NSString* exec_inprogress_pid_key = @"exec_inprogress_pid"; 80*94d3b452SApple OSS Distributionsstatic const NSString* exec_inprogress_found_key = @"exec_inprogress_found"; // callback when inprogress is found 81*94d3b452SApple OSS Distributionsstatic const NSString* transitioning_pid_key = @"transitioning_task_pid"; // -> @(pid), required for PARSE_STACKSHOT_TRANSITIONING 82*94d3b452SApple OSS Distributionsstatic const NSString* asyncstack_expected_threadid_key = @"asyncstack_expected_threadid"; // -> @(tid), required for PARSE_STACKSHOT_ASYNCSTACK 83*94d3b452SApple OSS Distributionsstatic const NSString* asyncstack_expected_stack_key = @"asyncstack_expected_stack"; // -> @[pc...]), expected PCs for asyncstack 84*94d3b452SApple OSS Distributionsstatic const NSString* driverkit_found_key = @"driverkit_found_key"; // callback when driverkit process is found. argument is the process pid. 85*94d3b452SApple OSS Distributionsstatic const NSString* sp_throttled_expected_ctxt_key = @"sp_throttled_expected_ctxt_key"; // -> @(ctxt), required for PARSE_STACKSHOT_THROTTLED_SP 86*94d3b452SApple OSS Distributionsstatic const NSString* sp_throttled_expect_flag = @"sp_throttled_expect_flag"; // -> @(is_throttled), required for PARSE_STACKSHOT_THROTTLED_SP 87*94d3b452SApple OSS Distributions 88*94d3b452SApple OSS Distributions#define TEST_STACKSHOT_QUEUE_LABEL "houston.we.had.a.problem" 89*94d3b452SApple OSS Distributions#define TEST_STACKSHOT_QUEUE_LABEL_LENGTH sizeof(TEST_STACKSHOT_QUEUE_LABEL) 90*94d3b452SApple OSS Distributions 91*94d3b452SApple OSS Distributions#define THROTTLED_SERVICE_NAME "com.apple.xnu.test.stackshot.throttled_service" 92*94d3b452SApple OSS Distributions 93*94d3b452SApple OSS DistributionsT_DECL(microstackshots, "test the microstackshot syscall") 94*94d3b452SApple OSS Distributions{ 95*94d3b452SApple OSS Distributions void *buf = NULL; 96*94d3b452SApple OSS Distributions unsigned int size = DEFAULT_STACKSHOT_BUFFER_SIZE; 97*94d3b452SApple OSS Distributions 98*94d3b452SApple OSS Distributions while (1) { 99*94d3b452SApple OSS Distributions buf = malloc(size); 100*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(buf, "allocated stackshot buffer"); 101*94d3b452SApple OSS Distributions 102*94d3b452SApple OSS Distributions#pragma clang diagnostic push 103*94d3b452SApple OSS Distributions#pragma clang diagnostic ignored "-Wdeprecated-declarations" 104*94d3b452SApple OSS Distributions int len = syscall(SYS_microstackshot, buf, size, 105*94d3b452SApple OSS Distributions (uint32_t) STACKSHOT_GET_MICROSTACKSHOT); 106*94d3b452SApple OSS Distributions#pragma clang diagnostic pop 107*94d3b452SApple OSS Distributions if (len == ENOSYS) { 108*94d3b452SApple OSS Distributions T_SKIP("microstackshot syscall failed, likely not compiled with CONFIG_TELEMETRY"); 109*94d3b452SApple OSS Distributions } 110*94d3b452SApple OSS Distributions if (len == -1 && errno == ENOSPC) { 111*94d3b452SApple OSS Distributions /* syscall failed because buffer wasn't large enough, try again */ 112*94d3b452SApple OSS Distributions free(buf); 113*94d3b452SApple OSS Distributions buf = NULL; 114*94d3b452SApple OSS Distributions size *= 2; 115*94d3b452SApple OSS Distributions T_ASSERT_LE(size, (unsigned int)MAX_STACKSHOT_BUFFER_SIZE, 116*94d3b452SApple OSS Distributions "growing stackshot buffer to sane size"); 117*94d3b452SApple OSS Distributions continue; 118*94d3b452SApple OSS Distributions } 119*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(len, "called microstackshot syscall"); 120*94d3b452SApple OSS Distributions break; 121*94d3b452SApple OSS Distributions } 122*94d3b452SApple OSS Distributions 123*94d3b452SApple OSS Distributions T_EXPECT_EQ(*(uint32_t *)buf, 124*94d3b452SApple OSS Distributions (uint32_t)STACKSHOT_MICRO_SNAPSHOT_MAGIC, 125*94d3b452SApple OSS Distributions "magic value for microstackshot matches"); 126*94d3b452SApple OSS Distributions 127*94d3b452SApple OSS Distributions free(buf); 128*94d3b452SApple OSS Distributions} 129*94d3b452SApple OSS Distributions 130*94d3b452SApple OSS Distributionsstruct scenario { 131*94d3b452SApple OSS Distributions const char *name; 132*94d3b452SApple OSS Distributions uint64_t flags; 133*94d3b452SApple OSS Distributions bool quiet; 134*94d3b452SApple OSS Distributions bool should_fail; 135*94d3b452SApple OSS Distributions bool maybe_unsupported; 136*94d3b452SApple OSS Distributions bool maybe_enomem; 137*94d3b452SApple OSS Distributions bool no_recordfile; 138*94d3b452SApple OSS Distributions pid_t target_pid; 139*94d3b452SApple OSS Distributions bool target_kernel; 140*94d3b452SApple OSS Distributions uint64_t since_timestamp; 141*94d3b452SApple OSS Distributions uint32_t size_hint; 142*94d3b452SApple OSS Distributions dt_stat_time_t timer; 143*94d3b452SApple OSS Distributions}; 144*94d3b452SApple OSS Distributions 145*94d3b452SApple OSS Distributionsstatic void 146*94d3b452SApple OSS Distributionsquiet(struct scenario *scenario) 147*94d3b452SApple OSS Distributions{ 148*94d3b452SApple OSS Distributions if (scenario->timer || scenario->quiet) { 149*94d3b452SApple OSS Distributions T_QUIET; 150*94d3b452SApple OSS Distributions } 151*94d3b452SApple OSS Distributions} 152*94d3b452SApple OSS Distributions 153*94d3b452SApple OSS Distributionsstatic void 154*94d3b452SApple OSS Distributionstake_stackshot(struct scenario *scenario, bool compress_ok, void (^cb)(void *buf, size_t size)) 155*94d3b452SApple OSS Distributions{ 156*94d3b452SApple OSS Distributionsstart: 157*94d3b452SApple OSS Distributions initialize_thread(); 158*94d3b452SApple OSS Distributions 159*94d3b452SApple OSS Distributions void *config = stackshot_config_create(); 160*94d3b452SApple OSS Distributions quiet(scenario); 161*94d3b452SApple OSS Distributions T_ASSERT_NOTNULL(config, "created stackshot config"); 162*94d3b452SApple OSS Distributions 163*94d3b452SApple OSS Distributions int ret = stackshot_config_set_flags(config, scenario->flags | global_flags); 164*94d3b452SApple OSS Distributions quiet(scenario); 165*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(ret, "set flags %#llx on stackshot config", scenario->flags); 166*94d3b452SApple OSS Distributions 167*94d3b452SApple OSS Distributions if (scenario->size_hint > 0) { 168*94d3b452SApple OSS Distributions ret = stackshot_config_set_size_hint(config, scenario->size_hint); 169*94d3b452SApple OSS Distributions quiet(scenario); 170*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(ret, "set size hint %" PRIu32 " on stackshot config", 171*94d3b452SApple OSS Distributions scenario->size_hint); 172*94d3b452SApple OSS Distributions } 173*94d3b452SApple OSS Distributions 174*94d3b452SApple OSS Distributions if (scenario->target_pid > 0) { 175*94d3b452SApple OSS Distributions ret = stackshot_config_set_pid(config, scenario->target_pid); 176*94d3b452SApple OSS Distributions quiet(scenario); 177*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(ret, "set target pid %d on stackshot config", 178*94d3b452SApple OSS Distributions scenario->target_pid); 179*94d3b452SApple OSS Distributions } else if (scenario->target_kernel) { 180*94d3b452SApple OSS Distributions ret = stackshot_config_set_pid(config, 0); 181*94d3b452SApple OSS Distributions quiet(scenario); 182*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(ret, "set kernel target on stackshot config"); 183*94d3b452SApple OSS Distributions } 184*94d3b452SApple OSS Distributions 185*94d3b452SApple OSS Distributions if (scenario->since_timestamp > 0) { 186*94d3b452SApple OSS Distributions ret = stackshot_config_set_delta_timestamp(config, scenario->since_timestamp); 187*94d3b452SApple OSS Distributions quiet(scenario); 188*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(ret, "set since timestamp %" PRIu64 " on stackshot config", 189*94d3b452SApple OSS Distributions scenario->since_timestamp); 190*94d3b452SApple OSS Distributions } 191*94d3b452SApple OSS Distributions 192*94d3b452SApple OSS Distributions int retries_remaining = 5; 193*94d3b452SApple OSS Distributions 194*94d3b452SApple OSS Distributionsretry: ; 195*94d3b452SApple OSS Distributions uint64_t start_time = mach_absolute_time(); 196*94d3b452SApple OSS Distributions ret = stackshot_capture_with_config(config); 197*94d3b452SApple OSS Distributions uint64_t end_time = mach_absolute_time(); 198*94d3b452SApple OSS Distributions 199*94d3b452SApple OSS Distributions if (scenario->should_fail) { 200*94d3b452SApple OSS Distributions T_EXPECTFAIL; 201*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(ret, "called stackshot_capture_with_config"); 202*94d3b452SApple OSS Distributions return; 203*94d3b452SApple OSS Distributions } 204*94d3b452SApple OSS Distributions 205*94d3b452SApple OSS Distributions if (ret == EBUSY || ret == ETIMEDOUT) { 206*94d3b452SApple OSS Distributions if (retries_remaining > 0) { 207*94d3b452SApple OSS Distributions if (!scenario->timer) { 208*94d3b452SApple OSS Distributions T_LOG("stackshot_capture_with_config failed with %s (%d), retrying", 209*94d3b452SApple OSS Distributions strerror(ret), ret); 210*94d3b452SApple OSS Distributions } 211*94d3b452SApple OSS Distributions 212*94d3b452SApple OSS Distributions retries_remaining--; 213*94d3b452SApple OSS Distributions goto retry; 214*94d3b452SApple OSS Distributions } else { 215*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(ret, 216*94d3b452SApple OSS Distributions "called stackshot_capture_with_config (no retries remaining)"); 217*94d3b452SApple OSS Distributions } 218*94d3b452SApple OSS Distributions } else if ((ret == ENOTSUP) && scenario->maybe_unsupported) { 219*94d3b452SApple OSS Distributions T_SKIP("kernel indicated this stackshot configuration is not supported"); 220*94d3b452SApple OSS Distributions } else if ((ret == ENOMEM) && scenario->maybe_enomem) { 221*94d3b452SApple OSS Distributions T_SKIP("insufficient available memory to run test"); 222*94d3b452SApple OSS Distributions } else { 223*94d3b452SApple OSS Distributions quiet(scenario); 224*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(ret, "called stackshot_capture_with_config"); 225*94d3b452SApple OSS Distributions } 226*94d3b452SApple OSS Distributions 227*94d3b452SApple OSS Distributions if (scenario->timer) { 228*94d3b452SApple OSS Distributions dt_stat_mach_time_add(scenario->timer, end_time - start_time); 229*94d3b452SApple OSS Distributions } 230*94d3b452SApple OSS Distributions void *buf = stackshot_config_get_stackshot_buffer(config); 231*94d3b452SApple OSS Distributions size_t size = stackshot_config_get_stackshot_size(config); 232*94d3b452SApple OSS Distributions if (scenario->name && !scenario->no_recordfile) { 233*94d3b452SApple OSS Distributions char sspath[MAXPATHLEN]; 234*94d3b452SApple OSS Distributions strlcpy(sspath, scenario->name, sizeof(sspath)); 235*94d3b452SApple OSS Distributions strlcat(sspath, ".kcdata", sizeof(sspath)); 236*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(dt_resultfile(sspath, sizeof(sspath)), 237*94d3b452SApple OSS Distributions "create result file path"); 238*94d3b452SApple OSS Distributions 239*94d3b452SApple OSS Distributions if (!scenario->quiet) { 240*94d3b452SApple OSS Distributions T_LOG("writing stackshot to %s", sspath); 241*94d3b452SApple OSS Distributions } 242*94d3b452SApple OSS Distributions 243*94d3b452SApple OSS Distributions FILE *f = fopen(sspath, "w"); 244*94d3b452SApple OSS Distributions T_WITH_ERRNO; T_QUIET; T_ASSERT_NOTNULL(f, 245*94d3b452SApple OSS Distributions "open stackshot output file"); 246*94d3b452SApple OSS Distributions 247*94d3b452SApple OSS Distributions size_t written = fwrite(buf, size, 1, f); 248*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(written, "wrote stackshot to file"); 249*94d3b452SApple OSS Distributions 250*94d3b452SApple OSS Distributions fclose(f); 251*94d3b452SApple OSS Distributions } 252*94d3b452SApple OSS Distributions cb(buf, size); 253*94d3b452SApple OSS Distributions if (compress_ok) { 254*94d3b452SApple OSS Distributions if (global_flags == 0) { 255*94d3b452SApple OSS Distributions T_LOG("Restarting test with compression"); 256*94d3b452SApple OSS Distributions global_flags |= STACKSHOT_DO_COMPRESS; 257*94d3b452SApple OSS Distributions goto start; 258*94d3b452SApple OSS Distributions } else { 259*94d3b452SApple OSS Distributions global_flags = 0; 260*94d3b452SApple OSS Distributions } 261*94d3b452SApple OSS Distributions } 262*94d3b452SApple OSS Distributions 263*94d3b452SApple OSS Distributions ret = stackshot_config_dealloc(config); 264*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_POSIX_ZERO(ret, "deallocated stackshot config"); 265*94d3b452SApple OSS Distributions} 266*94d3b452SApple OSS Distributions 267*94d3b452SApple OSS DistributionsT_DECL(simple_compressed, "take a simple compressed stackshot") 268*94d3b452SApple OSS Distributions{ 269*94d3b452SApple OSS Distributions struct scenario scenario = { 270*94d3b452SApple OSS Distributions .name = "kcdata_compressed", 271*94d3b452SApple OSS Distributions .flags = (STACKSHOT_DO_COMPRESS | STACKSHOT_SAVE_LOADINFO | STACKSHOT_THREAD_WAITINFO | STACKSHOT_GET_GLOBAL_MEM_STATS | 272*94d3b452SApple OSS Distributions STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_KCDATA_FORMAT), 273*94d3b452SApple OSS Distributions }; 274*94d3b452SApple OSS Distributions 275*94d3b452SApple OSS Distributions T_LOG("taking compressed kcdata stackshot"); 276*94d3b452SApple OSS Distributions take_stackshot(&scenario, true, ^(void *ssbuf, size_t sslen) { 277*94d3b452SApple OSS Distributions parse_stackshot(0, ssbuf, sslen, nil); 278*94d3b452SApple OSS Distributions }); 279*94d3b452SApple OSS Distributions} 280*94d3b452SApple OSS Distributions 281*94d3b452SApple OSS DistributionsT_DECL(panic_compressed, "take a compressed stackshot with the same flags as a panic stackshot") 282*94d3b452SApple OSS Distributions{ 283*94d3b452SApple OSS Distributions uint64_t stackshot_flags = (STACKSHOT_SAVE_KEXT_LOADINFO | 284*94d3b452SApple OSS Distributions STACKSHOT_SAVE_LOADINFO | 285*94d3b452SApple OSS Distributions STACKSHOT_KCDATA_FORMAT | 286*94d3b452SApple OSS Distributions STACKSHOT_ENABLE_BT_FAULTING | 287*94d3b452SApple OSS Distributions STACKSHOT_ENABLE_UUID_FAULTING | 288*94d3b452SApple OSS Distributions STACKSHOT_DO_COMPRESS | 289*94d3b452SApple OSS Distributions STACKSHOT_NO_IO_STATS | 290*94d3b452SApple OSS Distributions STACKSHOT_THREAD_WAITINFO | 291*94d3b452SApple OSS Distributions#if TARGET_OS_MAC 292*94d3b452SApple OSS Distributions STACKSHOT_COLLECT_SHAREDCACHE_LAYOUT | 293*94d3b452SApple OSS Distributions#endif 294*94d3b452SApple OSS Distributions STACKSHOT_DISABLE_LATENCY_INFO); 295*94d3b452SApple OSS Distributions 296*94d3b452SApple OSS Distributions struct scenario scenario = { 297*94d3b452SApple OSS Distributions .name = "kcdata_panic_compressed", 298*94d3b452SApple OSS Distributions .flags = stackshot_flags, 299*94d3b452SApple OSS Distributions }; 300*94d3b452SApple OSS Distributions 301*94d3b452SApple OSS Distributions T_LOG("taking compressed kcdata stackshot with panic flags"); 302*94d3b452SApple OSS Distributions take_stackshot(&scenario, true, ^(void *ssbuf, size_t sslen) { 303*94d3b452SApple OSS Distributions parse_stackshot(0, ssbuf, sslen, nil); 304*94d3b452SApple OSS Distributions }); 305*94d3b452SApple OSS Distributions} 306*94d3b452SApple OSS Distributions 307*94d3b452SApple OSS DistributionsT_DECL(kcdata, "test that kcdata stackshots can be taken and parsed") 308*94d3b452SApple OSS Distributions{ 309*94d3b452SApple OSS Distributions struct scenario scenario = { 310*94d3b452SApple OSS Distributions .name = "kcdata", 311*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_GET_GLOBAL_MEM_STATS | 312*94d3b452SApple OSS Distributions STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_KCDATA_FORMAT), 313*94d3b452SApple OSS Distributions }; 314*94d3b452SApple OSS Distributions 315*94d3b452SApple OSS Distributions T_LOG("taking kcdata stackshot"); 316*94d3b452SApple OSS Distributions take_stackshot(&scenario, true, ^(void *ssbuf, size_t sslen) { 317*94d3b452SApple OSS Distributions parse_stackshot(0, ssbuf, sslen, nil); 318*94d3b452SApple OSS Distributions }); 319*94d3b452SApple OSS Distributions} 320*94d3b452SApple OSS Distributions 321*94d3b452SApple OSS Distributionsstatic void 322*94d3b452SApple OSS Distributionsget_stats(stackshot_stats_t *_Nonnull out) 323*94d3b452SApple OSS Distributions{ 324*94d3b452SApple OSS Distributions size_t oldlen = sizeof (*out); 325*94d3b452SApple OSS Distributions bzero(out, oldlen); 326*94d3b452SApple OSS Distributions int result = sysctlbyname("kern.stackshot_stats", out, &oldlen, NULL, 0); 327*94d3b452SApple OSS Distributions T_WITH_ERRNO; T_ASSERT_POSIX_SUCCESS(result, "reading \"kern.stackshot_stats\" sysctl should succeed"); 328*94d3b452SApple OSS Distributions T_EXPECT_EQ(oldlen, sizeof (*out), "kernel should update full stats structure"); 329*94d3b452SApple OSS Distributions} 330*94d3b452SApple OSS Distributions 331*94d3b452SApple OSS Distributionsstatic void 332*94d3b452SApple OSS Distributionslog_stats(mach_timebase_info_data_t timebase, uint64_t now, const char *name, stackshot_stats_t stat) 333*94d3b452SApple OSS Distributions{ 334*94d3b452SApple OSS Distributions uint64_t last_ago = (now - stat.ss_last_start) * timebase.numer / timebase.denom; 335*94d3b452SApple OSS Distributions uint64_t last_duration = (stat.ss_last_end - stat.ss_last_start) * timebase.numer / timebase.denom; 336*94d3b452SApple OSS Distributions uint64_t total_duration = (stat.ss_duration) * timebase.numer / timebase.denom; 337*94d3b452SApple OSS Distributions 338*94d3b452SApple OSS Distributions uint64_t nanosec = 1000000000llu; 339*94d3b452SApple OSS Distributions T_LOG("%s: %8lld stackshots, %10lld.%09lld total nsecs, last %lld.%09lld secs ago, %lld.%09lld secs long", 340*94d3b452SApple OSS Distributions name, stat.ss_count, 341*94d3b452SApple OSS Distributions total_duration / nanosec, total_duration % nanosec, 342*94d3b452SApple OSS Distributions last_ago / nanosec, last_ago % nanosec, 343*94d3b452SApple OSS Distributions last_duration / nanosec, last_duration % nanosec); 344*94d3b452SApple OSS Distributions} 345*94d3b452SApple OSS Distributions 346*94d3b452SApple OSS DistributionsT_DECL(stats, "test that stackshot stats can be read out and change when a stackshot occurs") 347*94d3b452SApple OSS Distributions{ 348*94d3b452SApple OSS Distributions mach_timebase_info_data_t timebase = {0, 0}; 349*94d3b452SApple OSS Distributions mach_timebase_info(&timebase); 350*94d3b452SApple OSS Distributions 351*94d3b452SApple OSS Distributions struct scenario scenario = { 352*94d3b452SApple OSS Distributions .name = "kcdata", 353*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_KCDATA_FORMAT), 354*94d3b452SApple OSS Distributions }; 355*94d3b452SApple OSS Distributions 356*94d3b452SApple OSS Distributions stackshot_stats_t pre, post; 357*94d3b452SApple OSS Distributions 358*94d3b452SApple OSS Distributions get_stats(&pre); 359*94d3b452SApple OSS Distributions 360*94d3b452SApple OSS Distributions T_LOG("taking kcdata stackshot"); 361*94d3b452SApple OSS Distributions take_stackshot(&scenario, true, ^(__unused void *ssbuf, __unused size_t sslen) { 362*94d3b452SApple OSS Distributions (void)0; 363*94d3b452SApple OSS Distributions }); 364*94d3b452SApple OSS Distributions 365*94d3b452SApple OSS Distributions get_stats(&post); 366*94d3b452SApple OSS Distributions 367*94d3b452SApple OSS Distributions uint64_t now = mach_absolute_time(); 368*94d3b452SApple OSS Distributions 369*94d3b452SApple OSS Distributions log_stats(timebase, now, " pre", pre); 370*94d3b452SApple OSS Distributions log_stats(timebase, now, " post", post); 371*94d3b452SApple OSS Distributions 372*94d3b452SApple OSS Distributions int64_t delta_stackshots = (int64_t)(post.ss_count - pre.ss_count); 373*94d3b452SApple OSS Distributions int64_t delta_duration = (int64_t)(post.ss_duration - pre.ss_duration) * (int64_t)timebase.numer / (int64_t)timebase.denom; 374*94d3b452SApple OSS Distributions int64_t delta_nsec = delta_duration % 1000000000ll; 375*94d3b452SApple OSS Distributions if (delta_nsec < 0) { 376*94d3b452SApple OSS Distributions delta_nsec += 1000000000ll; 377*94d3b452SApple OSS Distributions } 378*94d3b452SApple OSS Distributions T_LOG("delta: %+8lld stackshots, %+10lld.%09lld total nsecs", delta_stackshots, delta_duration / 1000000000ll, delta_nsec); 379*94d3b452SApple OSS Distributions 380*94d3b452SApple OSS Distributions T_EXPECT_LT(pre.ss_last_start, pre.ss_last_end, "pre: stackshot should take time"); 381*94d3b452SApple OSS Distributions T_EXPECT_LT(pre.ss_count, post.ss_count, "stackshot count should increase when a stackshot is taken"); 382*94d3b452SApple OSS Distributions T_EXPECT_LT(pre.ss_duration, post.ss_duration, "stackshot duration should increase when a stackshot is taken"); 383*94d3b452SApple OSS Distributions T_EXPECT_LT(pre.ss_last_end, post.ss_last_start, "previous end should be less than new start after a stackshot"); 384*94d3b452SApple OSS Distributions T_EXPECT_LT(post.ss_last_start, post.ss_last_end, "post: stackshot should take time"); 385*94d3b452SApple OSS Distributions} 386*94d3b452SApple OSS Distributions 387*94d3b452SApple OSS DistributionsT_DECL(kcdata_faulting, "test that kcdata stackshots while faulting can be taken and parsed") 388*94d3b452SApple OSS Distributions{ 389*94d3b452SApple OSS Distributions struct scenario scenario = { 390*94d3b452SApple OSS Distributions .name = "faulting", 391*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_GET_GLOBAL_MEM_STATS 392*94d3b452SApple OSS Distributions | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_KCDATA_FORMAT 393*94d3b452SApple OSS Distributions | STACKSHOT_ENABLE_BT_FAULTING | STACKSHOT_ENABLE_UUID_FAULTING), 394*94d3b452SApple OSS Distributions }; 395*94d3b452SApple OSS Distributions 396*94d3b452SApple OSS Distributions T_LOG("taking faulting stackshot"); 397*94d3b452SApple OSS Distributions take_stackshot(&scenario, true, ^(void *ssbuf, size_t sslen) { 398*94d3b452SApple OSS Distributions parse_stackshot(0, ssbuf, sslen, nil); 399*94d3b452SApple OSS Distributions }); 400*94d3b452SApple OSS Distributions} 401*94d3b452SApple OSS Distributions 402*94d3b452SApple OSS DistributionsT_DECL(bad_flags, "test a poorly-formed stackshot syscall") 403*94d3b452SApple OSS Distributions{ 404*94d3b452SApple OSS Distributions struct scenario scenario = { 405*94d3b452SApple OSS Distributions .flags = STACKSHOT_SAVE_IN_KERNEL_BUFFER /* not allowed from user space */, 406*94d3b452SApple OSS Distributions .should_fail = true, 407*94d3b452SApple OSS Distributions }; 408*94d3b452SApple OSS Distributions 409*94d3b452SApple OSS Distributions T_LOG("attempting to take stackshot with kernel-only flag"); 410*94d3b452SApple OSS Distributions take_stackshot(&scenario, true, ^(__unused void *ssbuf, __unused size_t sslen) { 411*94d3b452SApple OSS Distributions T_ASSERT_FAIL("stackshot data callback called"); 412*94d3b452SApple OSS Distributions }); 413*94d3b452SApple OSS Distributions} 414*94d3b452SApple OSS Distributions 415*94d3b452SApple OSS DistributionsT_DECL(delta, "test delta stackshots") 416*94d3b452SApple OSS Distributions{ 417*94d3b452SApple OSS Distributions struct scenario scenario = { 418*94d3b452SApple OSS Distributions .name = "delta", 419*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_GET_GLOBAL_MEM_STATS 420*94d3b452SApple OSS Distributions | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_KCDATA_FORMAT), 421*94d3b452SApple OSS Distributions }; 422*94d3b452SApple OSS Distributions 423*94d3b452SApple OSS Distributions T_LOG("taking full stackshot"); 424*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 425*94d3b452SApple OSS Distributions uint64_t stackshot_time = stackshot_timestamp(ssbuf, sslen); 426*94d3b452SApple OSS Distributions 427*94d3b452SApple OSS Distributions T_LOG("taking delta stackshot since time %" PRIu64, stackshot_time); 428*94d3b452SApple OSS Distributions 429*94d3b452SApple OSS Distributions parse_stackshot(0, ssbuf, sslen, nil); 430*94d3b452SApple OSS Distributions 431*94d3b452SApple OSS Distributions struct scenario delta_scenario = { 432*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_GET_GLOBAL_MEM_STATS 433*94d3b452SApple OSS Distributions | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_KCDATA_FORMAT 434*94d3b452SApple OSS Distributions | STACKSHOT_COLLECT_DELTA_SNAPSHOT), 435*94d3b452SApple OSS Distributions .since_timestamp = stackshot_time 436*94d3b452SApple OSS Distributions }; 437*94d3b452SApple OSS Distributions 438*94d3b452SApple OSS Distributions take_stackshot(&delta_scenario, false, ^(void *dssbuf, size_t dsslen) { 439*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_DELTA, dssbuf, dsslen, nil); 440*94d3b452SApple OSS Distributions }); 441*94d3b452SApple OSS Distributions }); 442*94d3b452SApple OSS Distributions} 443*94d3b452SApple OSS Distributions 444*94d3b452SApple OSS DistributionsT_DECL(shared_cache_layout, "test stackshot inclusion of shared cache layout") 445*94d3b452SApple OSS Distributions{ 446*94d3b452SApple OSS Distributions struct scenario scenario = { 447*94d3b452SApple OSS Distributions .name = "shared_cache_layout", 448*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_GET_GLOBAL_MEM_STATS 449*94d3b452SApple OSS Distributions | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_KCDATA_FORMAT | 450*94d3b452SApple OSS Distributions STACKSHOT_COLLECT_SHAREDCACHE_LAYOUT), 451*94d3b452SApple OSS Distributions }; 452*94d3b452SApple OSS Distributions 453*94d3b452SApple OSS Distributions size_t shared_cache_length; 454*94d3b452SApple OSS Distributions const void *cache_header = _dyld_get_shared_cache_range(&shared_cache_length); 455*94d3b452SApple OSS Distributions if (cache_header == NULL) { 456*94d3b452SApple OSS Distributions T_SKIP("Device not running with shared cache, skipping test..."); 457*94d3b452SApple OSS Distributions } 458*94d3b452SApple OSS Distributions 459*94d3b452SApple OSS Distributions if (shared_cache_length == 0) { 460*94d3b452SApple OSS Distributions T_SKIP("dyld reports that currently running shared cache has zero length"); 461*94d3b452SApple OSS Distributions } 462*94d3b452SApple OSS Distributions 463*94d3b452SApple OSS Distributions T_LOG("taking stackshot with STACKSHOT_COLLECT_SHAREDCACHE_LAYOUT set"); 464*94d3b452SApple OSS Distributions take_stackshot(&scenario, true, ^(void *ssbuf, size_t sslen) { 465*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_SHAREDCACHE_LAYOUT, ssbuf, sslen, nil); 466*94d3b452SApple OSS Distributions }); 467*94d3b452SApple OSS Distributions} 468*94d3b452SApple OSS Distributions 469*94d3b452SApple OSS DistributionsT_DECL(stress, "test that taking stackshots for 60 seconds doesn't crash the system") 470*94d3b452SApple OSS Distributions{ 471*94d3b452SApple OSS Distributions uint64_t max_diff_time = 60ULL /* seconds */ * 1000000000ULL; 472*94d3b452SApple OSS Distributions uint64_t start_time; 473*94d3b452SApple OSS Distributions 474*94d3b452SApple OSS Distributions struct scenario scenario = { 475*94d3b452SApple OSS Distributions .name = "stress", 476*94d3b452SApple OSS Distributions .quiet = true, 477*94d3b452SApple OSS Distributions .flags = (STACKSHOT_KCDATA_FORMAT | 478*94d3b452SApple OSS Distributions STACKSHOT_THREAD_WAITINFO | 479*94d3b452SApple OSS Distributions STACKSHOT_SAVE_LOADINFO | 480*94d3b452SApple OSS Distributions STACKSHOT_SAVE_KEXT_LOADINFO | 481*94d3b452SApple OSS Distributions STACKSHOT_GET_GLOBAL_MEM_STATS | 482*94d3b452SApple OSS Distributions STACKSHOT_SAVE_IMP_DONATION_PIDS | 483*94d3b452SApple OSS Distributions STACKSHOT_COLLECT_SHAREDCACHE_LAYOUT | 484*94d3b452SApple OSS Distributions STACKSHOT_THREAD_GROUP | 485*94d3b452SApple OSS Distributions STACKSHOT_SAVE_JETSAM_COALITIONS | 486*94d3b452SApple OSS Distributions STACKSHOT_ASID | 487*94d3b452SApple OSS Distributions 0), 488*94d3b452SApple OSS Distributions }; 489*94d3b452SApple OSS Distributions 490*94d3b452SApple OSS Distributions start_time = clock_gettime_nsec_np(CLOCK_MONOTONIC); 491*94d3b452SApple OSS Distributions while (clock_gettime_nsec_np(CLOCK_MONOTONIC) - start_time < max_diff_time) { 492*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void * __unused ssbuf, 493*94d3b452SApple OSS Distributions size_t __unused sslen) { 494*94d3b452SApple OSS Distributions printf("."); 495*94d3b452SApple OSS Distributions fflush(stdout); 496*94d3b452SApple OSS Distributions }); 497*94d3b452SApple OSS Distributions 498*94d3b452SApple OSS Distributions /* 499*94d3b452SApple OSS Distributions * After the first stackshot, there's no point in continuing to 500*94d3b452SApple OSS Distributions * write them to disk, and it wears down the SSDs. 501*94d3b452SApple OSS Distributions */ 502*94d3b452SApple OSS Distributions scenario.no_recordfile = true; 503*94d3b452SApple OSS Distributions 504*94d3b452SApple OSS Distributions /* Leave some time for the testing infrastructure to catch up */ 505*94d3b452SApple OSS Distributions usleep(10000); 506*94d3b452SApple OSS Distributions 507*94d3b452SApple OSS Distributions } 508*94d3b452SApple OSS Distributions printf("\n"); 509*94d3b452SApple OSS Distributions} 510*94d3b452SApple OSS Distributions 511*94d3b452SApple OSS DistributionsT_DECL(dispatch_queue_label, "test that kcdata stackshots contain libdispatch queue labels") 512*94d3b452SApple OSS Distributions{ 513*94d3b452SApple OSS Distributions struct scenario scenario = { 514*94d3b452SApple OSS Distributions .name = "kcdata", 515*94d3b452SApple OSS Distributions .flags = (STACKSHOT_GET_DQ | STACKSHOT_KCDATA_FORMAT), 516*94d3b452SApple OSS Distributions }; 517*94d3b452SApple OSS Distributions dispatch_semaphore_t child_ready_sem, parent_done_sem; 518*94d3b452SApple OSS Distributions dispatch_queue_t dq; 519*94d3b452SApple OSS Distributions 520*94d3b452SApple OSS Distributions#if TARGET_OS_WATCH 521*94d3b452SApple OSS Distributions T_SKIP("This test is flaky on watches: 51663346"); 522*94d3b452SApple OSS Distributions#endif 523*94d3b452SApple OSS Distributions 524*94d3b452SApple OSS Distributions child_ready_sem = dispatch_semaphore_create(0); 525*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(child_ready_sem, "dqlabel child semaphore"); 526*94d3b452SApple OSS Distributions 527*94d3b452SApple OSS Distributions parent_done_sem = dispatch_semaphore_create(0); 528*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(parent_done_sem, "dqlabel parent semaphore"); 529*94d3b452SApple OSS Distributions 530*94d3b452SApple OSS Distributions dq = dispatch_queue_create(TEST_STACKSHOT_QUEUE_LABEL, NULL); 531*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(dq, "dispatch queue"); 532*94d3b452SApple OSS Distributions 533*94d3b452SApple OSS Distributions /* start the helper thread */ 534*94d3b452SApple OSS Distributions dispatch_async(dq, ^{ 535*94d3b452SApple OSS Distributions dispatch_semaphore_signal(child_ready_sem); 536*94d3b452SApple OSS Distributions 537*94d3b452SApple OSS Distributions dispatch_semaphore_wait(parent_done_sem, DISPATCH_TIME_FOREVER); 538*94d3b452SApple OSS Distributions }); 539*94d3b452SApple OSS Distributions 540*94d3b452SApple OSS Distributions /* block behind the child starting up */ 541*94d3b452SApple OSS Distributions dispatch_semaphore_wait(child_ready_sem, DISPATCH_TIME_FOREVER); 542*94d3b452SApple OSS Distributions 543*94d3b452SApple OSS Distributions T_LOG("taking kcdata stackshot with libdispatch queue labels"); 544*94d3b452SApple OSS Distributions take_stackshot(&scenario, true, ^(void *ssbuf, size_t sslen) { 545*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_DISPATCH_QUEUE_LABEL, ssbuf, sslen, nil); 546*94d3b452SApple OSS Distributions }); 547*94d3b452SApple OSS Distributions 548*94d3b452SApple OSS Distributions dispatch_semaphore_signal(parent_done_sem); 549*94d3b452SApple OSS Distributions} 550*94d3b452SApple OSS Distributions 551*94d3b452SApple OSS Distributions#define CACHEADDR_ENV "STACKSHOT_TEST_DYLDADDR" 552*94d3b452SApple OSS DistributionsT_HELPER_DECL(spawn_reslide_child, "child process to spawn with alternate slide") 553*94d3b452SApple OSS Distributions{ 554*94d3b452SApple OSS Distributions size_t shared_cache_len; 555*94d3b452SApple OSS Distributions const void *addr, *prevaddr; 556*94d3b452SApple OSS Distributions uintmax_t v; 557*94d3b452SApple OSS Distributions char *endptr; 558*94d3b452SApple OSS Distributions 559*94d3b452SApple OSS Distributions const char *cacheaddr_env = getenv(CACHEADDR_ENV); 560*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(cacheaddr_env, "getenv("CACHEADDR_ENV")"); 561*94d3b452SApple OSS Distributions errno = 0; 562*94d3b452SApple OSS Distributions endptr = NULL; 563*94d3b452SApple OSS Distributions v = strtoumax(cacheaddr_env, &endptr, 16); /* read hex value */ 564*94d3b452SApple OSS Distributions T_WITH_ERRNO; T_QUIET; T_ASSERT_NE(v, 0l, "getenv(%s) = \"%s\" should be a non-zero hex number", CACHEADDR_ENV, cacheaddr_env); 565*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(*endptr, 0, "getenv(%s) = \"%s\" endptr \"%s\" should be empty", CACHEADDR_ENV, cacheaddr_env, endptr); 566*94d3b452SApple OSS Distributions 567*94d3b452SApple OSS Distributions prevaddr = (const void *)v; 568*94d3b452SApple OSS Distributions addr = _dyld_get_shared_cache_range(&shared_cache_len); 569*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(addr, "shared cache address"); 570*94d3b452SApple OSS Distributions 571*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(kill(getppid(), (addr == prevaddr) ? SIGUSR2 : SIGUSR1), "signaled parent to take stackshot"); 572*94d3b452SApple OSS Distributions for (;;) { 573*94d3b452SApple OSS Distributions (void) pause(); /* parent will kill -9 us */ 574*94d3b452SApple OSS Distributions } 575*94d3b452SApple OSS Distributions} 576*94d3b452SApple OSS Distributions 577*94d3b452SApple OSS DistributionsT_DECL(shared_cache_flags, "tests stackshot's task_ss_flags for the shared cache") 578*94d3b452SApple OSS Distributions{ 579*94d3b452SApple OSS Distributions posix_spawnattr_t attr; 580*94d3b452SApple OSS Distributions char *env_addr; 581*94d3b452SApple OSS Distributions char path[PATH_MAX]; 582*94d3b452SApple OSS Distributions __block bool child_same_addr = false; 583*94d3b452SApple OSS Distributions 584*94d3b452SApple OSS Distributions uint32_t path_size = sizeof(path); 585*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path, &path_size), "_NSGetExecutablePath"); 586*94d3b452SApple OSS Distributions char *args[] = { path, "-n", "spawn_reslide_child", NULL }; 587*94d3b452SApple OSS Distributions pid_t pid; 588*94d3b452SApple OSS Distributions size_t shared_cache_len; 589*94d3b452SApple OSS Distributions const void *addr; 590*94d3b452SApple OSS Distributions 591*94d3b452SApple OSS Distributions dispatch_source_t child_diffsig_src, child_samesig_src; 592*94d3b452SApple OSS Distributions dispatch_semaphore_t child_ready_sem = dispatch_semaphore_create(0); 593*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(child_ready_sem, "shared_cache child semaphore"); 594*94d3b452SApple OSS Distributions 595*94d3b452SApple OSS Distributions dispatch_queue_t signal_processing_q = dispatch_queue_create("signal processing queue", NULL); 596*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(signal_processing_q, "signal processing queue"); 597*94d3b452SApple OSS Distributions 598*94d3b452SApple OSS Distributions signal(SIGUSR1, SIG_IGN); 599*94d3b452SApple OSS Distributions signal(SIGUSR2, SIG_IGN); 600*94d3b452SApple OSS Distributions child_samesig_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, signal_processing_q); 601*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(child_samesig_src, "dispatch_source_create (child_samesig_src)"); 602*94d3b452SApple OSS Distributions child_diffsig_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR2, 0, signal_processing_q); 603*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(child_diffsig_src, "dispatch_source_create (child_diffsig_src)"); 604*94d3b452SApple OSS Distributions 605*94d3b452SApple OSS Distributions /* child will signal us depending on if their addr is the same or different */ 606*94d3b452SApple OSS Distributions dispatch_source_set_event_handler(child_samesig_src, ^{ child_same_addr = false; dispatch_semaphore_signal(child_ready_sem); }); 607*94d3b452SApple OSS Distributions dispatch_source_set_event_handler(child_diffsig_src, ^{ child_same_addr = true; dispatch_semaphore_signal(child_ready_sem); }); 608*94d3b452SApple OSS Distributions dispatch_activate(child_samesig_src); 609*94d3b452SApple OSS Distributions dispatch_activate(child_diffsig_src); 610*94d3b452SApple OSS Distributions 611*94d3b452SApple OSS Distributions addr = _dyld_get_shared_cache_range(&shared_cache_len); 612*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(addr, "shared cache address"); 613*94d3b452SApple OSS Distributions 614*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(asprintf(&env_addr, "%p", addr), "asprintf of env_addr succeeded"); 615*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(setenv(CACHEADDR_ENV, env_addr, true), "setting "CACHEADDR_ENV" to %s", env_addr); 616*94d3b452SApple OSS Distributions 617*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(posix_spawnattr_init(&attr), "posix_spawnattr_init"); 618*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(posix_spawnattr_setflags(&attr, _POSIX_SPAWN_RESLIDE), "posix_spawnattr_setflags"); 619*94d3b452SApple OSS Distributions int sp_ret = posix_spawn(&pid, path, NULL, &attr, args, environ); 620*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(sp_ret, "spawned process '%s' with PID %d", args[0], pid); 621*94d3b452SApple OSS Distributions 622*94d3b452SApple OSS Distributions dispatch_semaphore_wait(child_ready_sem, DISPATCH_TIME_FOREVER); 623*94d3b452SApple OSS Distributions T_LOG("received signal from child (%s), capturing stackshot", child_same_addr ? "same shared cache addr" : "different shared cache addr"); 624*94d3b452SApple OSS Distributions 625*94d3b452SApple OSS Distributions struct scenario scenario = { 626*94d3b452SApple OSS Distributions .name = "shared_cache_flags", 627*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_GET_GLOBAL_MEM_STATS 628*94d3b452SApple OSS Distributions | STACKSHOT_COLLECT_SHAREDCACHE_LAYOUT 629*94d3b452SApple OSS Distributions | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_KCDATA_FORMAT), 630*94d3b452SApple OSS Distributions }; 631*94d3b452SApple OSS Distributions 632*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^( void *ssbuf, size_t sslen) { 633*94d3b452SApple OSS Distributions int status; 634*94d3b452SApple OSS Distributions /* First kill the child so we can reap it */ 635*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(kill(pid, SIGKILL), "killing spawned process"); 636*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(waitpid(pid, &status, 0), "waitpid on spawned child"); 637*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(!!WIFSIGNALED(status), 1, "waitpid status should be signalled"); 638*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(WTERMSIG(status), SIGKILL, "waitpid status should be SIGKILLed"); 639*94d3b452SApple OSS Distributions 640*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_SHAREDCACHE_FLAGS, ssbuf, sslen, 641*94d3b452SApple OSS Distributions @{sharedcache_child_pid_key: @(pid), sharedcache_child_sameaddr_key: @(child_same_addr ? 1 : 0)}); 642*94d3b452SApple OSS Distributions }); 643*94d3b452SApple OSS Distributions} 644*94d3b452SApple OSS Distributions 645*94d3b452SApple OSS DistributionsT_DECL(transitioning_tasks, "test that stackshot contains transitioning task info", T_META_BOOTARGS_SET("enable_proc_exit_lpexit_spin=1")) 646*94d3b452SApple OSS Distributions{ 647*94d3b452SApple OSS Distributions int32_t sysctlValue = -1, numAttempts =0; 648*94d3b452SApple OSS Distributions char path[PATH_MAX]; 649*94d3b452SApple OSS Distributions uint32_t path_size = sizeof(path); 650*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path, &path_size), "_NSGetExecutablePath"); 651*94d3b452SApple OSS Distributions char *args[] = { path, "-n", "exec_child_preexec", NULL }; 652*94d3b452SApple OSS Distributions 653*94d3b452SApple OSS Distributions dispatch_source_t child_sig_src; 654*94d3b452SApple OSS Distributions dispatch_semaphore_t child_ready_sem = dispatch_semaphore_create(0); 655*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(child_ready_sem, "exec child semaphore"); 656*94d3b452SApple OSS Distributions 657*94d3b452SApple OSS Distributions dispatch_queue_t signal_processing_q = dispatch_queue_create("signal processing queue", NULL); 658*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(signal_processing_q, "signal processing queue"); 659*94d3b452SApple OSS Distributions 660*94d3b452SApple OSS Distributions pid_t pid; 661*94d3b452SApple OSS Distributions 662*94d3b452SApple OSS Distributions signal(SIGUSR1, SIG_IGN); 663*94d3b452SApple OSS Distributions child_sig_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, signal_processing_q); 664*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(child_sig_src, "dispatch_source_create (child_sig_src)"); 665*94d3b452SApple OSS Distributions 666*94d3b452SApple OSS Distributions dispatch_source_set_event_handler(child_sig_src, ^{ dispatch_semaphore_signal(child_ready_sem); }); 667*94d3b452SApple OSS Distributions dispatch_activate(child_sig_src); 668*94d3b452SApple OSS Distributions 669*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(sysctlbyname("debug.proc_exit_lpexit_spin_pid", NULL, NULL, &sysctlValue, sizeof(sysctlValue)), "set debug.proc_exit_lpexit_spin_pid=-1"); 670*94d3b452SApple OSS Distributions 671*94d3b452SApple OSS Distributions int proc_exit_spin_pos = 0 ; 672*94d3b452SApple OSS Distributions 673*94d3b452SApple OSS Distributions while (0 == sysctlbyname("debug.proc_exit_lpexit_spin_pos", NULL, NULL, &proc_exit_spin_pos, sizeof(proc_exit_spin_pos))) { 674*94d3b452SApple OSS Distributions 675*94d3b452SApple OSS Distributions T_LOG(" ##### Testing while spinning in proc_exit at position %d ##### ", proc_exit_spin_pos); 676*94d3b452SApple OSS Distributions 677*94d3b452SApple OSS Distributions int sp_ret = posix_spawn(&pid, args[0], NULL, NULL, args, NULL); 678*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(sp_ret, "spawned process '%s' with PID %d", args[0], pid); 679*94d3b452SApple OSS Distributions 680*94d3b452SApple OSS Distributions dispatch_semaphore_wait(child_ready_sem, DISPATCH_TIME_FOREVER); 681*94d3b452SApple OSS Distributions 682*94d3b452SApple OSS Distributions struct proc_uniqidentifierinfo proc_info_data = { }; 683*94d3b452SApple OSS Distributions int retval = proc_pidinfo(getpid(), PROC_PIDUNIQIDENTIFIERINFO, 0, &proc_info_data, sizeof(proc_info_data)); 684*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_POSIX_SUCCESS(retval, "proc_pidinfo PROC_PIDUNIQIDENTIFIERINFO"); 685*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ_INT(retval, (int) sizeof(proc_info_data), "proc_pidinfo PROC_PIDUNIQIDENTIFIERINFO returned data"); 686*94d3b452SApple OSS Distributions 687*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kill(pid, SIGUSR1), "signaled pre-exec child to exec"); 688*94d3b452SApple OSS Distributions 689*94d3b452SApple OSS Distributions /* wait for a signal from post-exec child */ 690*94d3b452SApple OSS Distributions dispatch_semaphore_wait(child_ready_sem, DISPATCH_TIME_FOREVER); 691*94d3b452SApple OSS Distributions 692*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(sysctlbyname("debug.proc_exit_lpexit_spin_pid", NULL, NULL, &pid, sizeof(pid)), "set debug.proc_exit_lpexit_spin_pid = %d, ", pid); 693*94d3b452SApple OSS Distributions 694*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kill(pid, SIGKILL), "kill post-exec child %d", pid); 695*94d3b452SApple OSS Distributions 696*94d3b452SApple OSS Distributions sysctlValue = 0; 697*94d3b452SApple OSS Distributions size_t len = sizeof(sysctlValue); 698*94d3b452SApple OSS Distributions while (numAttempts < 5) { 699*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(sysctlbyname("debug.proc_exit_lpexit_spinning", &sysctlValue, &len, NULL, 0), "retrieve debug.proc_exit_lpexit_spinning"); 700*94d3b452SApple OSS Distributions if (sysctlValue != 1) numAttempts++; 701*94d3b452SApple OSS Distributions else break; 702*94d3b452SApple OSS Distributions sleep(1); 703*94d3b452SApple OSS Distributions } 704*94d3b452SApple OSS Distributions 705*94d3b452SApple OSS Distributions T_ASSERT_EQ_UINT(sysctlValue, 1, "find spinning task in proc_exit()"); 706*94d3b452SApple OSS Distributions 707*94d3b452SApple OSS Distributions struct scenario scenario = { 708*94d3b452SApple OSS Distributions .name = "transitioning_tasks", 709*94d3b452SApple OSS Distributions .flags = (STACKSHOT_KCDATA_FORMAT) 710*94d3b452SApple OSS Distributions }; 711*94d3b452SApple OSS Distributions 712*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^( void *ssbuf, size_t sslen) { 713*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_TRANSITIONING, ssbuf, sslen, @{transitioning_pid_key: @(pid)}); 714*94d3b452SApple OSS Distributions 715*94d3b452SApple OSS Distributions // Kill the child 716*94d3b452SApple OSS Distributions int sysctlValueB = -1; 717*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(sysctlbyname("debug.proc_exit_lpexit_spin_pid", NULL, NULL, &sysctlValueB, sizeof(sysctlValueB)), "set debug.proc_exit_lpexit_spin_pid=-1"); 718*94d3b452SApple OSS Distributions sleep(1); 719*94d3b452SApple OSS Distributions size_t blen = sizeof(sysctlValueB); 720*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(sysctlbyname("debug.proc_exit_lpexit_spinning", &sysctlValueB, &blen, NULL, 0), "retrieve debug.proc_exit_lpexit_spinning"); 721*94d3b452SApple OSS Distributions T_ASSERT_EQ_UINT(sysctlValueB, 0, "make sure nothing is spining in proc_exit()"); 722*94d3b452SApple OSS Distributions int status; 723*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(waitpid(pid, &status, 0), "waitpid on post-exec child"); 724*94d3b452SApple OSS Distributions }); 725*94d3b452SApple OSS Distributions 726*94d3b452SApple OSS Distributions proc_exit_spin_pos++; 727*94d3b452SApple OSS Distributions } 728*94d3b452SApple OSS Distributions 729*94d3b452SApple OSS Distributions} 730*94d3b452SApple OSS Distributions 731*94d3b452SApple OSS Distributionsstatic void *stuck_sysctl_thread(void *arg) { 732*94d3b452SApple OSS Distributions int val = 1; 733*94d3b452SApple OSS Distributions dispatch_semaphore_t child_thread_started = *(dispatch_semaphore_t *)arg; 734*94d3b452SApple OSS Distributions 735*94d3b452SApple OSS Distributions dispatch_semaphore_signal(child_thread_started); 736*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(sysctlbyname("kern.wedge_thread", NULL, NULL, &val, sizeof(val)), "wedge child thread"); 737*94d3b452SApple OSS Distributions 738*94d3b452SApple OSS Distributions return NULL; 739*94d3b452SApple OSS Distributions} 740*94d3b452SApple OSS Distributions 741*94d3b452SApple OSS DistributionsT_HELPER_DECL(zombie_child, "child process to sample as a zombie") 742*94d3b452SApple OSS Distributions{ 743*94d3b452SApple OSS Distributions pthread_t pthread; 744*94d3b452SApple OSS Distributions dispatch_semaphore_t child_thread_started = dispatch_semaphore_create(0); 745*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(child_thread_started, "zombie child thread semaphore"); 746*94d3b452SApple OSS Distributions 747*94d3b452SApple OSS Distributions /* spawn another thread to get stuck in the kernel, then call exit() to become a zombie */ 748*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_create(&pthread, NULL, stuck_sysctl_thread, &child_thread_started), "pthread_create"); 749*94d3b452SApple OSS Distributions 750*94d3b452SApple OSS Distributions dispatch_semaphore_wait(child_thread_started, DISPATCH_TIME_FOREVER); 751*94d3b452SApple OSS Distributions 752*94d3b452SApple OSS Distributions /* sleep for a bit in the hope of ensuring that the other thread has called the sysctl before we signal the parent */ 753*94d3b452SApple OSS Distributions usleep(100); 754*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kill(getppid(), SIGUSR1), "signaled parent to take stackshot"); 755*94d3b452SApple OSS Distributions 756*94d3b452SApple OSS Distributions exit(0); 757*94d3b452SApple OSS Distributions} 758*94d3b452SApple OSS Distributions 759*94d3b452SApple OSS DistributionsT_DECL(zombie, "tests a stackshot of a zombie task with a thread stuck in the kernel") 760*94d3b452SApple OSS Distributions{ 761*94d3b452SApple OSS Distributions char path[PATH_MAX]; 762*94d3b452SApple OSS Distributions uint32_t path_size = sizeof(path); 763*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path, &path_size), "_NSGetExecutablePath"); 764*94d3b452SApple OSS Distributions char *args[] = { path, "-n", "zombie_child", NULL }; 765*94d3b452SApple OSS Distributions 766*94d3b452SApple OSS Distributions dispatch_source_t child_sig_src; 767*94d3b452SApple OSS Distributions dispatch_semaphore_t child_ready_sem = dispatch_semaphore_create(0); 768*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(child_ready_sem, "zombie child semaphore"); 769*94d3b452SApple OSS Distributions 770*94d3b452SApple OSS Distributions dispatch_queue_t signal_processing_q = dispatch_queue_create("signal processing queue", NULL); 771*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(signal_processing_q, "signal processing queue"); 772*94d3b452SApple OSS Distributions 773*94d3b452SApple OSS Distributions pid_t pid; 774*94d3b452SApple OSS Distributions 775*94d3b452SApple OSS Distributions T_LOG("spawning a child"); 776*94d3b452SApple OSS Distributions 777*94d3b452SApple OSS Distributions signal(SIGUSR1, SIG_IGN); 778*94d3b452SApple OSS Distributions child_sig_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, signal_processing_q); 779*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(child_sig_src, "dispatch_source_create (child_sig_src)"); 780*94d3b452SApple OSS Distributions 781*94d3b452SApple OSS Distributions dispatch_source_set_event_handler(child_sig_src, ^{ dispatch_semaphore_signal(child_ready_sem); }); 782*94d3b452SApple OSS Distributions dispatch_activate(child_sig_src); 783*94d3b452SApple OSS Distributions 784*94d3b452SApple OSS Distributions int sp_ret = posix_spawn(&pid, args[0], NULL, NULL, args, NULL); 785*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(sp_ret, "spawned process '%s' with PID %d", args[0], pid); 786*94d3b452SApple OSS Distributions 787*94d3b452SApple OSS Distributions dispatch_semaphore_wait(child_ready_sem, DISPATCH_TIME_FOREVER); 788*94d3b452SApple OSS Distributions 789*94d3b452SApple OSS Distributions T_LOG("received signal from child, capturing stackshot"); 790*94d3b452SApple OSS Distributions 791*94d3b452SApple OSS Distributions struct proc_bsdshortinfo bsdshortinfo; 792*94d3b452SApple OSS Distributions int retval, iterations_to_wait = 10; 793*94d3b452SApple OSS Distributions 794*94d3b452SApple OSS Distributions while (iterations_to_wait > 0) { 795*94d3b452SApple OSS Distributions retval = proc_pidinfo(pid, PROC_PIDT_SHORTBSDINFO, 0, &bsdshortinfo, sizeof(bsdshortinfo)); 796*94d3b452SApple OSS Distributions if ((retval == 0) && errno == ESRCH) { 797*94d3b452SApple OSS Distributions T_LOG("unable to find child using proc_pidinfo, assuming zombie"); 798*94d3b452SApple OSS Distributions break; 799*94d3b452SApple OSS Distributions } 800*94d3b452SApple OSS Distributions 801*94d3b452SApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_GT(retval, 0, "proc_pidinfo(PROC_PIDT_SHORTBSDINFO) returned a value > 0"); 802*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(retval, (int)sizeof(bsdshortinfo), "proc_pidinfo call for PROC_PIDT_SHORTBSDINFO returned expected size"); 803*94d3b452SApple OSS Distributions 804*94d3b452SApple OSS Distributions if (bsdshortinfo.pbsi_flags & PROC_FLAG_INEXIT) { 805*94d3b452SApple OSS Distributions T_LOG("child proc info marked as in exit"); 806*94d3b452SApple OSS Distributions break; 807*94d3b452SApple OSS Distributions } 808*94d3b452SApple OSS Distributions 809*94d3b452SApple OSS Distributions iterations_to_wait--; 810*94d3b452SApple OSS Distributions if (iterations_to_wait == 0) { 811*94d3b452SApple OSS Distributions /* 812*94d3b452SApple OSS Distributions * This will mark the test as failed but let it continue so we 813*94d3b452SApple OSS Distributions * don't leave a process stuck in the kernel. 814*94d3b452SApple OSS Distributions */ 815*94d3b452SApple OSS Distributions T_FAIL("unable to discover that child is marked as exiting"); 816*94d3b452SApple OSS Distributions } 817*94d3b452SApple OSS Distributions 818*94d3b452SApple OSS Distributions /* Give the child a few more seconds to make it to exit */ 819*94d3b452SApple OSS Distributions sleep(5); 820*94d3b452SApple OSS Distributions } 821*94d3b452SApple OSS Distributions 822*94d3b452SApple OSS Distributions /* Give the child some more time to make it through exit */ 823*94d3b452SApple OSS Distributions sleep(10); 824*94d3b452SApple OSS Distributions 825*94d3b452SApple OSS Distributions struct scenario scenario = { 826*94d3b452SApple OSS Distributions .name = "zombie", 827*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_GET_GLOBAL_MEM_STATS 828*94d3b452SApple OSS Distributions | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_KCDATA_FORMAT), 829*94d3b452SApple OSS Distributions }; 830*94d3b452SApple OSS Distributions 831*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^( void *ssbuf, size_t sslen) { 832*94d3b452SApple OSS Distributions /* First unwedge the child so we can reap it */ 833*94d3b452SApple OSS Distributions int val = 1, status; 834*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(sysctlbyname("kern.unwedge_thread", NULL, NULL, &val, sizeof(val)), "unwedge child"); 835*94d3b452SApple OSS Distributions 836*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(waitpid(pid, &status, 0), "waitpid on zombie child"); 837*94d3b452SApple OSS Distributions 838*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_ZOMBIE, ssbuf, sslen, @{zombie_child_pid_key: @(pid)}); 839*94d3b452SApple OSS Distributions }); 840*94d3b452SApple OSS Distributions} 841*94d3b452SApple OSS Distributions 842*94d3b452SApple OSS DistributionsT_HELPER_DECL(exec_child_preexec, "child process pre-exec") 843*94d3b452SApple OSS Distributions{ 844*94d3b452SApple OSS Distributions dispatch_queue_t signal_processing_q = dispatch_queue_create("signal processing queue", NULL); 845*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(signal_processing_q, "signal processing queue"); 846*94d3b452SApple OSS Distributions 847*94d3b452SApple OSS Distributions signal(SIGUSR1, SIG_IGN); 848*94d3b452SApple OSS Distributions dispatch_source_t parent_sig_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, signal_processing_q); 849*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(parent_sig_src, "dispatch_source_create (child_sig_src)"); 850*94d3b452SApple OSS Distributions dispatch_source_set_event_handler(parent_sig_src, ^{ 851*94d3b452SApple OSS Distributions 852*94d3b452SApple OSS Distributions // Parent took a timestamp then signaled us: exec into the next process 853*94d3b452SApple OSS Distributions 854*94d3b452SApple OSS Distributions char path[PATH_MAX]; 855*94d3b452SApple OSS Distributions uint32_t path_size = sizeof(path); 856*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path, &path_size), "_NSGetExecutablePath"); 857*94d3b452SApple OSS Distributions char *args[] = { path, "-n", "exec_child_postexec", NULL }; 858*94d3b452SApple OSS Distributions 859*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(execve(args[0], args, NULL), "execing into exec_child_postexec"); 860*94d3b452SApple OSS Distributions }); 861*94d3b452SApple OSS Distributions dispatch_activate(parent_sig_src); 862*94d3b452SApple OSS Distributions 863*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kill(getppid(), SIGUSR1), "signaled parent to take timestamp"); 864*94d3b452SApple OSS Distributions 865*94d3b452SApple OSS Distributions sleep(100); 866*94d3b452SApple OSS Distributions // Should never get here 867*94d3b452SApple OSS Distributions T_FAIL("Received signal to exec from parent"); 868*94d3b452SApple OSS Distributions} 869*94d3b452SApple OSS Distributions 870*94d3b452SApple OSS DistributionsT_HELPER_DECL(exec_child_postexec, "child process post-exec to sample") 871*94d3b452SApple OSS Distributions{ 872*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kill(getppid(), SIGUSR1), "signaled parent to take stackshot"); 873*94d3b452SApple OSS Distributions sleep(100); 874*94d3b452SApple OSS Distributions // Should never get here 875*94d3b452SApple OSS Distributions T_FAIL("Killed by parent"); 876*94d3b452SApple OSS Distributions} 877*94d3b452SApple OSS Distributions 878*94d3b452SApple OSS DistributionsT_DECL(exec, "test getting full task snapshots for a task that execs") 879*94d3b452SApple OSS Distributions{ 880*94d3b452SApple OSS Distributions char path[PATH_MAX]; 881*94d3b452SApple OSS Distributions uint32_t path_size = sizeof(path); 882*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path, &path_size), "_NSGetExecutablePath"); 883*94d3b452SApple OSS Distributions char *args[] = { path, "-n", "exec_child_preexec", NULL }; 884*94d3b452SApple OSS Distributions 885*94d3b452SApple OSS Distributions dispatch_source_t child_sig_src; 886*94d3b452SApple OSS Distributions dispatch_semaphore_t child_ready_sem = dispatch_semaphore_create(0); 887*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(child_ready_sem, "exec child semaphore"); 888*94d3b452SApple OSS Distributions 889*94d3b452SApple OSS Distributions dispatch_queue_t signal_processing_q = dispatch_queue_create("signal processing queue", NULL); 890*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(signal_processing_q, "signal processing queue"); 891*94d3b452SApple OSS Distributions 892*94d3b452SApple OSS Distributions pid_t pid; 893*94d3b452SApple OSS Distributions 894*94d3b452SApple OSS Distributions T_LOG("spawning a child"); 895*94d3b452SApple OSS Distributions 896*94d3b452SApple OSS Distributions signal(SIGUSR1, SIG_IGN); 897*94d3b452SApple OSS Distributions child_sig_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, signal_processing_q); 898*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(child_sig_src, "dispatch_source_create (child_sig_src)"); 899*94d3b452SApple OSS Distributions 900*94d3b452SApple OSS Distributions dispatch_source_set_event_handler(child_sig_src, ^{ dispatch_semaphore_signal(child_ready_sem); }); 901*94d3b452SApple OSS Distributions dispatch_activate(child_sig_src); 902*94d3b452SApple OSS Distributions 903*94d3b452SApple OSS Distributions int sp_ret = posix_spawn(&pid, args[0], NULL, NULL, args, NULL); 904*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(sp_ret, "spawned process '%s' with PID %d", args[0], pid); 905*94d3b452SApple OSS Distributions 906*94d3b452SApple OSS Distributions dispatch_semaphore_wait(child_ready_sem, DISPATCH_TIME_FOREVER); 907*94d3b452SApple OSS Distributions uint64_t start_time = mach_absolute_time(); 908*94d3b452SApple OSS Distributions 909*94d3b452SApple OSS Distributions struct proc_uniqidentifierinfo proc_info_data = { }; 910*94d3b452SApple OSS Distributions int retval = proc_pidinfo(getpid(), PROC_PIDUNIQIDENTIFIERINFO, 0, &proc_info_data, sizeof(proc_info_data)); 911*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_POSIX_SUCCESS(retval, "proc_pidinfo PROC_PIDUNIQIDENTIFIERINFO"); 912*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ_INT(retval, (int) sizeof(proc_info_data), "proc_pidinfo PROC_PIDUNIQIDENTIFIERINFO returned data"); 913*94d3b452SApple OSS Distributions uint64_t unique_pid = proc_info_data.p_uniqueid; 914*94d3b452SApple OSS Distributions 915*94d3b452SApple OSS Distributions T_LOG("received signal from pre-exec child, unique_pid is %llu, timestamp is %llu", unique_pid, start_time); 916*94d3b452SApple OSS Distributions 917*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kill(pid, SIGUSR1), "signaled pre-exec child to exec"); 918*94d3b452SApple OSS Distributions 919*94d3b452SApple OSS Distributions dispatch_semaphore_wait(child_ready_sem, DISPATCH_TIME_FOREVER); 920*94d3b452SApple OSS Distributions 921*94d3b452SApple OSS Distributions T_LOG("received signal from post-exec child, capturing stackshot"); 922*94d3b452SApple OSS Distributions 923*94d3b452SApple OSS Distributions struct scenario scenario = { 924*94d3b452SApple OSS Distributions .name = "exec", 925*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_GET_GLOBAL_MEM_STATS 926*94d3b452SApple OSS Distributions | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_KCDATA_FORMAT 927*94d3b452SApple OSS Distributions | STACKSHOT_COLLECT_DELTA_SNAPSHOT), 928*94d3b452SApple OSS Distributions .since_timestamp = start_time 929*94d3b452SApple OSS Distributions }; 930*94d3b452SApple OSS Distributions 931*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^( void *ssbuf, size_t sslen) { 932*94d3b452SApple OSS Distributions // Kill the child 933*94d3b452SApple OSS Distributions int status; 934*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kill(pid, SIGKILL), "kill post-exec child %d", pid); 935*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(waitpid(pid, &status, 0), "waitpid on post-exec child"); 936*94d3b452SApple OSS Distributions 937*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_POSTEXEC | PARSE_STACKSHOT_DELTA, ssbuf, sslen, @{postexec_child_unique_pid_key: @(unique_pid)}); 938*94d3b452SApple OSS Distributions }); 939*94d3b452SApple OSS Distributions} 940*94d3b452SApple OSS Distributions 941*94d3b452SApple OSS DistributionsT_DECL( 942*94d3b452SApple OSS Distributions exec_inprogress, 943*94d3b452SApple OSS Distributions "test stackshots of processes in the middle of exec", 944*94d3b452SApple OSS Distributions T_META_ENABLED(false) /* rdar://111691318 */) 945*94d3b452SApple OSS Distributions{ 946*94d3b452SApple OSS Distributions pid_t pid; 947*94d3b452SApple OSS Distributions /* a BASH quine which execs itself as long as the parent doesn't exit */ 948*94d3b452SApple OSS Distributions char *bash_prog = "[[ $PPID -ne 1 ]] && exec /bin/bash -c \"$0\" \"$0\""; 949*94d3b452SApple OSS Distributions char *args[] = { "/bin/bash", "-c", bash_prog, bash_prog, NULL }; 950*94d3b452SApple OSS Distributions 951*94d3b452SApple OSS Distributions posix_spawnattr_t sattr; 952*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(posix_spawnattr_init(&sattr), "posix_spawnattr_init"); 953*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(posix_spawn(&pid, args[0], NULL, &sattr, args, NULL), "spawn exec_inprogress_child"); 954*94d3b452SApple OSS Distributions 955*94d3b452SApple OSS Distributions struct scenario scenario = { 956*94d3b452SApple OSS Distributions .name = "exec_inprogress", 957*94d3b452SApple OSS Distributions .flags = (STACKSHOT_KCDATA_FORMAT), 958*94d3b452SApple OSS Distributions .target_pid = pid, 959*94d3b452SApple OSS Distributions }; 960*94d3b452SApple OSS Distributions 961*94d3b452SApple OSS Distributions int tries = 0; 962*94d3b452SApple OSS Distributions int tries_limit = 30; 963*94d3b452SApple OSS Distributions __block bool found = false; 964*94d3b452SApple OSS Distributions __block uint64_t cid1 = 0, cid2 = 0; 965*94d3b452SApple OSS Distributions 966*94d3b452SApple OSS Distributions for (tries = 0; !found && tries < tries_limit; tries++) { 967*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, 968*94d3b452SApple OSS Distributions ^( void *ssbuf, size_t sslen) { 969*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_EXEC_INPROGRESS, 970*94d3b452SApple OSS Distributions ssbuf, sslen, @{ 971*94d3b452SApple OSS Distributions exec_inprogress_pid_key: @(pid), 972*94d3b452SApple OSS Distributions exec_inprogress_found_key: ^(uint64_t id1, uint64_t id2) { found = true; cid1 = id1; cid2 = id2; }}); 973*94d3b452SApple OSS Distributions }); 974*94d3b452SApple OSS Distributions } 975*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(kill(pid, SIGKILL), "killing exec loop"); 976*94d3b452SApple OSS Distributions T_ASSERT_TRUE(found, "able to find our execing process mid-exec in %d tries", tries); 977*94d3b452SApple OSS Distributions T_ASSERT_NE(cid1, cid2, "container IDs for in-progress exec are unique"); 978*94d3b452SApple OSS Distributions T_PASS("found mid-exec process in %d tries", tries); 979*94d3b452SApple OSS Distributions} 980*94d3b452SApple OSS Distributions 981*94d3b452SApple OSS Distributions#ifdef _LP64 982*94d3b452SApple OSS Distributions#if __has_feature(ptrauth_calls) 983*94d3b452SApple OSS Distributions#define __ptrauth_swift_async_context_parent \ 984*94d3b452SApple OSS Distributions __ptrauth(ptrauth_key_process_independent_data, 1, 0xbda2) 985*94d3b452SApple OSS Distributions#define __ptrauth_swift_async_context_resume \ 986*94d3b452SApple OSS Distributions __ptrauth(ptrauth_key_function_pointer, 1, 0xd707) 987*94d3b452SApple OSS Distributions#else 988*94d3b452SApple OSS Distributions#define __ptrauth_swift_async_context_parent 989*94d3b452SApple OSS Distributions#define __ptrauth_swift_async_context_resume 990*94d3b452SApple OSS Distributions#endif 991*94d3b452SApple OSS Distributions// Add 1 to match the symbolication aid added by the stackshot backtracer. 992*94d3b452SApple OSS Distributions#define asyncstack_frame(x) ((uintptr_t)(void *)ptrauth_strip((void *)(x), ptrauth_key_function_pointer) + 1) 993*94d3b452SApple OSS Distributions 994*94d3b452SApple OSS Distributions// This struct fakes the Swift AsyncContext struct which is used by 995*94d3b452SApple OSS Distributions// the Swift concurrency runtime. We only care about the first 2 fields. 996*94d3b452SApple OSS Distributionsstruct fake_async_context { 997*94d3b452SApple OSS Distributions struct fake_async_context* __ptrauth_swift_async_context_parent next; 998*94d3b452SApple OSS Distributions void(*__ptrauth_swift_async_context_resume resume_pc)(void); 999*94d3b452SApple OSS Distributions}; 1000*94d3b452SApple OSS Distributions 1001*94d3b452SApple OSS Distributionsstatic void 1002*94d3b452SApple OSS Distributionslevel1_func() 1003*94d3b452SApple OSS Distributions{ 1004*94d3b452SApple OSS Distributions} 1005*94d3b452SApple OSS Distributionsstatic void 1006*94d3b452SApple OSS Distributionslevel2_func() 1007*94d3b452SApple OSS Distributions{ 1008*94d3b452SApple OSS Distributions} 1009*94d3b452SApple OSS Distributions 1010*94d3b452SApple OSS Distributions// Create a chain of fake async contexts; sync with asyncstack_expected_stack below 1011*94d3b452SApple OSS Distributionsstatic alignas(16) struct fake_async_context level1 = { 0, level1_func }; 1012*94d3b452SApple OSS Distributionsstatic alignas(16) struct fake_async_context level2 = { &level1, level2_func }; 1013*94d3b452SApple OSS Distributions 1014*94d3b452SApple OSS Distributionsstruct async_test_semaphores { 1015*94d3b452SApple OSS Distributions dispatch_semaphore_t child_ready_sem; /* signal parent we're ready */ 1016*94d3b452SApple OSS Distributions dispatch_semaphore_t child_exit_sem; /* parent tells us to go away */ 1017*94d3b452SApple OSS Distributions}; 1018*94d3b452SApple OSS Distributions 1019*94d3b452SApple OSS Distributions#define ASYNCSTACK_THREAD_NAME "asyncstack_thread" 1020*94d3b452SApple OSS Distributions 1021*94d3b452SApple OSS Distributionsstatic void __attribute__((noinline, not_tail_called)) 1022*94d3b452SApple OSS Distributionsexpect_asyncstack(void *arg) 1023*94d3b452SApple OSS Distributions{ 1024*94d3b452SApple OSS Distributions struct async_test_semaphores *async_ts = arg; 1025*94d3b452SApple OSS Distributions 1026*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(pthread_setname_np(ASYNCSTACK_THREAD_NAME), 1027*94d3b452SApple OSS Distributions "set thread name to %s", ASYNCSTACK_THREAD_NAME); 1028*94d3b452SApple OSS Distributions 1029*94d3b452SApple OSS Distributions /* Tell the main thread we're all set up, then wait for permission to exit */ 1030*94d3b452SApple OSS Distributions dispatch_semaphore_signal(async_ts->child_ready_sem); 1031*94d3b452SApple OSS Distributions dispatch_semaphore_wait(async_ts->child_exit_sem, DISPATCH_TIME_FOREVER); 1032*94d3b452SApple OSS Distributions usleep(1); /* make sure we don't tailcall semaphore_wait */ 1033*94d3b452SApple OSS Distributions} 1034*94d3b452SApple OSS Distributions 1035*94d3b452SApple OSS Distributionsstatic void * 1036*94d3b452SApple OSS Distributionsasyncstack_thread(void *arg) 1037*94d3b452SApple OSS Distributions{ 1038*94d3b452SApple OSS Distributions uint64_t *fp = __builtin_frame_address(0); 1039*94d3b452SApple OSS Distributions // We cannot use a variable of pointer type, because this ABI is valid 1040*94d3b452SApple OSS Distributions // on arm64_32 where pointers are 32bits, but the context pointer will 1041*94d3b452SApple OSS Distributions // still be stored in a 64bits slot on the stack. 1042*94d3b452SApple OSS Distributions#if __has_feature(ptrauth_calls) 1043*94d3b452SApple OSS Distributions#define __stack_context_auth __ptrauth(ptrauth_key_process_dependent_data, 1, \ 1044*94d3b452SApple OSS Distributions 0xc31a) 1045*94d3b452SApple OSS Distributions struct fake_async_context * __stack_context_auth ctx = &level2; 1046*94d3b452SApple OSS Distributions#else // __has_feature(ptrauth_calls) 1047*94d3b452SApple OSS Distributions /* struct fake_async_context * */uint64_t ctx = (uintptr_t)&level2; 1048*94d3b452SApple OSS Distributions#endif // !__has_feature(ptrauth_calls) 1049*94d3b452SApple OSS Distributions 1050*94d3b452SApple OSS Distributions // The signature of an async frame on the OS stack is: 1051*94d3b452SApple OSS Distributions // [ <AsyncContext address>, <Saved FP | (1<<60)>, <return address> ] 1052*94d3b452SApple OSS Distributions // The Async context must be right before the saved FP on the stack. This 1053*94d3b452SApple OSS Distributions // should happen naturally in an optimized build as it is the only 1054*94d3b452SApple OSS Distributions // variable on the stack. 1055*94d3b452SApple OSS Distributions // This function cannot use T_ASSERT_* becuse it changes the stack 1056*94d3b452SApple OSS Distributions // layout. 1057*94d3b452SApple OSS Distributions assert((uintptr_t)fp - (uintptr_t)&ctx == 8); 1058*94d3b452SApple OSS Distributions 1059*94d3b452SApple OSS Distributions // Modify the saved FP on the stack to include the async frame marker 1060*94d3b452SApple OSS Distributions *fp |= (0x1ULL << 60); 1061*94d3b452SApple OSS Distributions expect_asyncstack(arg); 1062*94d3b452SApple OSS Distributions return NULL; 1063*94d3b452SApple OSS Distributions} 1064*94d3b452SApple OSS Distributions 1065*94d3b452SApple OSS DistributionsT_DECL(asyncstack, "test swift async stack entries") 1066*94d3b452SApple OSS Distributions{ 1067*94d3b452SApple OSS Distributions struct scenario scenario = { 1068*94d3b452SApple OSS Distributions .name = "asyncstack", 1069*94d3b452SApple OSS Distributions .flags = STACKSHOT_KCDATA_FORMAT | STACKSHOT_SAVE_LOADINFO, 1070*94d3b452SApple OSS Distributions }; 1071*94d3b452SApple OSS Distributions struct async_test_semaphores async_ts = { 1072*94d3b452SApple OSS Distributions .child_ready_sem = dispatch_semaphore_create(0), 1073*94d3b452SApple OSS Distributions .child_exit_sem = dispatch_semaphore_create(0), 1074*94d3b452SApple OSS Distributions }; 1075*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(async_ts.child_ready_sem, "child_ready_sem alloc"); 1076*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(async_ts.child_exit_sem, "child_exit_sem alloc"); 1077*94d3b452SApple OSS Distributions 1078*94d3b452SApple OSS Distributions pthread_t pthread; 1079*94d3b452SApple OSS Distributions __block uint64_t threadid = 0; 1080*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(pthread_create(&pthread, NULL, asyncstack_thread, &async_ts), "pthread_create"); 1081*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(pthread_threadid_np(pthread, &threadid), "pthread_threadid_np"); 1082*94d3b452SApple OSS Distributions 1083*94d3b452SApple OSS Distributions dispatch_semaphore_wait(async_ts.child_ready_sem, DISPATCH_TIME_FOREVER); 1084*94d3b452SApple OSS Distributions 1085*94d3b452SApple OSS Distributions take_stackshot(&scenario, true, ^( void *ssbuf, size_t sslen) { 1086*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_ASYNCSTACK, ssbuf, sslen, @{ 1087*94d3b452SApple OSS Distributions asyncstack_expected_threadid_key: @(threadid), 1088*94d3b452SApple OSS Distributions asyncstack_expected_stack_key: @[ @(asyncstack_frame(level2_func)), @(asyncstack_frame(level1_func)) ], 1089*94d3b452SApple OSS Distributions }); 1090*94d3b452SApple OSS Distributions }); 1091*94d3b452SApple OSS Distributions 1092*94d3b452SApple OSS Distributions dispatch_semaphore_signal(async_ts.child_exit_sem); 1093*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(pthread_join(pthread, NULL), "wait for thread"); 1094*94d3b452SApple OSS Distributions 1095*94d3b452SApple OSS Distributions} 1096*94d3b452SApple OSS Distributions#endif /* #ifdef _LP64 */ 1097*94d3b452SApple OSS Distributions 1098*94d3b452SApple OSS Distributionsstatic uint32_t 1099*94d3b452SApple OSS Distributionsget_user_promotion_basepri(void) 1100*94d3b452SApple OSS Distributions{ 1101*94d3b452SApple OSS Distributions mach_msg_type_number_t count = THREAD_POLICY_STATE_COUNT; 1102*94d3b452SApple OSS Distributions struct thread_policy_state thread_policy; 1103*94d3b452SApple OSS Distributions boolean_t get_default = FALSE; 1104*94d3b452SApple OSS Distributions mach_port_t thread_port = pthread_mach_thread_np(pthread_self()); 1105*94d3b452SApple OSS Distributions 1106*94d3b452SApple OSS Distributions kern_return_t kr = thread_policy_get(thread_port, THREAD_POLICY_STATE, 1107*94d3b452SApple OSS Distributions (thread_policy_t)&thread_policy, &count, &get_default); 1108*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_policy_get"); 1109*94d3b452SApple OSS Distributions return thread_policy.thps_user_promotion_basepri; 1110*94d3b452SApple OSS Distributions} 1111*94d3b452SApple OSS Distributions 1112*94d3b452SApple OSS Distributionsstatic int 1113*94d3b452SApple OSS Distributionsget_pri(thread_t thread_port) 1114*94d3b452SApple OSS Distributions{ 1115*94d3b452SApple OSS Distributions kern_return_t kr; 1116*94d3b452SApple OSS Distributions 1117*94d3b452SApple OSS Distributions thread_extended_info_data_t extended_info; 1118*94d3b452SApple OSS Distributions mach_msg_type_number_t count = THREAD_EXTENDED_INFO_COUNT; 1119*94d3b452SApple OSS Distributions kr = thread_info(thread_port, THREAD_EXTENDED_INFO, 1120*94d3b452SApple OSS Distributions (thread_info_t)&extended_info, &count); 1121*94d3b452SApple OSS Distributions 1122*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_info"); 1123*94d3b452SApple OSS Distributions 1124*94d3b452SApple OSS Distributions return extended_info.pth_curpri; 1125*94d3b452SApple OSS Distributions} 1126*94d3b452SApple OSS Distributions 1127*94d3b452SApple OSS Distributions 1128*94d3b452SApple OSS DistributionsT_DECL(turnstile_singlehop, "turnstile single hop test") 1129*94d3b452SApple OSS Distributions{ 1130*94d3b452SApple OSS Distributions dispatch_queue_t dq1, dq2; 1131*94d3b452SApple OSS Distributions dispatch_semaphore_t sema_x; 1132*94d3b452SApple OSS Distributions dispatch_queue_attr_t dq1_attr, dq2_attr; 1133*94d3b452SApple OSS Distributions __block qos_class_t main_qos = 0; 1134*94d3b452SApple OSS Distributions __block int main_relpri = 0, main_relpri2 = 0, main_afterpri = 0; 1135*94d3b452SApple OSS Distributions struct scenario scenario = { 1136*94d3b452SApple OSS Distributions .name = "turnstile_singlehop", 1137*94d3b452SApple OSS Distributions .flags = (STACKSHOT_THREAD_WAITINFO | STACKSHOT_KCDATA_FORMAT), 1138*94d3b452SApple OSS Distributions }; 1139*94d3b452SApple OSS Distributions dq1_attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0); 1140*94d3b452SApple OSS Distributions dq2_attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0); 1141*94d3b452SApple OSS Distributions pthread_mutex_t lock_a = PTHREAD_MUTEX_INITIALIZER; 1142*94d3b452SApple OSS Distributions pthread_mutex_t lock_b = PTHREAD_MUTEX_INITIALIZER; 1143*94d3b452SApple OSS Distributions 1144*94d3b452SApple OSS Distributions pthread_mutex_t *lockap = &lock_a, *lockbp = &lock_b; 1145*94d3b452SApple OSS Distributions 1146*94d3b452SApple OSS Distributions dq1 = dispatch_queue_create("q1", dq1_attr); 1147*94d3b452SApple OSS Distributions dq2 = dispatch_queue_create("q2", dq2_attr); 1148*94d3b452SApple OSS Distributions sema_x = dispatch_semaphore_create(0); 1149*94d3b452SApple OSS Distributions 1150*94d3b452SApple OSS Distributions pthread_mutex_lock(lockap); 1151*94d3b452SApple OSS Distributions dispatch_async(dq1, ^{ 1152*94d3b452SApple OSS Distributions pthread_mutex_lock(lockbp); 1153*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(pthread_get_qos_class_np(pthread_self(), &main_qos, &main_relpri), "get qos class"); 1154*94d3b452SApple OSS Distributions T_LOG("The priority of q1 is %d\n", get_pri(mach_thread_self())); 1155*94d3b452SApple OSS Distributions dispatch_semaphore_signal(sema_x); 1156*94d3b452SApple OSS Distributions pthread_mutex_lock(lockap); 1157*94d3b452SApple OSS Distributions }); 1158*94d3b452SApple OSS Distributions dispatch_semaphore_wait(sema_x, DISPATCH_TIME_FOREVER); 1159*94d3b452SApple OSS Distributions 1160*94d3b452SApple OSS Distributions T_LOG("Async1 completed"); 1161*94d3b452SApple OSS Distributions 1162*94d3b452SApple OSS Distributions pthread_set_qos_class_self_np(QOS_CLASS_UTILITY, 0); 1163*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(pthread_get_qos_class_np(pthread_self(), &main_qos, &main_relpri), "get qos class"); 1164*94d3b452SApple OSS Distributions T_LOG("The priority of main is %d\n", get_pri(mach_thread_self())); 1165*94d3b452SApple OSS Distributions main_relpri = get_pri(mach_thread_self()); 1166*94d3b452SApple OSS Distributions 1167*94d3b452SApple OSS Distributions dispatch_async(dq2, ^{ 1168*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(pthread_get_qos_class_np(pthread_self(), &main_qos, &main_relpri2), "get qos class"); 1169*94d3b452SApple OSS Distributions T_LOG("The priority of q2 is %d\n", get_pri(mach_thread_self())); 1170*94d3b452SApple OSS Distributions dispatch_semaphore_signal(sema_x); 1171*94d3b452SApple OSS Distributions pthread_mutex_lock(lockbp); 1172*94d3b452SApple OSS Distributions }); 1173*94d3b452SApple OSS Distributions dispatch_semaphore_wait(sema_x, DISPATCH_TIME_FOREVER); 1174*94d3b452SApple OSS Distributions 1175*94d3b452SApple OSS Distributions T_LOG("Async2 completed"); 1176*94d3b452SApple OSS Distributions 1177*94d3b452SApple OSS Distributions while (1) { 1178*94d3b452SApple OSS Distributions main_afterpri = (int) get_user_promotion_basepri(); 1179*94d3b452SApple OSS Distributions if (main_relpri != main_afterpri) { 1180*94d3b452SApple OSS Distributions T_LOG("Success with promotion pri is %d", main_afterpri); 1181*94d3b452SApple OSS Distributions break; 1182*94d3b452SApple OSS Distributions } 1183*94d3b452SApple OSS Distributions 1184*94d3b452SApple OSS Distributions usleep(100); 1185*94d3b452SApple OSS Distributions } 1186*94d3b452SApple OSS Distributions 1187*94d3b452SApple OSS Distributions take_stackshot(&scenario, true, ^( void *ssbuf, size_t sslen) { 1188*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_TURNSTILEINFO, ssbuf, sslen, nil); 1189*94d3b452SApple OSS Distributions }); 1190*94d3b452SApple OSS Distributions} 1191*94d3b452SApple OSS Distributions 1192*94d3b452SApple OSS Distributions 1193*94d3b452SApple OSS Distributionsstatic void 1194*94d3b452SApple OSS Distributionsexpect_instrs_cycles_in_stackshot(void *ssbuf, size_t sslen) 1195*94d3b452SApple OSS Distributions{ 1196*94d3b452SApple OSS Distributions kcdata_iter_t iter = kcdata_iter(ssbuf, sslen); 1197*94d3b452SApple OSS Distributions 1198*94d3b452SApple OSS Distributions bool in_task = false; 1199*94d3b452SApple OSS Distributions bool in_thread = false; 1200*94d3b452SApple OSS Distributions bool saw_instrs_cycles = false; 1201*94d3b452SApple OSS Distributions iter = kcdata_iter_next(iter); 1202*94d3b452SApple OSS Distributions 1203*94d3b452SApple OSS Distributions KCDATA_ITER_FOREACH(iter) { 1204*94d3b452SApple OSS Distributions switch (kcdata_iter_type(iter)) { 1205*94d3b452SApple OSS Distributions case KCDATA_TYPE_CONTAINER_BEGIN: 1206*94d3b452SApple OSS Distributions switch (kcdata_iter_container_type(iter)) { 1207*94d3b452SApple OSS Distributions case STACKSHOT_KCCONTAINER_TASK: 1208*94d3b452SApple OSS Distributions in_task = true; 1209*94d3b452SApple OSS Distributions saw_instrs_cycles = false; 1210*94d3b452SApple OSS Distributions break; 1211*94d3b452SApple OSS Distributions 1212*94d3b452SApple OSS Distributions case STACKSHOT_KCCONTAINER_THREAD: 1213*94d3b452SApple OSS Distributions in_thread = true; 1214*94d3b452SApple OSS Distributions saw_instrs_cycles = false; 1215*94d3b452SApple OSS Distributions break; 1216*94d3b452SApple OSS Distributions 1217*94d3b452SApple OSS Distributions default: 1218*94d3b452SApple OSS Distributions break; 1219*94d3b452SApple OSS Distributions } 1220*94d3b452SApple OSS Distributions break; 1221*94d3b452SApple OSS Distributions 1222*94d3b452SApple OSS Distributions case STACKSHOT_KCTYPE_INSTRS_CYCLES: 1223*94d3b452SApple OSS Distributions saw_instrs_cycles = true; 1224*94d3b452SApple OSS Distributions break; 1225*94d3b452SApple OSS Distributions 1226*94d3b452SApple OSS Distributions case KCDATA_TYPE_CONTAINER_END: 1227*94d3b452SApple OSS Distributions if (in_thread) { 1228*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_TRUE(saw_instrs_cycles, 1229*94d3b452SApple OSS Distributions "saw instructions and cycles in thread"); 1230*94d3b452SApple OSS Distributions in_thread = false; 1231*94d3b452SApple OSS Distributions } else if (in_task) { 1232*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_TRUE(saw_instrs_cycles, 1233*94d3b452SApple OSS Distributions "saw instructions and cycles in task"); 1234*94d3b452SApple OSS Distributions in_task = false; 1235*94d3b452SApple OSS Distributions } 1236*94d3b452SApple OSS Distributions 1237*94d3b452SApple OSS Distributions default: 1238*94d3b452SApple OSS Distributions break; 1239*94d3b452SApple OSS Distributions } 1240*94d3b452SApple OSS Distributions } 1241*94d3b452SApple OSS Distributions} 1242*94d3b452SApple OSS Distributions 1243*94d3b452SApple OSS Distributionsstatic void 1244*94d3b452SApple OSS Distributionsskip_if_monotonic_unsupported(void) 1245*94d3b452SApple OSS Distributions{ 1246*94d3b452SApple OSS Distributions int supported = 0; 1247*94d3b452SApple OSS Distributions size_t supported_size = sizeof(supported); 1248*94d3b452SApple OSS Distributions int ret = sysctlbyname("kern.monotonic.supported", &supported, 1249*94d3b452SApple OSS Distributions &supported_size, 0, 0); 1250*94d3b452SApple OSS Distributions if (ret < 0 || !supported) { 1251*94d3b452SApple OSS Distributions T_SKIP("monotonic is unsupported"); 1252*94d3b452SApple OSS Distributions } 1253*94d3b452SApple OSS Distributions} 1254*94d3b452SApple OSS Distributions 1255*94d3b452SApple OSS DistributionsT_DECL(instrs_cycles, "test a getting instructions and cycles in stackshot") 1256*94d3b452SApple OSS Distributions{ 1257*94d3b452SApple OSS Distributions skip_if_monotonic_unsupported(); 1258*94d3b452SApple OSS Distributions 1259*94d3b452SApple OSS Distributions struct scenario scenario = { 1260*94d3b452SApple OSS Distributions .name = "instrs-cycles", 1261*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_INSTRS_CYCLES 1262*94d3b452SApple OSS Distributions | STACKSHOT_KCDATA_FORMAT), 1263*94d3b452SApple OSS Distributions }; 1264*94d3b452SApple OSS Distributions 1265*94d3b452SApple OSS Distributions T_LOG("attempting to take stackshot with instructions and cycles"); 1266*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 1267*94d3b452SApple OSS Distributions parse_stackshot(0, ssbuf, sslen, nil); 1268*94d3b452SApple OSS Distributions expect_instrs_cycles_in_stackshot(ssbuf, sslen); 1269*94d3b452SApple OSS Distributions }); 1270*94d3b452SApple OSS Distributions} 1271*94d3b452SApple OSS Distributions 1272*94d3b452SApple OSS DistributionsT_DECL(delta_instrs_cycles, 1273*94d3b452SApple OSS Distributions "test delta stackshots with instructions and cycles") 1274*94d3b452SApple OSS Distributions{ 1275*94d3b452SApple OSS Distributions skip_if_monotonic_unsupported(); 1276*94d3b452SApple OSS Distributions 1277*94d3b452SApple OSS Distributions struct scenario scenario = { 1278*94d3b452SApple OSS Distributions .name = "delta-instrs-cycles", 1279*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_INSTRS_CYCLES 1280*94d3b452SApple OSS Distributions | STACKSHOT_KCDATA_FORMAT), 1281*94d3b452SApple OSS Distributions }; 1282*94d3b452SApple OSS Distributions 1283*94d3b452SApple OSS Distributions T_LOG("taking full stackshot"); 1284*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 1285*94d3b452SApple OSS Distributions uint64_t stackshot_time = stackshot_timestamp(ssbuf, sslen); 1286*94d3b452SApple OSS Distributions 1287*94d3b452SApple OSS Distributions T_LOG("taking delta stackshot since time %" PRIu64, stackshot_time); 1288*94d3b452SApple OSS Distributions 1289*94d3b452SApple OSS Distributions parse_stackshot(0, ssbuf, sslen, nil); 1290*94d3b452SApple OSS Distributions expect_instrs_cycles_in_stackshot(ssbuf, sslen); 1291*94d3b452SApple OSS Distributions 1292*94d3b452SApple OSS Distributions struct scenario delta_scenario = { 1293*94d3b452SApple OSS Distributions .name = "delta-instrs-cycles-next", 1294*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_INSTRS_CYCLES 1295*94d3b452SApple OSS Distributions | STACKSHOT_KCDATA_FORMAT 1296*94d3b452SApple OSS Distributions | STACKSHOT_COLLECT_DELTA_SNAPSHOT), 1297*94d3b452SApple OSS Distributions .since_timestamp = stackshot_time, 1298*94d3b452SApple OSS Distributions }; 1299*94d3b452SApple OSS Distributions 1300*94d3b452SApple OSS Distributions take_stackshot(&delta_scenario, false, ^(void *dssbuf, size_t dsslen) { 1301*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_DELTA, dssbuf, dsslen, nil); 1302*94d3b452SApple OSS Distributions expect_instrs_cycles_in_stackshot(dssbuf, dsslen); 1303*94d3b452SApple OSS Distributions }); 1304*94d3b452SApple OSS Distributions }); 1305*94d3b452SApple OSS Distributions} 1306*94d3b452SApple OSS Distributions 1307*94d3b452SApple OSS Distributionsstatic void 1308*94d3b452SApple OSS Distributionscheck_thread_groups_supported() 1309*94d3b452SApple OSS Distributions{ 1310*94d3b452SApple OSS Distributions int err; 1311*94d3b452SApple OSS Distributions int supported = 0; 1312*94d3b452SApple OSS Distributions size_t supported_size = sizeof(supported); 1313*94d3b452SApple OSS Distributions err = sysctlbyname("kern.thread_groups_supported", &supported, &supported_size, NULL, 0); 1314*94d3b452SApple OSS Distributions 1315*94d3b452SApple OSS Distributions if (err || !supported) 1316*94d3b452SApple OSS Distributions T_SKIP("thread groups not supported on this system"); 1317*94d3b452SApple OSS Distributions} 1318*94d3b452SApple OSS Distributions 1319*94d3b452SApple OSS DistributionsT_DECL(thread_groups, "test getting thread groups in stackshot") 1320*94d3b452SApple OSS Distributions{ 1321*94d3b452SApple OSS Distributions check_thread_groups_supported(); 1322*94d3b452SApple OSS Distributions 1323*94d3b452SApple OSS Distributions struct scenario scenario = { 1324*94d3b452SApple OSS Distributions .name = "thread-groups", 1325*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_THREAD_GROUP 1326*94d3b452SApple OSS Distributions | STACKSHOT_KCDATA_FORMAT), 1327*94d3b452SApple OSS Distributions }; 1328*94d3b452SApple OSS Distributions 1329*94d3b452SApple OSS Distributions T_LOG("attempting to take stackshot with thread group flag"); 1330*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 1331*94d3b452SApple OSS Distributions parse_thread_group_stackshot(ssbuf, sslen); 1332*94d3b452SApple OSS Distributions }); 1333*94d3b452SApple OSS Distributions} 1334*94d3b452SApple OSS Distributions 1335*94d3b452SApple OSS DistributionsT_DECL(compactinfo, "test compactinfo inclusion") 1336*94d3b452SApple OSS Distributions{ 1337*94d3b452SApple OSS Distributions struct scenario scenario = { 1338*94d3b452SApple OSS Distributions .name = "compactinfo", 1339*94d3b452SApple OSS Distributions .target_pid = getpid(), 1340*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_DYLD_COMPACTINFO 1341*94d3b452SApple OSS Distributions | STACKSHOT_KCDATA_FORMAT), 1342*94d3b452SApple OSS Distributions }; 1343*94d3b452SApple OSS Distributions 1344*94d3b452SApple OSS Distributions T_LOG("attempting to take stackshot with compactinfo flag"); 1345*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 1346*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_COMPACTINFO, ssbuf, sslen, nil); 1347*94d3b452SApple OSS Distributions }); 1348*94d3b452SApple OSS Distributions} 1349*94d3b452SApple OSS Distributions 1350*94d3b452SApple OSS DistributionsT_DECL(suspendinfo, "test task suspend info inclusion") 1351*94d3b452SApple OSS Distributions{ 1352*94d3b452SApple OSS Distributions struct scenario scenario = { 1353*94d3b452SApple OSS Distributions .name = "suspendinfo", 1354*94d3b452SApple OSS Distributions .target_pid = getpid(), 1355*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_KCDATA_FORMAT), 1356*94d3b452SApple OSS Distributions }; 1357*94d3b452SApple OSS Distributions 1358*94d3b452SApple OSS Distributions T_LOG("attempting to take stackshot with suspendinfo flag"); 1359*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 1360*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_SUSPENDINFO, ssbuf, sslen, nil); 1361*94d3b452SApple OSS Distributions }); 1362*94d3b452SApple OSS Distributions} 1363*94d3b452SApple OSS Distributions 1364*94d3b452SApple OSS Distributionsstatic NSMutableSet * find_driverkit_pids(io_registry_entry_t root) { 1365*94d3b452SApple OSS Distributions NSMutableSet * driverkit_pids = [NSMutableSet setWithCapacity:3]; 1366*94d3b452SApple OSS Distributions io_registry_entry_t current = IO_OBJECT_NULL; 1367*94d3b452SApple OSS Distributions io_iterator_t iter = IO_OBJECT_NULL; 1368*94d3b452SApple OSS Distributions 1369*94d3b452SApple OSS Distributions T_EXPECT_MACH_SUCCESS(IORegistryEntryGetChildIterator(root, kIOServicePlane, &iter), "get registry iterator"); 1370*94d3b452SApple OSS Distributions 1371*94d3b452SApple OSS Distributions while ((current = IOIteratorNext(iter)) != IO_OBJECT_NULL) { 1372*94d3b452SApple OSS Distributions if (_IOObjectConformsTo(current, "IOUserServer", kIOClassNameOverrideNone)) { 1373*94d3b452SApple OSS Distributions CFMutableDictionaryRef cfProperties = NULL; 1374*94d3b452SApple OSS Distributions NSMutableDictionary * properties; 1375*94d3b452SApple OSS Distributions NSString * client_creator_info; 1376*94d3b452SApple OSS Distributions NSArray<NSString *> *creator_info_array; 1377*94d3b452SApple OSS Distributions pid_t pid; 1378*94d3b452SApple OSS Distributions 1379*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_MACH_SUCCESS(IORegistryEntryCreateCFProperties(current, &cfProperties, kCFAllocatorDefault, kNilOptions), "get properties"); 1380*94d3b452SApple OSS Distributions properties = CFBridgingRelease(cfProperties); 1381*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(properties, "properties is not null"); 1382*94d3b452SApple OSS Distributions client_creator_info = properties[@kIOUserClientCreatorKey]; 1383*94d3b452SApple OSS Distributions creator_info_array = [client_creator_info componentsSeparatedByString:@","]; 1384*94d3b452SApple OSS Distributions if ([creator_info_array[0] hasPrefix:@"pid"]) { 1385*94d3b452SApple OSS Distributions NSArray<NSString *> *pid_info = [creator_info_array[0] componentsSeparatedByString:@" "]; 1386*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(pid_info.count, 2UL, "Get pid info components from %s", creator_info_array[0].UTF8String); 1387*94d3b452SApple OSS Distributions pid = pid_info[1].intValue; 1388*94d3b452SApple OSS Distributions } else { 1389*94d3b452SApple OSS Distributions T_ASSERT_FAIL("No pid info in client creator info: %s", client_creator_info.UTF8String); 1390*94d3b452SApple OSS Distributions } 1391*94d3b452SApple OSS Distributions T_LOG("Found driver pid %d", pid); 1392*94d3b452SApple OSS Distributions [driverkit_pids addObject:[NSNumber numberWithInt:pid]]; 1393*94d3b452SApple OSS Distributions } else { 1394*94d3b452SApple OSS Distributions [driverkit_pids unionSet:find_driverkit_pids(current)]; 1395*94d3b452SApple OSS Distributions } 1396*94d3b452SApple OSS Distributions IOObjectRelease(current); 1397*94d3b452SApple OSS Distributions } 1398*94d3b452SApple OSS Distributions 1399*94d3b452SApple OSS Distributions IOObjectRelease(iter); 1400*94d3b452SApple OSS Distributions return driverkit_pids; 1401*94d3b452SApple OSS Distributions} 1402*94d3b452SApple OSS Distributions 1403*94d3b452SApple OSS DistributionsT_DECL(driverkit, "test driverkit inclusion") 1404*94d3b452SApple OSS Distributions{ 1405*94d3b452SApple OSS Distributions struct scenario scenario = { 1406*94d3b452SApple OSS Distributions .name = "driverkit", 1407*94d3b452SApple OSS Distributions .target_kernel = true, 1408*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_KCDATA_FORMAT 1409*94d3b452SApple OSS Distributions | STACKSHOT_INCLUDE_DRIVER_THREADS_IN_KERNEL), 1410*94d3b452SApple OSS Distributions }; 1411*94d3b452SApple OSS Distributions 1412*94d3b452SApple OSS Distributions io_registry_entry_t root = IORegistryGetRootEntry(kIOMainPortDefault); 1413*94d3b452SApple OSS Distributions NSMutableSet * driverkit_pids = find_driverkit_pids(root); 1414*94d3b452SApple OSS Distributions IOObjectRelease(root); 1415*94d3b452SApple OSS Distributions 1416*94d3b452SApple OSS Distributions T_LOG("expecting to find %lu driverkit processes", [driverkit_pids count]); 1417*94d3b452SApple OSS Distributions T_LOG("attempting to take stackshot with STACKSHOT_INCLUDE_DRIVER_THREADS_IN_KERNEL flag"); 1418*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 1419*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_DRIVERKIT, ssbuf, sslen, @{ 1420*94d3b452SApple OSS Distributions driverkit_found_key: ^(pid_t pid) { 1421*94d3b452SApple OSS Distributions [driverkit_pids removeObject:[NSNumber numberWithInt:pid]]; 1422*94d3b452SApple OSS Distributions }}); 1423*94d3b452SApple OSS Distributions }); 1424*94d3b452SApple OSS Distributions 1425*94d3b452SApple OSS Distributions T_EXPECT_EQ([driverkit_pids count], (NSUInteger)0, "found expected number of driverkit processes"); 1426*94d3b452SApple OSS Distributions} 1427*94d3b452SApple OSS Distributions 1428*94d3b452SApple OSS Distributionsstatic void 1429*94d3b452SApple OSS Distributionsparse_page_table_asid_stackshot(void **ssbuf, size_t sslen) 1430*94d3b452SApple OSS Distributions{ 1431*94d3b452SApple OSS Distributions bool seen_asid = false; 1432*94d3b452SApple OSS Distributions bool seen_page_table_snapshot = false; 1433*94d3b452SApple OSS Distributions kcdata_iter_t iter = kcdata_iter(ssbuf, sslen); 1434*94d3b452SApple OSS Distributions T_ASSERT_EQ(kcdata_iter_type(iter), KCDATA_BUFFER_BEGIN_STACKSHOT, 1435*94d3b452SApple OSS Distributions "buffer provided is a stackshot"); 1436*94d3b452SApple OSS Distributions 1437*94d3b452SApple OSS Distributions iter = kcdata_iter_next(iter); 1438*94d3b452SApple OSS Distributions KCDATA_ITER_FOREACH(iter) { 1439*94d3b452SApple OSS Distributions switch (kcdata_iter_type(iter)) { 1440*94d3b452SApple OSS Distributions case KCDATA_TYPE_ARRAY: { 1441*94d3b452SApple OSS Distributions T_QUIET; 1442*94d3b452SApple OSS Distributions T_ASSERT_TRUE(kcdata_iter_array_valid(iter), 1443*94d3b452SApple OSS Distributions "checked that array is valid"); 1444*94d3b452SApple OSS Distributions 1445*94d3b452SApple OSS Distributions if (kcdata_iter_array_elem_type(iter) != STACKSHOT_KCTYPE_PAGE_TABLES) { 1446*94d3b452SApple OSS Distributions continue; 1447*94d3b452SApple OSS Distributions } 1448*94d3b452SApple OSS Distributions 1449*94d3b452SApple OSS Distributions T_ASSERT_FALSE(seen_page_table_snapshot, "check that we haven't yet seen a page table snapshot"); 1450*94d3b452SApple OSS Distributions seen_page_table_snapshot = true; 1451*94d3b452SApple OSS Distributions 1452*94d3b452SApple OSS Distributions T_ASSERT_EQ((size_t) kcdata_iter_array_elem_size(iter), sizeof(uint64_t), 1453*94d3b452SApple OSS Distributions "check that each element of the pagetable dump is the expected size"); 1454*94d3b452SApple OSS Distributions 1455*94d3b452SApple OSS Distributions uint64_t *pt_array = kcdata_iter_payload(iter); 1456*94d3b452SApple OSS Distributions uint32_t elem_count = kcdata_iter_array_elem_count(iter); 1457*94d3b452SApple OSS Distributions uint32_t j; 1458*94d3b452SApple OSS Distributions bool nonzero_tte = false; 1459*94d3b452SApple OSS Distributions for (j = 0; j < elem_count;) { 1460*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_LE(j + 4, elem_count, "check for valid page table segment header"); 1461*94d3b452SApple OSS Distributions uint64_t pa = pt_array[j]; 1462*94d3b452SApple OSS Distributions uint64_t num_entries = pt_array[j + 1]; 1463*94d3b452SApple OSS Distributions uint64_t start_va = pt_array[j + 2]; 1464*94d3b452SApple OSS Distributions uint64_t end_va = pt_array[j + 3]; 1465*94d3b452SApple OSS Distributions 1466*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NE(pa, (uint64_t) 0, "check that the pagetable physical address is non-zero"); 1467*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(pa % (num_entries * sizeof(uint64_t)), (uint64_t) 0, "check that the pagetable physical address is correctly aligned"); 1468*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NE(num_entries, (uint64_t) 0, "check that a pagetable region has more than 0 entries"); 1469*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_LE(j + 4 + num_entries, (uint64_t) elem_count, "check for sufficient space in page table array"); 1470*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_GT(end_va, start_va, "check for valid VA bounds in page table segment header"); 1471*94d3b452SApple OSS Distributions 1472*94d3b452SApple OSS Distributions for (uint32_t k = j + 4; k < (j + 4 + num_entries); ++k) { 1473*94d3b452SApple OSS Distributions if (pt_array[k] != 0) { 1474*94d3b452SApple OSS Distributions nonzero_tte = true; 1475*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ((pt_array[k] >> 48) & 0xf, (uint64_t) 0, "check that bits[48:51] of arm64 TTE are clear"); 1476*94d3b452SApple OSS Distributions // L0-L2 table and non-compressed L3 block entries should always have bit 1 set; assumes L0-L2 blocks will not be used outside the kernel 1477*94d3b452SApple OSS Distributions bool table = ((pt_array[k] & 0x2) != 0); 1478*94d3b452SApple OSS Distributions if (table) { 1479*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NE(pt_array[k] & ((1ULL << 48) - 1) & ~((1ULL << 12) - 1), (uint64_t) 0, "check that arm64 TTE physical address is non-zero"); 1480*94d3b452SApple OSS Distributions } else { // should be a compressed PTE 1481*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NE(pt_array[k] & 0xC000000000000000ULL, (uint64_t) 0, "check that compressed PTE has at least one of bits [63:62] set"); 1482*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(pt_array[k] & ~0xC000000000000000ULL, (uint64_t) 0, "check that compressed PTE has no other bits besides [63:62] set"); 1483*94d3b452SApple OSS Distributions } 1484*94d3b452SApple OSS Distributions } 1485*94d3b452SApple OSS Distributions } 1486*94d3b452SApple OSS Distributions 1487*94d3b452SApple OSS Distributions j += (4 + num_entries); 1488*94d3b452SApple OSS Distributions } 1489*94d3b452SApple OSS Distributions T_ASSERT_TRUE(nonzero_tte, "check that we saw at least one non-empty TTE"); 1490*94d3b452SApple OSS Distributions T_ASSERT_EQ(j, elem_count, "check that page table dump size matches extent of last header"); 1491*94d3b452SApple OSS Distributions break; 1492*94d3b452SApple OSS Distributions } 1493*94d3b452SApple OSS Distributions case STACKSHOT_KCTYPE_ASID: { 1494*94d3b452SApple OSS Distributions T_ASSERT_FALSE(seen_asid, "check that we haven't yet seen an ASID"); 1495*94d3b452SApple OSS Distributions seen_asid = true; 1496*94d3b452SApple OSS Distributions } 1497*94d3b452SApple OSS Distributions } 1498*94d3b452SApple OSS Distributions } 1499*94d3b452SApple OSS Distributions T_ASSERT_TRUE(seen_page_table_snapshot, "check that we have seen a page table snapshot"); 1500*94d3b452SApple OSS Distributions T_ASSERT_TRUE(seen_asid, "check that we have seen an ASID"); 1501*94d3b452SApple OSS Distributions} 1502*94d3b452SApple OSS Distributions 1503*94d3b452SApple OSS DistributionsT_DECL(dump_page_tables, "test stackshot page table dumping support") 1504*94d3b452SApple OSS Distributions{ 1505*94d3b452SApple OSS Distributions struct scenario scenario = { 1506*94d3b452SApple OSS Distributions .name = "asid-page-tables", 1507*94d3b452SApple OSS Distributions .flags = (STACKSHOT_KCDATA_FORMAT | STACKSHOT_ASID | STACKSHOT_PAGE_TABLES), 1508*94d3b452SApple OSS Distributions .size_hint = (9ull << 20), // 9 MB 1509*94d3b452SApple OSS Distributions .target_pid = getpid(), 1510*94d3b452SApple OSS Distributions .maybe_unsupported = true, 1511*94d3b452SApple OSS Distributions .maybe_enomem = true, 1512*94d3b452SApple OSS Distributions }; 1513*94d3b452SApple OSS Distributions 1514*94d3b452SApple OSS Distributions T_LOG("attempting to take stackshot with ASID and page table flags"); 1515*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 1516*94d3b452SApple OSS Distributions parse_page_table_asid_stackshot(ssbuf, sslen); 1517*94d3b452SApple OSS Distributions }); 1518*94d3b452SApple OSS Distributions} 1519*94d3b452SApple OSS Distributions 1520*94d3b452SApple OSS Distributionsstatic void stackshot_verify_current_proc_uuid_info(void **ssbuf, size_t sslen, uint64_t expected_offset, const struct proc_uniqidentifierinfo *proc_info_data) 1521*94d3b452SApple OSS Distributions{ 1522*94d3b452SApple OSS Distributions const uuid_t *current_uuid = (const uuid_t *)(&proc_info_data->p_uuid); 1523*94d3b452SApple OSS Distributions 1524*94d3b452SApple OSS Distributions kcdata_iter_t iter = kcdata_iter(ssbuf, sslen); 1525*94d3b452SApple OSS Distributions T_ASSERT_EQ(kcdata_iter_type(iter), KCDATA_BUFFER_BEGIN_STACKSHOT, "buffer provided is a stackshot"); 1526*94d3b452SApple OSS Distributions 1527*94d3b452SApple OSS Distributions iter = kcdata_iter_next(iter); 1528*94d3b452SApple OSS Distributions 1529*94d3b452SApple OSS Distributions KCDATA_ITER_FOREACH(iter) { 1530*94d3b452SApple OSS Distributions switch (kcdata_iter_type(iter)) { 1531*94d3b452SApple OSS Distributions case KCDATA_TYPE_ARRAY: { 1532*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(kcdata_iter_array_valid(iter), "checked that array is valid"); 1533*94d3b452SApple OSS Distributions if (kcdata_iter_array_elem_type(iter) == KCDATA_TYPE_LIBRARY_LOADINFO64) { 1534*94d3b452SApple OSS Distributions struct user64_dyld_uuid_info *info = (struct user64_dyld_uuid_info *) kcdata_iter_payload(iter); 1535*94d3b452SApple OSS Distributions if (uuid_compare(*current_uuid, info->imageUUID) == 0) { 1536*94d3b452SApple OSS Distributions T_ASSERT_EQ(expected_offset, info->imageLoadAddress, "found matching UUID with matching binary offset"); 1537*94d3b452SApple OSS Distributions return; 1538*94d3b452SApple OSS Distributions } 1539*94d3b452SApple OSS Distributions } else if (kcdata_iter_array_elem_type(iter) == KCDATA_TYPE_LIBRARY_LOADINFO) { 1540*94d3b452SApple OSS Distributions struct user32_dyld_uuid_info *info = (struct user32_dyld_uuid_info *) kcdata_iter_payload(iter); 1541*94d3b452SApple OSS Distributions if (uuid_compare(*current_uuid, info->imageUUID) == 0) { 1542*94d3b452SApple OSS Distributions T_ASSERT_EQ(expected_offset, ((uint64_t) info->imageLoadAddress), "found matching UUID with matching binary offset"); 1543*94d3b452SApple OSS Distributions return; 1544*94d3b452SApple OSS Distributions } 1545*94d3b452SApple OSS Distributions } 1546*94d3b452SApple OSS Distributions break; 1547*94d3b452SApple OSS Distributions } 1548*94d3b452SApple OSS Distributions default: 1549*94d3b452SApple OSS Distributions break; 1550*94d3b452SApple OSS Distributions } 1551*94d3b452SApple OSS Distributions } 1552*94d3b452SApple OSS Distributions 1553*94d3b452SApple OSS Distributions T_FAIL("failed to find matching UUID in stackshot data"); 1554*94d3b452SApple OSS Distributions} 1555*94d3b452SApple OSS Distributions 1556*94d3b452SApple OSS DistributionsT_DECL(translated, "tests translated bit is set correctly") 1557*94d3b452SApple OSS Distributions{ 1558*94d3b452SApple OSS Distributions#if !(TARGET_OS_OSX && TARGET_CPU_ARM64) 1559*94d3b452SApple OSS Distributions T_SKIP("Only valid on Apple silicon Macs") 1560*94d3b452SApple OSS Distributions#endif 1561*94d3b452SApple OSS Distributions // Get path of stackshot_translated_child helper binary 1562*94d3b452SApple OSS Distributions char path[PATH_MAX]; 1563*94d3b452SApple OSS Distributions uint32_t path_size = sizeof(path); 1564*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path, &path_size), "_NSGetExecutablePath"); 1565*94d3b452SApple OSS Distributions char* binary_name = strrchr(path, '/'); 1566*94d3b452SApple OSS Distributions if (binary_name) binary_name++; 1567*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(binary_name, "Find basename in path '%s'", path); 1568*94d3b452SApple OSS Distributions strlcpy(binary_name, "stackshot_translated_child", path_size - (binary_name - path)); 1569*94d3b452SApple OSS Distributions char *args[] = { path, NULL }; 1570*94d3b452SApple OSS Distributions 1571*94d3b452SApple OSS Distributions dispatch_source_t child_sig_src; 1572*94d3b452SApple OSS Distributions dispatch_semaphore_t child_ready_sem = dispatch_semaphore_create(0); 1573*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(child_ready_sem, "exec child semaphore"); 1574*94d3b452SApple OSS Distributions 1575*94d3b452SApple OSS Distributions dispatch_queue_t signal_processing_q = dispatch_queue_create("signal processing queue", NULL); 1576*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(signal_processing_q, "signal processing queue"); 1577*94d3b452SApple OSS Distributions 1578*94d3b452SApple OSS Distributions signal(SIGUSR1, SIG_IGN); 1579*94d3b452SApple OSS Distributions child_sig_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, signal_processing_q); 1580*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(child_sig_src, "dispatch_source_create (child_sig_src)"); 1581*94d3b452SApple OSS Distributions 1582*94d3b452SApple OSS Distributions dispatch_source_set_event_handler(child_sig_src, ^{ dispatch_semaphore_signal(child_ready_sem); }); 1583*94d3b452SApple OSS Distributions dispatch_activate(child_sig_src); 1584*94d3b452SApple OSS Distributions 1585*94d3b452SApple OSS Distributions // Spawn child 1586*94d3b452SApple OSS Distributions pid_t pid; 1587*94d3b452SApple OSS Distributions T_LOG("spawning translated child"); 1588*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(posix_spawn(&pid, args[0], NULL, NULL, args, NULL), "spawned process '%s' with PID %d", args[0], pid); 1589*94d3b452SApple OSS Distributions 1590*94d3b452SApple OSS Distributions // Wait for the the child to spawn up 1591*94d3b452SApple OSS Distributions dispatch_semaphore_wait(child_ready_sem, DISPATCH_TIME_FOREVER); 1592*94d3b452SApple OSS Distributions 1593*94d3b452SApple OSS Distributions // Make sure the child is running and is translated 1594*94d3b452SApple OSS Distributions int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }; 1595*94d3b452SApple OSS Distributions struct kinfo_proc process_info; 1596*94d3b452SApple OSS Distributions size_t bufsize = sizeof(process_info); 1597*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctl(mib, (unsigned)(sizeof(mib)/sizeof(int)), &process_info, &bufsize, NULL, 0), "get translated child process info"); 1598*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_GT(bufsize, (size_t)0, "process info is not empty"); 1599*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE((process_info.kp_proc.p_flag & P_TRANSLATED), "KERN_PROC_PID reports child is translated"); 1600*94d3b452SApple OSS Distributions 1601*94d3b452SApple OSS Distributions T_LOG("capturing stackshot"); 1602*94d3b452SApple OSS Distributions 1603*94d3b452SApple OSS Distributions struct scenario scenario = { 1604*94d3b452SApple OSS Distributions .name = "translated", 1605*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_GET_GLOBAL_MEM_STATS 1606*94d3b452SApple OSS Distributions | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_KCDATA_FORMAT), 1607*94d3b452SApple OSS Distributions }; 1608*94d3b452SApple OSS Distributions 1609*94d3b452SApple OSS Distributions take_stackshot(&scenario, true, ^( void *ssbuf, size_t sslen) { 1610*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_TRANSLATED, ssbuf, sslen, @{translated_child_pid_key: @(pid)}); 1611*94d3b452SApple OSS Distributions }); 1612*94d3b452SApple OSS Distributions 1613*94d3b452SApple OSS Distributions // Kill the child 1614*94d3b452SApple OSS Distributions int status; 1615*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(kill(pid, SIGTERM), "kill translated child"); 1616*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(waitpid(pid, &status, 0), "waitpid on translated child"); 1617*94d3b452SApple OSS Distributions 1618*94d3b452SApple OSS Distributions} 1619*94d3b452SApple OSS Distributions 1620*94d3b452SApple OSS DistributionsT_DECL(proc_uuid_info, "tests that the main binary UUID for a proc is always populated") 1621*94d3b452SApple OSS Distributions{ 1622*94d3b452SApple OSS Distributions struct proc_uniqidentifierinfo proc_info_data = { }; 1623*94d3b452SApple OSS Distributions mach_msg_type_number_t count; 1624*94d3b452SApple OSS Distributions kern_return_t kernel_status; 1625*94d3b452SApple OSS Distributions task_dyld_info_data_t task_dyld_info; 1626*94d3b452SApple OSS Distributions struct dyld_all_image_infos *target_infos; 1627*94d3b452SApple OSS Distributions int retval; 1628*94d3b452SApple OSS Distributions bool found_image_in_image_infos = false; 1629*94d3b452SApple OSS Distributions uint64_t expected_mach_header_offset = 0; 1630*94d3b452SApple OSS Distributions 1631*94d3b452SApple OSS Distributions /* Find the UUID of our main binary */ 1632*94d3b452SApple OSS Distributions retval = proc_pidinfo(getpid(), PROC_PIDUNIQIDENTIFIERINFO, 0, &proc_info_data, sizeof(proc_info_data)); 1633*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_POSIX_SUCCESS(retval, "proc_pidinfo PROC_PIDUNIQIDENTIFIERINFO"); 1634*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ_INT(retval, (int) sizeof(proc_info_data), "proc_pidinfo PROC_PIDUNIQIDENTIFIERINFO returned data"); 1635*94d3b452SApple OSS Distributions 1636*94d3b452SApple OSS Distributions uuid_string_t str = {}; 1637*94d3b452SApple OSS Distributions uuid_unparse(*(uuid_t*)&proc_info_data.p_uuid, str); 1638*94d3b452SApple OSS Distributions T_LOG("Found current UUID is %s", str); 1639*94d3b452SApple OSS Distributions 1640*94d3b452SApple OSS Distributions /* Find the location of the dyld image info metadata */ 1641*94d3b452SApple OSS Distributions count = TASK_DYLD_INFO_COUNT; 1642*94d3b452SApple OSS Distributions kernel_status = task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count); 1643*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(kernel_status, KERN_SUCCESS, "retrieve task_info for TASK_DYLD_INFO"); 1644*94d3b452SApple OSS Distributions 1645*94d3b452SApple OSS Distributions target_infos = (struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr; 1646*94d3b452SApple OSS Distributions 1647*94d3b452SApple OSS Distributions /* Find our binary in the dyld image info array */ 1648*94d3b452SApple OSS Distributions for (int i = 0; i < (int) target_infos->uuidArrayCount; i++) { 1649*94d3b452SApple OSS Distributions if (uuid_compare(target_infos->uuidArray[i].imageUUID, *(uuid_t*)&proc_info_data.p_uuid) == 0) { 1650*94d3b452SApple OSS Distributions expected_mach_header_offset = (uint64_t) target_infos->uuidArray[i].imageLoadAddress; 1651*94d3b452SApple OSS Distributions found_image_in_image_infos = true; 1652*94d3b452SApple OSS Distributions } 1653*94d3b452SApple OSS Distributions } 1654*94d3b452SApple OSS Distributions 1655*94d3b452SApple OSS Distributions T_ASSERT_TRUE(found_image_in_image_infos, "found binary image in dyld image info list"); 1656*94d3b452SApple OSS Distributions 1657*94d3b452SApple OSS Distributions /* Overwrite the dyld image info data so the kernel has to fallback to the UUID stored in the proc structure */ 1658*94d3b452SApple OSS Distributions target_infos->uuidArrayCount = 0; 1659*94d3b452SApple OSS Distributions 1660*94d3b452SApple OSS Distributions struct scenario scenario = { 1661*94d3b452SApple OSS Distributions .name = "proc_uuid_info", 1662*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_KCDATA_FORMAT), 1663*94d3b452SApple OSS Distributions .target_pid = getpid(), 1664*94d3b452SApple OSS Distributions }; 1665*94d3b452SApple OSS Distributions 1666*94d3b452SApple OSS Distributions T_LOG("attempting to take stackshot for current PID"); 1667*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 1668*94d3b452SApple OSS Distributions stackshot_verify_current_proc_uuid_info(ssbuf, sslen, expected_mach_header_offset, &proc_info_data); 1669*94d3b452SApple OSS Distributions }); 1670*94d3b452SApple OSS Distributions} 1671*94d3b452SApple OSS Distributions 1672*94d3b452SApple OSS DistributionsT_DECL(cseg_waitinfo, "test that threads stuck in the compressor report correct waitinfo") 1673*94d3b452SApple OSS Distributions{ 1674*94d3b452SApple OSS Distributions struct scenario scenario = { 1675*94d3b452SApple OSS Distributions .name = "cseg_waitinfo", 1676*94d3b452SApple OSS Distributions .quiet = false, 1677*94d3b452SApple OSS Distributions .flags = (STACKSHOT_THREAD_WAITINFO | STACKSHOT_KCDATA_FORMAT), 1678*94d3b452SApple OSS Distributions }; 1679*94d3b452SApple OSS Distributions __block uint64_t thread_id = 0; 1680*94d3b452SApple OSS Distributions 1681*94d3b452SApple OSS Distributions dispatch_queue_t dq = dispatch_queue_create("com.apple.stackshot.cseg_waitinfo", NULL); 1682*94d3b452SApple OSS Distributions dispatch_semaphore_t child_ok = dispatch_semaphore_create(0); 1683*94d3b452SApple OSS Distributions 1684*94d3b452SApple OSS Distributions dispatch_async(dq, ^{ 1685*94d3b452SApple OSS Distributions pthread_threadid_np(NULL, &thread_id); 1686*94d3b452SApple OSS Distributions dispatch_semaphore_signal(child_ok); 1687*94d3b452SApple OSS Distributions int val = 1; 1688*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(sysctlbyname("kern.cseg_wedge_thread", NULL, NULL, &val, sizeof(val)), "wedge child thread"); 1689*94d3b452SApple OSS Distributions }); 1690*94d3b452SApple OSS Distributions 1691*94d3b452SApple OSS Distributions dispatch_semaphore_wait(child_ok, DISPATCH_TIME_FOREVER); 1692*94d3b452SApple OSS Distributions sleep(1); 1693*94d3b452SApple OSS Distributions 1694*94d3b452SApple OSS Distributions T_LOG("taking stackshot"); 1695*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 1696*94d3b452SApple OSS Distributions int val = 1; 1697*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(sysctlbyname("kern.cseg_unwedge_thread", NULL, NULL, &val, sizeof(val)), "unwedge child thread"); 1698*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_WAITINFO_CSEG, ssbuf, sslen, @{cseg_expected_threadid_key: @(thread_id)}); 1699*94d3b452SApple OSS Distributions }); 1700*94d3b452SApple OSS Distributions} 1701*94d3b452SApple OSS Distributions 1702*94d3b452SApple OSS Distributionsstatic void 1703*94d3b452SApple OSS Distributionssrp_send( 1704*94d3b452SApple OSS Distributions mach_port_t send_port, 1705*94d3b452SApple OSS Distributions mach_port_t reply_port, 1706*94d3b452SApple OSS Distributions mach_port_t msg_port) 1707*94d3b452SApple OSS Distributions{ 1708*94d3b452SApple OSS Distributions kern_return_t ret = 0; 1709*94d3b452SApple OSS Distributions 1710*94d3b452SApple OSS Distributions struct test_msg { 1711*94d3b452SApple OSS Distributions mach_msg_header_t header; 1712*94d3b452SApple OSS Distributions mach_msg_body_t body; 1713*94d3b452SApple OSS Distributions mach_msg_port_descriptor_t port_descriptor; 1714*94d3b452SApple OSS Distributions }; 1715*94d3b452SApple OSS Distributions struct test_msg send_msg = { 1716*94d3b452SApple OSS Distributions .header = { 1717*94d3b452SApple OSS Distributions .msgh_remote_port = send_port, 1718*94d3b452SApple OSS Distributions .msgh_local_port = reply_port, 1719*94d3b452SApple OSS Distributions .msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, 1720*94d3b452SApple OSS Distributions reply_port ? MACH_MSG_TYPE_MAKE_SEND_ONCE : 0, 1721*94d3b452SApple OSS Distributions MACH_MSG_TYPE_MOVE_SEND, 1722*94d3b452SApple OSS Distributions MACH_MSGH_BITS_COMPLEX), 1723*94d3b452SApple OSS Distributions .msgh_id = 0x100, 1724*94d3b452SApple OSS Distributions .msgh_size = sizeof(send_msg), 1725*94d3b452SApple OSS Distributions }, 1726*94d3b452SApple OSS Distributions .body = { 1727*94d3b452SApple OSS Distributions .msgh_descriptor_count = 1, 1728*94d3b452SApple OSS Distributions }, 1729*94d3b452SApple OSS Distributions .port_descriptor = { 1730*94d3b452SApple OSS Distributions .name = msg_port, 1731*94d3b452SApple OSS Distributions .disposition = MACH_MSG_TYPE_MOVE_RECEIVE, 1732*94d3b452SApple OSS Distributions .type = MACH_MSG_PORT_DESCRIPTOR, 1733*94d3b452SApple OSS Distributions }, 1734*94d3b452SApple OSS Distributions }; 1735*94d3b452SApple OSS Distributions 1736*94d3b452SApple OSS Distributions if (msg_port == MACH_PORT_NULL) { 1737*94d3b452SApple OSS Distributions send_msg.body.msgh_descriptor_count = 0; 1738*94d3b452SApple OSS Distributions } 1739*94d3b452SApple OSS Distributions 1740*94d3b452SApple OSS Distributions ret = mach_msg(&(send_msg.header), 1741*94d3b452SApple OSS Distributions MACH_SEND_MSG | 1742*94d3b452SApple OSS Distributions MACH_SEND_TIMEOUT | 1743*94d3b452SApple OSS Distributions MACH_SEND_OVERRIDE, 1744*94d3b452SApple OSS Distributions send_msg.header.msgh_size, 1745*94d3b452SApple OSS Distributions 0, 1746*94d3b452SApple OSS Distributions MACH_PORT_NULL, 1747*94d3b452SApple OSS Distributions 10000, 1748*94d3b452SApple OSS Distributions 0); 1749*94d3b452SApple OSS Distributions 1750*94d3b452SApple OSS Distributions T_ASSERT_MACH_SUCCESS(ret, "client mach_msg"); 1751*94d3b452SApple OSS Distributions} 1752*94d3b452SApple OSS Distributions 1753*94d3b452SApple OSS DistributionsT_HELPER_DECL(srp_client, 1754*94d3b452SApple OSS Distributions "Client used for the special_reply_port test") 1755*94d3b452SApple OSS Distributions{ 1756*94d3b452SApple OSS Distributions pid_t ppid = getppid(); 1757*94d3b452SApple OSS Distributions dispatch_semaphore_t can_continue = dispatch_semaphore_create(0); 1758*94d3b452SApple OSS Distributions dispatch_queue_t dq = dispatch_queue_create("client_signalqueue", NULL); 1759*94d3b452SApple OSS Distributions dispatch_source_t sig_src; 1760*94d3b452SApple OSS Distributions 1761*94d3b452SApple OSS Distributions mach_msg_return_t mr; 1762*94d3b452SApple OSS Distributions mach_port_t service_port; 1763*94d3b452SApple OSS Distributions mach_port_t conn_port; 1764*94d3b452SApple OSS Distributions mach_port_t special_reply_port; 1765*94d3b452SApple OSS Distributions mach_port_options_t opts = { 1766*94d3b452SApple OSS Distributions .flags = MPO_INSERT_SEND_RIGHT, 1767*94d3b452SApple OSS Distributions }; 1768*94d3b452SApple OSS Distributions 1769*94d3b452SApple OSS Distributions signal(SIGUSR1, SIG_IGN); 1770*94d3b452SApple OSS Distributions sig_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, dq); 1771*94d3b452SApple OSS Distributions 1772*94d3b452SApple OSS Distributions dispatch_source_set_event_handler(sig_src, ^{ 1773*94d3b452SApple OSS Distributions dispatch_semaphore_signal(can_continue); 1774*94d3b452SApple OSS Distributions }); 1775*94d3b452SApple OSS Distributions dispatch_activate(sig_src); 1776*94d3b452SApple OSS Distributions 1777*94d3b452SApple OSS Distributions /* lookup the mach service port for the parent */ 1778*94d3b452SApple OSS Distributions kern_return_t kr = bootstrap_look_up(bootstrap_port, 1779*94d3b452SApple OSS Distributions SRP_SERVICE_NAME, &service_port); 1780*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client bootstrap_look_up"); 1781*94d3b452SApple OSS Distributions 1782*94d3b452SApple OSS Distributions /* create the send-once right (special reply port) and message to send to the server */ 1783*94d3b452SApple OSS Distributions kr = mach_port_construct(mach_task_self(), &opts, 0ull, &conn_port); 1784*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_construct"); 1785*94d3b452SApple OSS Distributions 1786*94d3b452SApple OSS Distributions special_reply_port = thread_get_special_reply_port(); 1787*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port), "get_thread_special_reply_port"); 1788*94d3b452SApple OSS Distributions 1789*94d3b452SApple OSS Distributions /* send the message with the special reply port */ 1790*94d3b452SApple OSS Distributions srp_send(service_port, special_reply_port, conn_port); 1791*94d3b452SApple OSS Distributions 1792*94d3b452SApple OSS Distributions /* signal the parent to continue */ 1793*94d3b452SApple OSS Distributions kill(ppid, SIGUSR1); 1794*94d3b452SApple OSS Distributions 1795*94d3b452SApple OSS Distributions struct { 1796*94d3b452SApple OSS Distributions mach_msg_header_t header; 1797*94d3b452SApple OSS Distributions mach_msg_body_t body; 1798*94d3b452SApple OSS Distributions mach_msg_port_descriptor_t port_descriptor; 1799*94d3b452SApple OSS Distributions } rcv_msg = { 1800*94d3b452SApple OSS Distributions .header = 1801*94d3b452SApple OSS Distributions { 1802*94d3b452SApple OSS Distributions .msgh_remote_port = MACH_PORT_NULL, 1803*94d3b452SApple OSS Distributions .msgh_local_port = special_reply_port, 1804*94d3b452SApple OSS Distributions .msgh_size = sizeof(rcv_msg), 1805*94d3b452SApple OSS Distributions }, 1806*94d3b452SApple OSS Distributions }; 1807*94d3b452SApple OSS Distributions 1808*94d3b452SApple OSS Distributions /* wait on the reply from the parent (that we will never receive) */ 1809*94d3b452SApple OSS Distributions mr = mach_msg(&(rcv_msg.header), 1810*94d3b452SApple OSS Distributions (MACH_RCV_MSG | MACH_RCV_SYNC_WAIT), 1811*94d3b452SApple OSS Distributions 0, 1812*94d3b452SApple OSS Distributions rcv_msg.header.msgh_size, 1813*94d3b452SApple OSS Distributions special_reply_port, 1814*94d3b452SApple OSS Distributions MACH_MSG_TIMEOUT_NONE, 1815*94d3b452SApple OSS Distributions service_port); 1816*94d3b452SApple OSS Distributions 1817*94d3b452SApple OSS Distributions /* not expected to execute as parent will SIGKILL client... */ 1818*94d3b452SApple OSS Distributions T_LOG("client process exiting after sending message to parent (server)"); 1819*94d3b452SApple OSS Distributions} 1820*94d3b452SApple OSS Distributions 1821*94d3b452SApple OSS Distributionsenum srp_test_type { 1822*94d3b452SApple OSS Distributions SRP_TEST_THREAD, /* expect waiter on current thread */ 1823*94d3b452SApple OSS Distributions SRP_TEST_PID, /* expect waiter on current PID */ 1824*94d3b452SApple OSS Distributions SRP_TEST_EITHER, /* waiter could be on either */ 1825*94d3b452SApple OSS Distributions}; 1826*94d3b452SApple OSS Distributions 1827*94d3b452SApple OSS Distributionsstatic void 1828*94d3b452SApple OSS Distributionscheck_srp_test(const char *name, enum srp_test_type ty) 1829*94d3b452SApple OSS Distributions{ 1830*94d3b452SApple OSS Distributions struct scenario scenario = { 1831*94d3b452SApple OSS Distributions .name = name, 1832*94d3b452SApple OSS Distributions .quiet = false, 1833*94d3b452SApple OSS Distributions .flags = (STACKSHOT_THREAD_WAITINFO | STACKSHOT_KCDATA_FORMAT), 1834*94d3b452SApple OSS Distributions }; 1835*94d3b452SApple OSS Distributions uint64_t thread_id = 0; 1836*94d3b452SApple OSS Distributions pthread_threadid_np(NULL, &thread_id); 1837*94d3b452SApple OSS Distributions if (ty == SRP_TEST_THREAD) { 1838*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 1839*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_WAITINFO_SRP, ssbuf, sslen, 1840*94d3b452SApple OSS Distributions @{srp_expected_threadid_key: @(thread_id)}); 1841*94d3b452SApple OSS Distributions }); 1842*94d3b452SApple OSS Distributions } else if (ty == SRP_TEST_PID) { 1843*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 1844*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_WAITINFO_SRP, ssbuf, sslen, 1845*94d3b452SApple OSS Distributions @{srp_expected_pid_key: @(getpid())}); 1846*94d3b452SApple OSS Distributions }); 1847*94d3b452SApple OSS Distributions } else { 1848*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 1849*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_WAITINFO_SRP, ssbuf, sslen, 1850*94d3b452SApple OSS Distributions @{srp_expected_pid_key: @(getpid()), srp_expected_threadid_key: @(thread_id)}); 1851*94d3b452SApple OSS Distributions }); 1852*94d3b452SApple OSS Distributions } 1853*94d3b452SApple OSS Distributions 1854*94d3b452SApple OSS Distributions} 1855*94d3b452SApple OSS Distributions 1856*94d3b452SApple OSS Distributions 1857*94d3b452SApple OSS Distributions/* 1858*94d3b452SApple OSS Distributions * Tests the stackshot wait info plumbing for synchronous IPC that doesn't use kevent on the server. 1859*94d3b452SApple OSS Distributions * 1860*94d3b452SApple OSS Distributions * (part 1): tests the scenario where a client sends a request that includes a special reply port 1861*94d3b452SApple OSS Distributions * to a server that doesn't receive the message and doesn't copy the send-once right 1862*94d3b452SApple OSS Distributions * into its address space as a result. for this case the special reply port is enqueued 1863*94d3b452SApple OSS Distributions * in a port and we check which task has that receive right and use that info. (rdar://60440338) 1864*94d3b452SApple OSS Distributions * (part 2): tests the scenario where a client sends a request that includes a special reply port 1865*94d3b452SApple OSS Distributions * to a server that receives the message and copies in the send-once right, but doesn't 1866*94d3b452SApple OSS Distributions * reply to the client. for this case the special reply port is copied out and the kernel 1867*94d3b452SApple OSS Distributions * stashes the info about which task copied out the send once right. (rdar://60440592) 1868*94d3b452SApple OSS Distributions * (part 3): tests the same as part 2, but uses kevents, which allow for 1869*94d3b452SApple OSS Distributions * priority inheritance 1870*94d3b452SApple OSS Distributions */ 1871*94d3b452SApple OSS DistributionsT_DECL(special_reply_port, "test that tasks using special reply ports have correct waitinfo") 1872*94d3b452SApple OSS Distributions{ 1873*94d3b452SApple OSS Distributions dispatch_semaphore_t can_continue = dispatch_semaphore_create(0); 1874*94d3b452SApple OSS Distributions dispatch_queue_t dq = dispatch_queue_create("signalqueue", NULL); 1875*94d3b452SApple OSS Distributions dispatch_queue_t machdq = dispatch_queue_create("machqueue", NULL); 1876*94d3b452SApple OSS Distributions dispatch_source_t sig_src; 1877*94d3b452SApple OSS Distributions char path[PATH_MAX]; 1878*94d3b452SApple OSS Distributions uint32_t path_size = sizeof(path); 1879*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path, &path_size), "_NSGetExecutablePath"); 1880*94d3b452SApple OSS Distributions char *client_args[] = { path, "-n", "srp_client", NULL }; 1881*94d3b452SApple OSS Distributions pid_t client_pid; 1882*94d3b452SApple OSS Distributions int sp_ret; 1883*94d3b452SApple OSS Distributions kern_return_t kr; 1884*94d3b452SApple OSS Distributions mach_port_t port; 1885*94d3b452SApple OSS Distributions 1886*94d3b452SApple OSS Distributions /* setup the signal handler in the parent (server) */ 1887*94d3b452SApple OSS Distributions T_LOG("setup sig handlers"); 1888*94d3b452SApple OSS Distributions signal(SIGUSR1, SIG_IGN); 1889*94d3b452SApple OSS Distributions sig_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, dq); 1890*94d3b452SApple OSS Distributions 1891*94d3b452SApple OSS Distributions dispatch_source_set_event_handler(sig_src, ^{ 1892*94d3b452SApple OSS Distributions dispatch_semaphore_signal(can_continue); 1893*94d3b452SApple OSS Distributions }); 1894*94d3b452SApple OSS Distributions dispatch_activate(sig_src); 1895*94d3b452SApple OSS Distributions 1896*94d3b452SApple OSS Distributions /* register with the mach service name so the client can lookup and send a message to the parent (server) */ 1897*94d3b452SApple OSS Distributions T_LOG("Server about to check in"); 1898*94d3b452SApple OSS Distributions kr = bootstrap_check_in(bootstrap_port, SRP_SERVICE_NAME, &port); 1899*94d3b452SApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "server bootstrap_check_in"); 1900*94d3b452SApple OSS Distributions 1901*94d3b452SApple OSS Distributions T_LOG("Launching client"); 1902*94d3b452SApple OSS Distributions sp_ret = posix_spawn(&client_pid, client_args[0], NULL, NULL, client_args, NULL); 1903*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(sp_ret, "spawned process '%s' with PID %d", client_args[0], client_pid); 1904*94d3b452SApple OSS Distributions T_LOG("Spawned client as PID %d", client_pid); 1905*94d3b452SApple OSS Distributions 1906*94d3b452SApple OSS Distributions dispatch_semaphore_wait(can_continue, DISPATCH_TIME_FOREVER); 1907*94d3b452SApple OSS Distributions T_LOG("Ready to take stackshot, but waiting 1s for the coast to clear"); 1908*94d3b452SApple OSS Distributions 1909*94d3b452SApple OSS Distributions /* 1910*94d3b452SApple OSS Distributions * can_continue indicates the client has signaled us, but we want to make 1911*94d3b452SApple OSS Distributions * sure they've actually blocked sending their mach message. It's cheesy, but 1912*94d3b452SApple OSS Distributions * sleep() works for this. 1913*94d3b452SApple OSS Distributions */ 1914*94d3b452SApple OSS Distributions sleep(1); 1915*94d3b452SApple OSS Distributions 1916*94d3b452SApple OSS Distributions /* 1917*94d3b452SApple OSS Distributions * take the stackshot without calling receive to verify that the stackshot wait 1918*94d3b452SApple OSS Distributions * info shows our (the server) thread for the scenario where the server has yet to 1919*94d3b452SApple OSS Distributions * receive the message. 1920*94d3b452SApple OSS Distributions */ 1921*94d3b452SApple OSS Distributions T_LOG("Taking stackshot for part 1 coverage"); 1922*94d3b452SApple OSS Distributions check_srp_test("srp", SRP_TEST_THREAD); 1923*94d3b452SApple OSS Distributions 1924*94d3b452SApple OSS Distributions /* 1925*94d3b452SApple OSS Distributions * receive the message from the client (which should copy the send once right into 1926*94d3b452SApple OSS Distributions * our address space). 1927*94d3b452SApple OSS Distributions */ 1928*94d3b452SApple OSS Distributions struct { 1929*94d3b452SApple OSS Distributions mach_msg_header_t header; 1930*94d3b452SApple OSS Distributions mach_msg_body_t body; 1931*94d3b452SApple OSS Distributions mach_msg_port_descriptor_t port_descriptor; 1932*94d3b452SApple OSS Distributions } rcv_msg = { 1933*94d3b452SApple OSS Distributions .header = 1934*94d3b452SApple OSS Distributions { 1935*94d3b452SApple OSS Distributions .msgh_remote_port = MACH_PORT_NULL, 1936*94d3b452SApple OSS Distributions .msgh_local_port = port, 1937*94d3b452SApple OSS Distributions .msgh_size = sizeof(rcv_msg), 1938*94d3b452SApple OSS Distributions }, 1939*94d3b452SApple OSS Distributions }; 1940*94d3b452SApple OSS Distributions 1941*94d3b452SApple OSS Distributions T_LOG("server: starting sync receive\n"); 1942*94d3b452SApple OSS Distributions 1943*94d3b452SApple OSS Distributions mach_msg_return_t mr; 1944*94d3b452SApple OSS Distributions mr = mach_msg(&(rcv_msg.header), 1945*94d3b452SApple OSS Distributions (MACH_RCV_MSG | MACH_RCV_TIMEOUT), 1946*94d3b452SApple OSS Distributions 0, 1947*94d3b452SApple OSS Distributions 4096, 1948*94d3b452SApple OSS Distributions port, 1949*94d3b452SApple OSS Distributions 10000, 1950*94d3b452SApple OSS Distributions MACH_PORT_NULL); 1951*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(mr, "mach_msg() recieve of message from client"); 1952*94d3b452SApple OSS Distributions 1953*94d3b452SApple OSS Distributions /* 1954*94d3b452SApple OSS Distributions * take the stackshot to verify that the stackshot wait info shows our (the server) PID 1955*94d3b452SApple OSS Distributions * for the scenario where the server has received the message and copied in the send-once right. 1956*94d3b452SApple OSS Distributions */ 1957*94d3b452SApple OSS Distributions T_LOG("Taking stackshot for part 2 coverage"); 1958*94d3b452SApple OSS Distributions check_srp_test("srp", SRP_TEST_PID); 1959*94d3b452SApple OSS Distributions 1960*94d3b452SApple OSS Distributions /* cleanup - kill the client */ 1961*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kill(client_pid, SIGKILL), "killing client"); 1962*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(waitpid(client_pid, NULL, 0), "waiting for the client to exit"); 1963*94d3b452SApple OSS Distributions 1964*94d3b452SApple OSS Distributions // do it again, but using kevents 1965*94d3b452SApple OSS Distributions T_LOG("Launching client"); 1966*94d3b452SApple OSS Distributions sp_ret = posix_spawn(&client_pid, client_args[0], NULL, NULL, client_args, NULL); 1967*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(sp_ret, "spawned process '%s' with PID %d", client_args[0], client_pid); 1968*94d3b452SApple OSS Distributions T_LOG("Spawned client as PID %d", client_pid); 1969*94d3b452SApple OSS Distributions 1970*94d3b452SApple OSS Distributions dispatch_semaphore_wait(can_continue, DISPATCH_TIME_FOREVER); 1971*94d3b452SApple OSS Distributions T_LOG("Ready to take stackshot, but waiting 1s for the coast to clear"); 1972*94d3b452SApple OSS Distributions 1973*94d3b452SApple OSS Distributions /* 1974*94d3b452SApple OSS Distributions * can_continue indicates the client has signaled us, but we want to make 1975*94d3b452SApple OSS Distributions * sure they've actually blocked sending their mach message. It's cheesy, but 1976*94d3b452SApple OSS Distributions * sleep() works for this. 1977*94d3b452SApple OSS Distributions */ 1978*94d3b452SApple OSS Distributions sleep(1); 1979*94d3b452SApple OSS Distributions 1980*94d3b452SApple OSS Distributions dispatch_mach_t dispatch_mach = dispatch_mach_create(SRP_SERVICE_NAME, machdq, 1981*94d3b452SApple OSS Distributions ^(dispatch_mach_reason_t reason, 1982*94d3b452SApple OSS Distributions dispatch_mach_msg_t message, 1983*94d3b452SApple OSS Distributions mach_error_t error __unused) { 1984*94d3b452SApple OSS Distributions switch (reason) { 1985*94d3b452SApple OSS Distributions case DISPATCH_MACH_MESSAGE_RECEIVED: { 1986*94d3b452SApple OSS Distributions size_t size = 0; 1987*94d3b452SApple OSS Distributions mach_msg_header_t *msg __unused = dispatch_mach_msg_get_msg(message, &size); 1988*94d3b452SApple OSS Distributions T_LOG("server: recieved %ld byte message", size); 1989*94d3b452SApple OSS Distributions check_srp_test("turnstile_port_thread", SRP_TEST_THREAD); 1990*94d3b452SApple OSS Distributions T_LOG("server: letting client go"); 1991*94d3b452SApple OSS Distributions // drop the message on the ground, we'll kill the client later 1992*94d3b452SApple OSS Distributions dispatch_semaphore_signal(can_continue); 1993*94d3b452SApple OSS Distributions break; 1994*94d3b452SApple OSS Distributions } 1995*94d3b452SApple OSS Distributions default: 1996*94d3b452SApple OSS Distributions break; 1997*94d3b452SApple OSS Distributions } 1998*94d3b452SApple OSS Distributions }); 1999*94d3b452SApple OSS Distributions 2000*94d3b452SApple OSS Distributions dispatch_mach_connect(dispatch_mach, port, MACH_PORT_NULL, NULL); 2001*94d3b452SApple OSS Distributions 2002*94d3b452SApple OSS Distributions dispatch_semaphore_wait(can_continue, DISPATCH_TIME_FOREVER); 2003*94d3b452SApple OSS Distributions 2004*94d3b452SApple OSS Distributions /* cleanup - kill the client */ 2005*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kill(client_pid, SIGKILL), "killing client"); 2006*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(waitpid(client_pid, NULL, 0), "waiting for the client to exit"); 2007*94d3b452SApple OSS Distributions} 2008*94d3b452SApple OSS Distributions 2009*94d3b452SApple OSS DistributionsT_HELPER_DECL(throtlled_sp_client, 2010*94d3b452SApple OSS Distributions "client that uses a connection port to send a message to a server") 2011*94d3b452SApple OSS Distributions{ 2012*94d3b452SApple OSS Distributions mach_port_t conn_port, service_port, reply_port, *stash; 2013*94d3b452SApple OSS Distributions mach_msg_type_number_t stash_cnt = 0; 2014*94d3b452SApple OSS Distributions 2015*94d3b452SApple OSS Distributions kern_return_t kr = mach_ports_lookup(mach_task_self(), &stash, &stash_cnt); 2016*94d3b452SApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "mach_ports_lookup"); 2017*94d3b452SApple OSS Distributions 2018*94d3b452SApple OSS Distributions service_port = stash[0]; 2019*94d3b452SApple OSS Distributions T_ASSERT_TRUE(MACH_PORT_VALID(service_port), "valid service port"); 2020*94d3b452SApple OSS Distributions mig_deallocate((vm_address_t)stash, stash_cnt * sizeof(stash[0])); 2021*94d3b452SApple OSS Distributions 2022*94d3b452SApple OSS Distributions mach_port_options_t opts = { 2023*94d3b452SApple OSS Distributions .flags = MPO_INSERT_SEND_RIGHT 2024*94d3b452SApple OSS Distributions | MPO_CONNECTION_PORT, 2025*94d3b452SApple OSS Distributions .service_port_name = service_port, 2026*94d3b452SApple OSS Distributions }; 2027*94d3b452SApple OSS Distributions 2028*94d3b452SApple OSS Distributions kr = mach_port_construct(mach_task_self(), &opts, 0ull, &conn_port); 2029*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_construct"); 2030*94d3b452SApple OSS Distributions 2031*94d3b452SApple OSS Distributions mach_port_options_t opts2 = { 2032*94d3b452SApple OSS Distributions .flags = MPO_REPLY_PORT 2033*94d3b452SApple OSS Distributions }; 2034*94d3b452SApple OSS Distributions kr = mach_port_construct(mach_task_self(), &opts2, 0ull, &reply_port); 2035*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_construct"); 2036*94d3b452SApple OSS Distributions 2037*94d3b452SApple OSS Distributions /* XPC-like check-in message */ 2038*94d3b452SApple OSS Distributions struct { 2039*94d3b452SApple OSS Distributions mach_msg_header_t header; 2040*94d3b452SApple OSS Distributions mach_msg_port_descriptor_t recvp; 2041*94d3b452SApple OSS Distributions mach_msg_port_descriptor_t sendp; 2042*94d3b452SApple OSS Distributions } checkin_message = { 2043*94d3b452SApple OSS Distributions .header = 2044*94d3b452SApple OSS Distributions { 2045*94d3b452SApple OSS Distributions .msgh_remote_port = service_port, 2046*94d3b452SApple OSS Distributions .msgh_local_port = MACH_PORT_NULL, 2047*94d3b452SApple OSS Distributions .msgh_size = sizeof(checkin_message), 2048*94d3b452SApple OSS Distributions .msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0), 2049*94d3b452SApple OSS Distributions }, 2050*94d3b452SApple OSS Distributions .recvp = 2051*94d3b452SApple OSS Distributions { 2052*94d3b452SApple OSS Distributions .type = MACH_MSG_PORT_DESCRIPTOR, 2053*94d3b452SApple OSS Distributions .name = conn_port, 2054*94d3b452SApple OSS Distributions .disposition = MACH_MSG_TYPE_MOVE_RECEIVE, 2055*94d3b452SApple OSS Distributions }, 2056*94d3b452SApple OSS Distributions .sendp = 2057*94d3b452SApple OSS Distributions { 2058*94d3b452SApple OSS Distributions .type = MACH_MSG_PORT_DESCRIPTOR, 2059*94d3b452SApple OSS Distributions .name = reply_port, 2060*94d3b452SApple OSS Distributions .disposition = MACH_MSG_TYPE_MAKE_SEND, 2061*94d3b452SApple OSS Distributions } 2062*94d3b452SApple OSS Distributions }; 2063*94d3b452SApple OSS Distributions dispatch_mach_msg_t dmsg = dispatch_mach_msg_create((mach_msg_header_t *)&checkin_message, sizeof(checkin_message), 2064*94d3b452SApple OSS Distributions DISPATCH_MACH_MSG_DESTRUCTOR_DEFAULT, NULL); 2065*94d3b452SApple OSS Distributions 2066*94d3b452SApple OSS Distributions dispatch_queue_t machdq = dispatch_queue_create("machqueue", NULL); 2067*94d3b452SApple OSS Distributions dispatch_mach_t dchannel = dispatch_mach_create(THROTTLED_SERVICE_NAME, machdq, 2068*94d3b452SApple OSS Distributions ^(dispatch_mach_reason_t reason, 2069*94d3b452SApple OSS Distributions dispatch_mach_msg_t message __unused, 2070*94d3b452SApple OSS Distributions mach_error_t error __unused) { 2071*94d3b452SApple OSS Distributions switch (reason) { 2072*94d3b452SApple OSS Distributions case DISPATCH_MACH_CONNECTED: 2073*94d3b452SApple OSS Distributions T_LOG("mach channel connected"); 2074*94d3b452SApple OSS Distributions break; 2075*94d3b452SApple OSS Distributions case DISPATCH_MACH_MESSAGE_SENT: 2076*94d3b452SApple OSS Distributions T_LOG("sent mach message"); 2077*94d3b452SApple OSS Distributions break; 2078*94d3b452SApple OSS Distributions default: 2079*94d3b452SApple OSS Distributions T_ASSERT_FAIL("Unexpected reply to channel reason %lu", reason); 2080*94d3b452SApple OSS Distributions } 2081*94d3b452SApple OSS Distributions }); 2082*94d3b452SApple OSS Distributions dispatch_mach_connect(dchannel, reply_port, service_port, dmsg); 2083*94d3b452SApple OSS Distributions dispatch_release(dmsg); 2084*94d3b452SApple OSS Distributions 2085*94d3b452SApple OSS Distributions struct { 2086*94d3b452SApple OSS Distributions mach_msg_header_t header; 2087*94d3b452SApple OSS Distributions uint64_t request_id; 2088*94d3b452SApple OSS Distributions } request = { 2089*94d3b452SApple OSS Distributions .header = 2090*94d3b452SApple OSS Distributions { 2091*94d3b452SApple OSS Distributions .msgh_size = sizeof(request), 2092*94d3b452SApple OSS Distributions .msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE), 2093*94d3b452SApple OSS Distributions }, 2094*94d3b452SApple OSS Distributions .request_id = 1, 2095*94d3b452SApple OSS Distributions }; 2096*94d3b452SApple OSS Distributions dispatch_mach_msg_t dmsg2 = dispatch_mach_msg_create((mach_msg_header_t *)&request, sizeof(request), 2097*94d3b452SApple OSS Distributions DISPATCH_MACH_MSG_DESTRUCTOR_DEFAULT, NULL); 2098*94d3b452SApple OSS Distributions 2099*94d3b452SApple OSS Distributions dispatch_mach_reason_t reason; 2100*94d3b452SApple OSS Distributions mach_error_t error; 2101*94d3b452SApple OSS Distributions 2102*94d3b452SApple OSS Distributions /* send the check-in message and the request message */ 2103*94d3b452SApple OSS Distributions dispatch_mach_msg_t dreply = dispatch_mach_send_with_result_and_wait_for_reply(dchannel, 2104*94d3b452SApple OSS Distributions dmsg2, 0, DISPATCH_MACH_SEND_DEFAULT, &reason, &error); 2105*94d3b452SApple OSS Distributions dispatch_release(dmsg2); 2106*94d3b452SApple OSS Distributions 2107*94d3b452SApple OSS Distributions /* not expected to execute as parent will SIGKILL client */ 2108*94d3b452SApple OSS Distributions T_ASSERT_FAIL("client process exiting after receiving %s reply", dreply ? "non-null" : "null"); 2109*94d3b452SApple OSS Distributions} 2110*94d3b452SApple OSS Distributions 2111*94d3b452SApple OSS Distributionsstatic void 2112*94d3b452SApple OSS Distributionscheck_throttled_sp(const char *test_name, uint64_t context, bool is_throttled) 2113*94d3b452SApple OSS Distributions{ 2114*94d3b452SApple OSS Distributions struct scenario scenario = { 2115*94d3b452SApple OSS Distributions .name = test_name, 2116*94d3b452SApple OSS Distributions .quiet = false, 2117*94d3b452SApple OSS Distributions .flags = (STACKSHOT_THREAD_WAITINFO | STACKSHOT_KCDATA_FORMAT), 2118*94d3b452SApple OSS Distributions }; 2119*94d3b452SApple OSS Distributions 2120*94d3b452SApple OSS Distributions T_LOG("taking stackshot %s", test_name); 2121*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 2122*94d3b452SApple OSS Distributions parse_stackshot(PARSE_STACKSHOT_THROTTLED_SP, ssbuf, sslen, 2123*94d3b452SApple OSS Distributions @{sp_throttled_expected_ctxt_key: @(context), 2124*94d3b452SApple OSS Distributions sp_throttled_expect_flag: @(is_throttled)}); 2125*94d3b452SApple OSS Distributions }); 2126*94d3b452SApple OSS Distributions} 2127*94d3b452SApple OSS Distributions 2128*94d3b452SApple OSS Distributions/* Take stackshot when a client is blocked on the service port of a process, in the scenario when 2129*94d3b452SApple OSS Distributions * the process with the receive right for the service port is: 2130*94d3b452SApple OSS Distributions * (a) Monitoring the service port using kevents 2131*94d3b452SApple OSS Distributions * (b) Not monitoring the service port 2132*94d3b452SApple OSS Distributions */ 2133*94d3b452SApple OSS DistributionsT_DECL(throttled_sp, 2134*94d3b452SApple OSS Distributions "test that service port throttled flag is propagated to the stackshot correctly") 2135*94d3b452SApple OSS Distributions{ 2136*94d3b452SApple OSS Distributions mach_port_t service_port; 2137*94d3b452SApple OSS Distributions __block dispatch_semaphore_t can_continue = dispatch_semaphore_create(0); 2138*94d3b452SApple OSS Distributions 2139*94d3b452SApple OSS Distributions char path[PATH_MAX]; 2140*94d3b452SApple OSS Distributions uint32_t path_size = sizeof(path); 2141*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path, &path_size), "_NSGetExecutablePath"); 2142*94d3b452SApple OSS Distributions char *client_args[] = { path, "-n", "throtlled_sp_client", NULL }; 2143*94d3b452SApple OSS Distributions 2144*94d3b452SApple OSS Distributions __block uint64_t thread_id = 0; 2145*94d3b452SApple OSS Distributions pid_t client_pid; 2146*94d3b452SApple OSS Distributions int mark_throttled; 2147*94d3b452SApple OSS Distributions 2148*94d3b452SApple OSS Distributions struct mach_service_port_info sp_info = {}; 2149*94d3b452SApple OSS Distributions strcpy(sp_info.mspi_string_name, THROTTLED_SERVICE_NAME); 2150*94d3b452SApple OSS Distributions sp_info.mspi_domain_type = (uint8_t)1; 2151*94d3b452SApple OSS Distributions kern_return_t kr; 2152*94d3b452SApple OSS Distributions 2153*94d3b452SApple OSS Distributions mach_port_options_t opts = { 2154*94d3b452SApple OSS Distributions .flags = MPO_SERVICE_PORT | MPO_INSERT_SEND_RIGHT | MPO_CONTEXT_AS_GUARD | MPO_STRICT | MPO_TEMPOWNER, 2155*94d3b452SApple OSS Distributions .service_port_info = &sp_info, 2156*94d3b452SApple OSS Distributions }; 2157*94d3b452SApple OSS Distributions 2158*94d3b452SApple OSS Distributions kr = mach_port_construct(mach_task_self(), &opts, 0ull, &service_port); 2159*94d3b452SApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "mach_port_construct %u", service_port); 2160*94d3b452SApple OSS Distributions 2161*94d3b452SApple OSS Distributions /* Setup a dispatch source to monitor the service port similar to how launchd does. */ 2162*94d3b452SApple OSS Distributions dispatch_queue_t machdq = dispatch_queue_create("machqueue", NULL); 2163*94d3b452SApple OSS Distributions dispatch_source_t mach_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, service_port, 2164*94d3b452SApple OSS Distributions DISPATCH_MACH_RECV_SYNC_PEEK, machdq); 2165*94d3b452SApple OSS Distributions dispatch_source_set_event_handler(mach_src, ^{ 2166*94d3b452SApple OSS Distributions pthread_threadid_np(NULL, &thread_id); 2167*94d3b452SApple OSS Distributions dispatch_semaphore_signal(can_continue); 2168*94d3b452SApple OSS Distributions }); 2169*94d3b452SApple OSS Distributions dispatch_activate(mach_src); 2170*94d3b452SApple OSS Distributions 2171*94d3b452SApple OSS Distributions /* Stash the port in task to make sure child also gets it */ 2172*94d3b452SApple OSS Distributions kr = mach_ports_register(mach_task_self(), &service_port, 1); 2173*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_ports_register service port"); 2174*94d3b452SApple OSS Distributions 2175*94d3b452SApple OSS Distributions mark_throttled = 1; 2176*94d3b452SApple OSS Distributions kr = mach_port_set_attributes(mach_task_self(), service_port, MACH_PORT_SERVICE_THROTTLED, (mach_port_info_t)(&mark_throttled), 2177*94d3b452SApple OSS Distributions MACH_PORT_SERVICE_THROTTLED_COUNT); 2178*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mark service port as throttled"); 2179*94d3b452SApple OSS Distributions 2180*94d3b452SApple OSS Distributions int rc = posix_spawn(&client_pid, client_args[0], NULL, NULL, client_args, NULL); 2181*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(rc, "spawned process '%s' with PID %d", client_args[0], client_pid); 2182*94d3b452SApple OSS Distributions T_LOG("Spawned client as PID %d", client_pid); 2183*94d3b452SApple OSS Distributions 2184*94d3b452SApple OSS Distributions dispatch_semaphore_wait(can_continue, DISPATCH_TIME_FOREVER); 2185*94d3b452SApple OSS Distributions 2186*94d3b452SApple OSS Distributions /* The service port has received the check-in message. Take stackshot for scenario (a). */ 2187*94d3b452SApple OSS Distributions check_throttled_sp("throttled_service_port_monitored", thread_id, true); 2188*94d3b452SApple OSS Distributions 2189*94d3b452SApple OSS Distributions /* This simulates a throttled spawn when the service port is no longer monitored. */ 2190*94d3b452SApple OSS Distributions dispatch_source_cancel(mach_src); 2191*94d3b452SApple OSS Distributions 2192*94d3b452SApple OSS Distributions /* Take stackshot for scenario (b) */ 2193*94d3b452SApple OSS Distributions check_throttled_sp("throttled_service_port_unmonitored", (uint64_t)getpid(), true); 2194*94d3b452SApple OSS Distributions 2195*94d3b452SApple OSS Distributions mark_throttled = 0; 2196*94d3b452SApple OSS Distributions kr = mach_port_set_attributes(mach_task_self(), service_port, MACH_PORT_SERVICE_THROTTLED, (mach_port_info_t)(&mark_throttled), 2197*94d3b452SApple OSS Distributions MACH_PORT_SERVICE_THROTTLED_COUNT); 2198*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "unmark service port as throttled"); 2199*94d3b452SApple OSS Distributions 2200*94d3b452SApple OSS Distributions /* Throttled flag should not be set when the port is not throttled. */ 2201*94d3b452SApple OSS Distributions check_throttled_sp("unthrottled_service_port_unmonitored", (uint64_t)getpid(), false); 2202*94d3b452SApple OSS Distributions 2203*94d3b452SApple OSS Distributions /* cleanup - kill the client */ 2204*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kill(client_pid, SIGKILL), "killing client"); 2205*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(waitpid(client_pid, NULL, 0), "waiting for the client to exit"); 2206*94d3b452SApple OSS Distributions} 2207*94d3b452SApple OSS Distributions 2208*94d3b452SApple OSS Distributions 2209*94d3b452SApple OSS Distributions#pragma mark performance tests 2210*94d3b452SApple OSS Distributions 2211*94d3b452SApple OSS Distributions#define SHOULD_REUSE_SIZE_HINT 0x01 2212*94d3b452SApple OSS Distributions#define SHOULD_USE_DELTA 0x02 2213*94d3b452SApple OSS Distributions#define SHOULD_TARGET_SELF 0x04 2214*94d3b452SApple OSS Distributions 2215*94d3b452SApple OSS Distributionsstatic void 2216*94d3b452SApple OSS Distributionsstackshot_perf(unsigned int options) 2217*94d3b452SApple OSS Distributions{ 2218*94d3b452SApple OSS Distributions struct scenario scenario = { 2219*94d3b452SApple OSS Distributions .flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_GET_GLOBAL_MEM_STATS 2220*94d3b452SApple OSS Distributions | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_KCDATA_FORMAT), 2221*94d3b452SApple OSS Distributions }; 2222*94d3b452SApple OSS Distributions 2223*94d3b452SApple OSS Distributions dt_stat_t size = dt_stat_create("bytes", "size"); 2224*94d3b452SApple OSS Distributions dt_stat_time_t duration = dt_stat_time_create("duration"); 2225*94d3b452SApple OSS Distributions scenario.timer = duration; 2226*94d3b452SApple OSS Distributions 2227*94d3b452SApple OSS Distributions if (options & SHOULD_TARGET_SELF) { 2228*94d3b452SApple OSS Distributions scenario.target_pid = getpid(); 2229*94d3b452SApple OSS Distributions } 2230*94d3b452SApple OSS Distributions 2231*94d3b452SApple OSS Distributions while (!dt_stat_stable(duration) || !dt_stat_stable(size)) { 2232*94d3b452SApple OSS Distributions __block uint64_t last_time = 0; 2233*94d3b452SApple OSS Distributions __block uint32_t size_hint = 0; 2234*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 2235*94d3b452SApple OSS Distributions dt_stat_add(size, (double)sslen); 2236*94d3b452SApple OSS Distributions last_time = stackshot_timestamp(ssbuf, sslen); 2237*94d3b452SApple OSS Distributions size_hint = (uint32_t)sslen; 2238*94d3b452SApple OSS Distributions }); 2239*94d3b452SApple OSS Distributions if (options & SHOULD_USE_DELTA) { 2240*94d3b452SApple OSS Distributions scenario.since_timestamp = last_time; 2241*94d3b452SApple OSS Distributions scenario.flags |= STACKSHOT_COLLECT_DELTA_SNAPSHOT; 2242*94d3b452SApple OSS Distributions } 2243*94d3b452SApple OSS Distributions if (options & SHOULD_REUSE_SIZE_HINT) { 2244*94d3b452SApple OSS Distributions scenario.size_hint = size_hint; 2245*94d3b452SApple OSS Distributions } 2246*94d3b452SApple OSS Distributions } 2247*94d3b452SApple OSS Distributions 2248*94d3b452SApple OSS Distributions dt_stat_finalize(duration); 2249*94d3b452SApple OSS Distributions dt_stat_finalize(size); 2250*94d3b452SApple OSS Distributions} 2251*94d3b452SApple OSS Distributions 2252*94d3b452SApple OSS Distributionsstatic void 2253*94d3b452SApple OSS Distributionsstackshot_flag_perf_noclobber(uint64_t flag, char *flagname) 2254*94d3b452SApple OSS Distributions{ 2255*94d3b452SApple OSS Distributions struct scenario scenario = { 2256*94d3b452SApple OSS Distributions .quiet = true, 2257*94d3b452SApple OSS Distributions .flags = (flag | STACKSHOT_KCDATA_FORMAT), 2258*94d3b452SApple OSS Distributions }; 2259*94d3b452SApple OSS Distributions 2260*94d3b452SApple OSS Distributions dt_stat_t duration = dt_stat_create("nanoseconds per thread", "%s_duration", flagname); 2261*94d3b452SApple OSS Distributions dt_stat_t size = dt_stat_create("bytes per thread", "%s_size", flagname); 2262*94d3b452SApple OSS Distributions T_LOG("Testing \"%s\" = 0x%" PRIx64, flagname, flag); 2263*94d3b452SApple OSS Distributions 2264*94d3b452SApple OSS Distributions while (!dt_stat_stable(duration) || !dt_stat_stable(size)) { 2265*94d3b452SApple OSS Distributions take_stackshot(&scenario, false, ^(void *ssbuf, size_t sslen) { 2266*94d3b452SApple OSS Distributions kcdata_iter_t iter = kcdata_iter(ssbuf, sslen); 2267*94d3b452SApple OSS Distributions unsigned long no_threads = 0; 2268*94d3b452SApple OSS Distributions mach_timebase_info_data_t timebase = {0, 0}; 2269*94d3b452SApple OSS Distributions uint64_t stackshot_duration = 0; 2270*94d3b452SApple OSS Distributions int found = 0; 2271*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(kcdata_iter_type(iter), KCDATA_BUFFER_BEGIN_STACKSHOT, "stackshot buffer"); 2272*94d3b452SApple OSS Distributions 2273*94d3b452SApple OSS Distributions KCDATA_ITER_FOREACH(iter) { 2274*94d3b452SApple OSS Distributions switch(kcdata_iter_type(iter)) { 2275*94d3b452SApple OSS Distributions case STACKSHOT_KCTYPE_THREAD_SNAPSHOT: { 2276*94d3b452SApple OSS Distributions found |= 1; 2277*94d3b452SApple OSS Distributions no_threads ++; 2278*94d3b452SApple OSS Distributions break; 2279*94d3b452SApple OSS Distributions } 2280*94d3b452SApple OSS Distributions case STACKSHOT_KCTYPE_STACKSHOT_DURATION: { 2281*94d3b452SApple OSS Distributions struct stackshot_duration *ssd = kcdata_iter_payload(iter); 2282*94d3b452SApple OSS Distributions stackshot_duration = ssd->stackshot_duration; 2283*94d3b452SApple OSS Distributions found |= 2; 2284*94d3b452SApple OSS Distributions break; 2285*94d3b452SApple OSS Distributions } 2286*94d3b452SApple OSS Distributions case KCDATA_TYPE_TIMEBASE: { 2287*94d3b452SApple OSS Distributions found |= 4; 2288*94d3b452SApple OSS Distributions mach_timebase_info_data_t *tb = kcdata_iter_payload(iter); 2289*94d3b452SApple OSS Distributions memcpy(&timebase, tb, sizeof(timebase)); 2290*94d3b452SApple OSS Distributions break; 2291*94d3b452SApple OSS Distributions } 2292*94d3b452SApple OSS Distributions } 2293*94d3b452SApple OSS Distributions } 2294*94d3b452SApple OSS Distributions 2295*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(found, 0x7, "found everything needed"); 2296*94d3b452SApple OSS Distributions 2297*94d3b452SApple OSS Distributions uint64_t ns = (stackshot_duration * timebase.numer) / timebase.denom; 2298*94d3b452SApple OSS Distributions uint64_t per_thread_ns = ns / no_threads; 2299*94d3b452SApple OSS Distributions uint64_t per_thread_size = sslen / no_threads; 2300*94d3b452SApple OSS Distributions 2301*94d3b452SApple OSS Distributions dt_stat_add(duration, per_thread_ns); 2302*94d3b452SApple OSS Distributions dt_stat_add(size, per_thread_size); 2303*94d3b452SApple OSS Distributions }); 2304*94d3b452SApple OSS Distributions } 2305*94d3b452SApple OSS Distributions 2306*94d3b452SApple OSS Distributions dt_stat_finalize(duration); 2307*94d3b452SApple OSS Distributions dt_stat_finalize(size); 2308*94d3b452SApple OSS Distributions} 2309*94d3b452SApple OSS Distributions 2310*94d3b452SApple OSS Distributionsstatic void 2311*94d3b452SApple OSS Distributionsstackshot_flag_perf(uint64_t flag, char *flagname) 2312*94d3b452SApple OSS Distributions{ 2313*94d3b452SApple OSS Distributions /* 2314*94d3b452SApple OSS Distributions * STACKSHOT_NO_IO_STATS disables data collection, so set it for 2315*94d3b452SApple OSS Distributions * more accurate perfdata collection. 2316*94d3b452SApple OSS Distributions */ 2317*94d3b452SApple OSS Distributions flag |= STACKSHOT_NO_IO_STATS; 2318*94d3b452SApple OSS Distributions 2319*94d3b452SApple OSS Distributions stackshot_flag_perf_noclobber(flag, flagname); 2320*94d3b452SApple OSS Distributions} 2321*94d3b452SApple OSS Distributions 2322*94d3b452SApple OSS Distributions 2323*94d3b452SApple OSS DistributionsT_DECL(flag_perf, "test stackshot performance with different flags set", T_META_TAG_PERF) 2324*94d3b452SApple OSS Distributions{ 2325*94d3b452SApple OSS Distributions stackshot_flag_perf_noclobber(STACKSHOT_NO_IO_STATS, "baseline"); 2326*94d3b452SApple OSS Distributions stackshot_flag_perf_noclobber(0, "io_stats"); 2327*94d3b452SApple OSS Distributions 2328*94d3b452SApple OSS Distributions stackshot_flag_perf(STACKSHOT_THREAD_WAITINFO, "thread_waitinfo"); 2329*94d3b452SApple OSS Distributions stackshot_flag_perf(STACKSHOT_GET_DQ, "get_dq"); 2330*94d3b452SApple OSS Distributions stackshot_flag_perf(STACKSHOT_SAVE_LOADINFO, "save_loadinfo"); 2331*94d3b452SApple OSS Distributions stackshot_flag_perf(STACKSHOT_GET_GLOBAL_MEM_STATS, "get_global_mem_stats"); 2332*94d3b452SApple OSS Distributions stackshot_flag_perf(STACKSHOT_SAVE_KEXT_LOADINFO, "save_kext_loadinfo"); 2333*94d3b452SApple OSS Distributions stackshot_flag_perf(STACKSHOT_SAVE_IMP_DONATION_PIDS, "save_imp_donation_pids"); 2334*94d3b452SApple OSS Distributions stackshot_flag_perf(STACKSHOT_ENABLE_BT_FAULTING, "enable_bt_faulting"); 2335*94d3b452SApple OSS Distributions stackshot_flag_perf(STACKSHOT_COLLECT_SHAREDCACHE_LAYOUT, "collect_sharedcache_layout"); 2336*94d3b452SApple OSS Distributions stackshot_flag_perf(STACKSHOT_ENABLE_UUID_FAULTING, "enable_uuid_faulting"); 2337*94d3b452SApple OSS Distributions stackshot_flag_perf(STACKSHOT_THREAD_GROUP, "thread_group"); 2338*94d3b452SApple OSS Distributions stackshot_flag_perf(STACKSHOT_SAVE_JETSAM_COALITIONS, "save_jetsam_coalitions"); 2339*94d3b452SApple OSS Distributions stackshot_flag_perf(STACKSHOT_INSTRS_CYCLES, "instrs_cycles"); 2340*94d3b452SApple OSS Distributions stackshot_flag_perf(STACKSHOT_ASID, "asid"); 2341*94d3b452SApple OSS Distributions} 2342*94d3b452SApple OSS Distributions 2343*94d3b452SApple OSS DistributionsT_DECL(perf_no_size_hint, "test stackshot performance with no size hint", 2344*94d3b452SApple OSS Distributions T_META_TAG_PERF) 2345*94d3b452SApple OSS Distributions{ 2346*94d3b452SApple OSS Distributions stackshot_perf(0); 2347*94d3b452SApple OSS Distributions} 2348*94d3b452SApple OSS Distributions 2349*94d3b452SApple OSS DistributionsT_DECL(perf_size_hint, "test stackshot performance with size hint", 2350*94d3b452SApple OSS Distributions T_META_TAG_PERF) 2351*94d3b452SApple OSS Distributions{ 2352*94d3b452SApple OSS Distributions stackshot_perf(SHOULD_REUSE_SIZE_HINT); 2353*94d3b452SApple OSS Distributions} 2354*94d3b452SApple OSS Distributions 2355*94d3b452SApple OSS DistributionsT_DECL(perf_process, "test stackshot performance targeted at process", 2356*94d3b452SApple OSS Distributions T_META_TAG_PERF) 2357*94d3b452SApple OSS Distributions{ 2358*94d3b452SApple OSS Distributions stackshot_perf(SHOULD_REUSE_SIZE_HINT | SHOULD_TARGET_SELF); 2359*94d3b452SApple OSS Distributions} 2360*94d3b452SApple OSS Distributions 2361*94d3b452SApple OSS DistributionsT_DECL(perf_delta, "test delta stackshot performance", 2362*94d3b452SApple OSS Distributions T_META_TAG_PERF) 2363*94d3b452SApple OSS Distributions{ 2364*94d3b452SApple OSS Distributions stackshot_perf(SHOULD_REUSE_SIZE_HINT | SHOULD_USE_DELTA); 2365*94d3b452SApple OSS Distributions} 2366*94d3b452SApple OSS Distributions 2367*94d3b452SApple OSS DistributionsT_DECL(perf_delta_process, "test delta stackshot performance targeted at a process", 2368*94d3b452SApple OSS Distributions T_META_TAG_PERF) 2369*94d3b452SApple OSS Distributions{ 2370*94d3b452SApple OSS Distributions stackshot_perf(SHOULD_REUSE_SIZE_HINT | SHOULD_USE_DELTA | SHOULD_TARGET_SELF); 2371*94d3b452SApple OSS Distributions} 2372*94d3b452SApple OSS Distributions 2373*94d3b452SApple OSS DistributionsT_DECL(stackshot_entitlement_report_test, "test stackshot entitlement report") 2374*94d3b452SApple OSS Distributions{ 2375*94d3b452SApple OSS Distributions int sysctlValue = 1; 2376*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS( 2377*94d3b452SApple OSS Distributions sysctlbyname("debug.stackshot_entitlement_send_batch", NULL, NULL, &sysctlValue, sizeof(sysctlValue)), 2378*94d3b452SApple OSS Distributions "set debug.stackshot_entitlement_send_batch=1"); 2379*94d3b452SApple OSS Distributions // having a way to verify that the coreanalytics event was received would be even better 2380*94d3b452SApple OSS Distributions // See rdar://74197197 2381*94d3b452SApple OSS Distributions T_PASS("entitlement test ran"); 2382*94d3b452SApple OSS Distributions} 2383*94d3b452SApple OSS Distributions 2384*94d3b452SApple OSS Distributionsstatic uint64_t 2385*94d3b452SApple OSS Distributionsstackshot_timestamp(void *ssbuf, size_t sslen) 2386*94d3b452SApple OSS Distributions{ 2387*94d3b452SApple OSS Distributions kcdata_iter_t iter = kcdata_iter(ssbuf, sslen); 2388*94d3b452SApple OSS Distributions 2389*94d3b452SApple OSS Distributions uint32_t type = kcdata_iter_type(iter); 2390*94d3b452SApple OSS Distributions if (type != KCDATA_BUFFER_BEGIN_STACKSHOT && type != KCDATA_BUFFER_BEGIN_DELTA_STACKSHOT) { 2391*94d3b452SApple OSS Distributions T_ASSERT_FAIL("invalid kcdata type %u", kcdata_iter_type(iter)); 2392*94d3b452SApple OSS Distributions } 2393*94d3b452SApple OSS Distributions 2394*94d3b452SApple OSS Distributions iter = kcdata_iter_find_type(iter, KCDATA_TYPE_MACH_ABSOLUTE_TIME); 2395*94d3b452SApple OSS Distributions T_QUIET; 2396*94d3b452SApple OSS Distributions T_ASSERT_TRUE(kcdata_iter_valid(iter), "timestamp found in stackshot"); 2397*94d3b452SApple OSS Distributions 2398*94d3b452SApple OSS Distributions return *(uint64_t *)kcdata_iter_payload(iter); 2399*94d3b452SApple OSS Distributions} 2400*94d3b452SApple OSS Distributions 2401*94d3b452SApple OSS Distributions#define TEST_THREAD_NAME "stackshot_test_thread" 2402*94d3b452SApple OSS Distributions 2403*94d3b452SApple OSS Distributionsstatic void 2404*94d3b452SApple OSS Distributionsparse_thread_group_stackshot(void **ssbuf, size_t sslen) 2405*94d3b452SApple OSS Distributions{ 2406*94d3b452SApple OSS Distributions bool seen_thread_group_snapshot = false; 2407*94d3b452SApple OSS Distributions kcdata_iter_t iter = kcdata_iter(ssbuf, sslen); 2408*94d3b452SApple OSS Distributions T_ASSERT_EQ(kcdata_iter_type(iter), KCDATA_BUFFER_BEGIN_STACKSHOT, 2409*94d3b452SApple OSS Distributions "buffer provided is a stackshot"); 2410*94d3b452SApple OSS Distributions 2411*94d3b452SApple OSS Distributions NSMutableSet *thread_groups = [[NSMutableSet alloc] init]; 2412*94d3b452SApple OSS Distributions 2413*94d3b452SApple OSS Distributions iter = kcdata_iter_next(iter); 2414*94d3b452SApple OSS Distributions KCDATA_ITER_FOREACH(iter) { 2415*94d3b452SApple OSS Distributions switch (kcdata_iter_type(iter)) { 2416*94d3b452SApple OSS Distributions case KCDATA_TYPE_ARRAY: { 2417*94d3b452SApple OSS Distributions T_QUIET; 2418*94d3b452SApple OSS Distributions T_ASSERT_TRUE(kcdata_iter_array_valid(iter), 2419*94d3b452SApple OSS Distributions "checked that array is valid"); 2420*94d3b452SApple OSS Distributions 2421*94d3b452SApple OSS Distributions if (kcdata_iter_array_elem_type(iter) != STACKSHOT_KCTYPE_THREAD_GROUP_SNAPSHOT) { 2422*94d3b452SApple OSS Distributions continue; 2423*94d3b452SApple OSS Distributions } 2424*94d3b452SApple OSS Distributions 2425*94d3b452SApple OSS Distributions seen_thread_group_snapshot = true; 2426*94d3b452SApple OSS Distributions 2427*94d3b452SApple OSS Distributions if (kcdata_iter_array_elem_size(iter) >= sizeof(struct thread_group_snapshot_v3)) { 2428*94d3b452SApple OSS Distributions struct thread_group_snapshot_v3 *tgs_array = kcdata_iter_payload(iter); 2429*94d3b452SApple OSS Distributions for (uint32_t j = 0; j < kcdata_iter_array_elem_count(iter); j++) { 2430*94d3b452SApple OSS Distributions struct thread_group_snapshot_v3 *tgs = tgs_array + j; 2431*94d3b452SApple OSS Distributions [thread_groups addObject:@(tgs->tgs_id)]; 2432*94d3b452SApple OSS Distributions } 2433*94d3b452SApple OSS Distributions } 2434*94d3b452SApple OSS Distributions else { 2435*94d3b452SApple OSS Distributions struct thread_group_snapshot *tgs_array = kcdata_iter_payload(iter); 2436*94d3b452SApple OSS Distributions for (uint32_t j = 0; j < kcdata_iter_array_elem_count(iter); j++) { 2437*94d3b452SApple OSS Distributions struct thread_group_snapshot *tgs = tgs_array + j; 2438*94d3b452SApple OSS Distributions [thread_groups addObject:@(tgs->tgs_id)]; 2439*94d3b452SApple OSS Distributions } 2440*94d3b452SApple OSS Distributions } 2441*94d3b452SApple OSS Distributions break; 2442*94d3b452SApple OSS Distributions } 2443*94d3b452SApple OSS Distributions } 2444*94d3b452SApple OSS Distributions } 2445*94d3b452SApple OSS Distributions KCDATA_ITER_FOREACH(iter) { 2446*94d3b452SApple OSS Distributions NSError *error = nil; 2447*94d3b452SApple OSS Distributions 2448*94d3b452SApple OSS Distributions switch (kcdata_iter_type(iter)) { 2449*94d3b452SApple OSS Distributions 2450*94d3b452SApple OSS Distributions case KCDATA_TYPE_CONTAINER_BEGIN: { 2451*94d3b452SApple OSS Distributions T_QUIET; 2452*94d3b452SApple OSS Distributions T_ASSERT_TRUE(kcdata_iter_container_valid(iter), 2453*94d3b452SApple OSS Distributions "checked that container is valid"); 2454*94d3b452SApple OSS Distributions 2455*94d3b452SApple OSS Distributions if (kcdata_iter_container_type(iter) != STACKSHOT_KCCONTAINER_THREAD) { 2456*94d3b452SApple OSS Distributions break; 2457*94d3b452SApple OSS Distributions } 2458*94d3b452SApple OSS Distributions 2459*94d3b452SApple OSS Distributions NSDictionary *container = parseKCDataContainer(&iter, &error); 2460*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(container, "parsed thread container from stackshot"); 2461*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NULL(error, "error unset after parsing container"); 2462*94d3b452SApple OSS Distributions 2463*94d3b452SApple OSS Distributions int tg = [container[@"thread_snapshots"][@"thread_group"] intValue]; 2464*94d3b452SApple OSS Distributions 2465*94d3b452SApple OSS Distributions T_ASSERT_TRUE([thread_groups containsObject:@(tg)], "check that the thread group the thread is in exists"); 2466*94d3b452SApple OSS Distributions 2467*94d3b452SApple OSS Distributions break; 2468*94d3b452SApple OSS Distributions }; 2469*94d3b452SApple OSS Distributions 2470*94d3b452SApple OSS Distributions } 2471*94d3b452SApple OSS Distributions } 2472*94d3b452SApple OSS Distributions T_ASSERT_TRUE(seen_thread_group_snapshot, "check that we have seen a thread group snapshot"); 2473*94d3b452SApple OSS Distributions} 2474*94d3b452SApple OSS Distributions 2475*94d3b452SApple OSS Distributionsstatic void 2476*94d3b452SApple OSS Distributionsverify_stackshot_sharedcache_layout(struct dyld_uuid_info_64 *uuids, uint32_t uuid_count) 2477*94d3b452SApple OSS Distributions{ 2478*94d3b452SApple OSS Distributions uuid_t cur_shared_cache_uuid; 2479*94d3b452SApple OSS Distributions __block uint32_t lib_index = 0, libs_found = 0; 2480*94d3b452SApple OSS Distributions 2481*94d3b452SApple OSS Distributions _dyld_get_shared_cache_uuid(cur_shared_cache_uuid); 2482*94d3b452SApple OSS Distributions int result = dyld_shared_cache_iterate_text(cur_shared_cache_uuid, ^(const dyld_shared_cache_dylib_text_info* info) { 2483*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_LT(lib_index, uuid_count, "dyld_shared_cache_iterate_text exceeded number of libraries returned by kernel"); 2484*94d3b452SApple OSS Distributions 2485*94d3b452SApple OSS Distributions libs_found++; 2486*94d3b452SApple OSS Distributions struct dyld_uuid_info_64 *cur_stackshot_uuid_entry = &uuids[lib_index]; 2487*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(memcmp(info->dylibUuid, cur_stackshot_uuid_entry->imageUUID, sizeof(info->dylibUuid)), 0, 2488*94d3b452SApple OSS Distributions "dyld returned UUID doesn't match kernel returned UUID"); 2489*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(info->loadAddressUnslid, cur_stackshot_uuid_entry->imageLoadAddress, 2490*94d3b452SApple OSS Distributions "dyld returned load address doesn't match kernel returned load address"); 2491*94d3b452SApple OSS Distributions lib_index++; 2492*94d3b452SApple OSS Distributions }); 2493*94d3b452SApple OSS Distributions 2494*94d3b452SApple OSS Distributions T_ASSERT_EQ(result, 0, "iterate shared cache layout"); 2495*94d3b452SApple OSS Distributions T_ASSERT_EQ(libs_found, uuid_count, "dyld iterator returned same number of libraries as kernel"); 2496*94d3b452SApple OSS Distributions 2497*94d3b452SApple OSS Distributions T_LOG("verified %d libraries from dyld shared cache", libs_found); 2498*94d3b452SApple OSS Distributions} 2499*94d3b452SApple OSS Distributions 2500*94d3b452SApple OSS Distributionsstatic void 2501*94d3b452SApple OSS Distributionscheck_shared_cache_uuid(uuid_t imageUUID) 2502*94d3b452SApple OSS Distributions{ 2503*94d3b452SApple OSS Distributions static uuid_t shared_cache_uuid; 2504*94d3b452SApple OSS Distributions static dispatch_once_t read_shared_cache_uuid; 2505*94d3b452SApple OSS Distributions 2506*94d3b452SApple OSS Distributions dispatch_once(&read_shared_cache_uuid, ^{ 2507*94d3b452SApple OSS Distributions T_QUIET; 2508*94d3b452SApple OSS Distributions T_ASSERT_TRUE(_dyld_get_shared_cache_uuid(shared_cache_uuid), "retrieve current shared cache UUID"); 2509*94d3b452SApple OSS Distributions }); 2510*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(uuid_compare(shared_cache_uuid, imageUUID), 0, 2511*94d3b452SApple OSS Distributions "dyld returned UUID doesn't match kernel returned UUID for system shared cache"); 2512*94d3b452SApple OSS Distributions} 2513*94d3b452SApple OSS Distributions 2514*94d3b452SApple OSS Distributions/* 2515*94d3b452SApple OSS Distributions * extra dictionary contains data relevant for the given flags: 2516*94d3b452SApple OSS Distributions * PARSE_STACKSHOT_ZOMBIE: zombie_child_pid_key -> @(pid) 2517*94d3b452SApple OSS Distributions * PARSE_STACKSHOT_POSTEXEC: postexec_child_unique_pid_key -> @(unique_pid) 2518*94d3b452SApple OSS Distributions */ 2519*94d3b452SApple OSS Distributionsstatic void 2520*94d3b452SApple OSS Distributionsparse_stackshot(uint64_t stackshot_parsing_flags, void *ssbuf, size_t sslen, NSDictionary *extra) 2521*94d3b452SApple OSS Distributions{ 2522*94d3b452SApple OSS Distributions bool delta = (stackshot_parsing_flags & PARSE_STACKSHOT_DELTA); 2523*94d3b452SApple OSS Distributions bool expect_sharedcache_child = (stackshot_parsing_flags & PARSE_STACKSHOT_SHAREDCACHE_FLAGS); 2524*94d3b452SApple OSS Distributions bool expect_zombie_child = (stackshot_parsing_flags & PARSE_STACKSHOT_ZOMBIE); 2525*94d3b452SApple OSS Distributions bool expect_postexec_child = (stackshot_parsing_flags & PARSE_STACKSHOT_POSTEXEC); 2526*94d3b452SApple OSS Distributions bool expect_cseg_waitinfo = (stackshot_parsing_flags & PARSE_STACKSHOT_WAITINFO_CSEG); 2527*94d3b452SApple OSS Distributions bool expect_translated_child = (stackshot_parsing_flags & PARSE_STACKSHOT_TRANSLATED); 2528*94d3b452SApple OSS Distributions bool expect_shared_cache_layout = false; 2529*94d3b452SApple OSS Distributions bool expect_shared_cache_uuid = !delta; 2530*94d3b452SApple OSS Distributions bool expect_dispatch_queue_label = (stackshot_parsing_flags & PARSE_STACKSHOT_DISPATCH_QUEUE_LABEL); 2531*94d3b452SApple OSS Distributions bool expect_turnstile_lock = (stackshot_parsing_flags & PARSE_STACKSHOT_TURNSTILEINFO); 2532*94d3b452SApple OSS Distributions bool expect_srp_waitinfo = (stackshot_parsing_flags & PARSE_STACKSHOT_WAITINFO_SRP); 2533*94d3b452SApple OSS Distributions bool expect_sp_throttled = (stackshot_parsing_flags & PARSE_STACKSHOT_THROTTLED_SP); 2534*94d3b452SApple OSS Distributions bool expect_exec_inprogress = (stackshot_parsing_flags & PARSE_STACKSHOT_EXEC_INPROGRESS); 2535*94d3b452SApple OSS Distributions bool expect_transitioning_task = (stackshot_parsing_flags & PARSE_STACKSHOT_TRANSITIONING); 2536*94d3b452SApple OSS Distributions bool expect_asyncstack = (stackshot_parsing_flags & PARSE_STACKSHOT_ASYNCSTACK); 2537*94d3b452SApple OSS Distributions bool expect_driverkit = (stackshot_parsing_flags & PARSE_STACKSHOT_DRIVERKIT); 2538*94d3b452SApple OSS Distributions bool expect_suspendinfo = (stackshot_parsing_flags & PARSE_STACKSHOT_SUSPENDINFO); 2539*94d3b452SApple OSS Distributions bool found_zombie_child = false, found_postexec_child = false, found_shared_cache_layout = false, found_shared_cache_uuid = false; 2540*94d3b452SApple OSS Distributions bool found_translated_child = false, found_transitioning_task = false; 2541*94d3b452SApple OSS Distributions bool found_dispatch_queue_label = false, found_turnstile_lock = false; 2542*94d3b452SApple OSS Distributions bool found_cseg_waitinfo = false, found_srp_waitinfo = false; 2543*94d3b452SApple OSS Distributions bool found_sharedcache_child = false, found_sharedcache_badflags = false, found_sharedcache_self = false; 2544*94d3b452SApple OSS Distributions bool found_asyncstack = false; 2545*94d3b452SApple OSS Distributions bool found_throttled_service = false; 2546*94d3b452SApple OSS Distributions uint64_t srp_expected_threadid = 0; 2547*94d3b452SApple OSS Distributions pid_t zombie_child_pid = -1, srp_expected_pid = -1, sharedcache_child_pid = -1, throttled_service_ctx = -1; 2548*94d3b452SApple OSS Distributions pid_t translated_child_pid = -1, transistioning_task_pid = -1; 2549*94d3b452SApple OSS Distributions bool sharedcache_child_sameaddr = false, is_throttled = false; 2550*94d3b452SApple OSS Distributions uint64_t postexec_child_unique_pid = 0, cseg_expected_threadid = 0; 2551*94d3b452SApple OSS Distributions uint64_t sharedcache_child_flags = 0, sharedcache_self_flags = 0; 2552*94d3b452SApple OSS Distributions uint64_t asyncstack_threadid = 0; 2553*94d3b452SApple OSS Distributions NSArray *asyncstack_stack = nil; 2554*94d3b452SApple OSS Distributions char *inflatedBufferBase = NULL; 2555*94d3b452SApple OSS Distributions pid_t exec_inprogress_pid = -1; 2556*94d3b452SApple OSS Distributions void (^exec_inprogress_cb)(uint64_t, uint64_t) = NULL; 2557*94d3b452SApple OSS Distributions int exec_inprogress_found = 0; 2558*94d3b452SApple OSS Distributions uint64_t exec_inprogress_containerid = 0; 2559*94d3b452SApple OSS Distributions void (^driverkit_cb)(pid_t) = NULL; 2560*94d3b452SApple OSS Distributions NSMutableDictionary *sharedCaches = [NSMutableDictionary new]; 2561*94d3b452SApple OSS Distributions 2562*94d3b452SApple OSS Distributions if (expect_shared_cache_uuid) { 2563*94d3b452SApple OSS Distributions uuid_t shared_cache_uuid; 2564*94d3b452SApple OSS Distributions if (!_dyld_get_shared_cache_uuid(shared_cache_uuid)) { 2565*94d3b452SApple OSS Distributions T_LOG("Skipping verifying shared cache UUID in stackshot data because not running with a shared cache"); 2566*94d3b452SApple OSS Distributions expect_shared_cache_uuid = false; 2567*94d3b452SApple OSS Distributions } 2568*94d3b452SApple OSS Distributions } 2569*94d3b452SApple OSS Distributions 2570*94d3b452SApple OSS Distributions if (stackshot_parsing_flags & PARSE_STACKSHOT_SHAREDCACHE_LAYOUT) { 2571*94d3b452SApple OSS Distributions size_t shared_cache_length = 0; 2572*94d3b452SApple OSS Distributions const void *cache_header = _dyld_get_shared_cache_range(&shared_cache_length); 2573*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(cache_header, "current process running with shared cache"); 2574*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_GT(shared_cache_length, sizeof(struct _dyld_cache_header), "valid shared cache length populated by _dyld_get_shared_cache_range"); 2575*94d3b452SApple OSS Distributions 2576*94d3b452SApple OSS Distributions if (_dyld_shared_cache_is_locally_built()) { 2577*94d3b452SApple OSS Distributions T_LOG("device running with locally built shared cache, expect shared cache layout"); 2578*94d3b452SApple OSS Distributions expect_shared_cache_layout = true; 2579*94d3b452SApple OSS Distributions } else { 2580*94d3b452SApple OSS Distributions T_LOG("device running with B&I built shared-cache, no shared cache layout expected"); 2581*94d3b452SApple OSS Distributions } 2582*94d3b452SApple OSS Distributions } 2583*94d3b452SApple OSS Distributions 2584*94d3b452SApple OSS Distributions if (expect_sharedcache_child) { 2585*94d3b452SApple OSS Distributions NSNumber* pid_num = extra[sharedcache_child_pid_key]; 2586*94d3b452SApple OSS Distributions NSNumber* sameaddr_num = extra[sharedcache_child_sameaddr_key]; 2587*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(pid_num, "sharedcache child pid provided"); 2588*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(sameaddr_num, "sharedcache child addrsame provided"); 2589*94d3b452SApple OSS Distributions sharedcache_child_pid = [pid_num intValue]; 2590*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_GT(sharedcache_child_pid, 0, "sharedcache child pid greater than zero"); 2591*94d3b452SApple OSS Distributions sharedcache_child_sameaddr = [sameaddr_num intValue]; 2592*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_GE([sameaddr_num intValue], 0, "sharedcache child sameaddr is boolean (0 or 1)"); 2593*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_LE([sameaddr_num intValue], 1, "sharedcache child sameaddr is boolean (0 or 1)"); 2594*94d3b452SApple OSS Distributions } 2595*94d3b452SApple OSS Distributions 2596*94d3b452SApple OSS Distributions if (expect_transitioning_task) { 2597*94d3b452SApple OSS Distributions NSNumber* pid_num = extra[transitioning_pid_key]; 2598*94d3b452SApple OSS Distributions T_ASSERT_NOTNULL(pid_num, "transitioning task pid provided"); 2599*94d3b452SApple OSS Distributions transistioning_task_pid = [pid_num intValue]; 2600*94d3b452SApple OSS Distributions } 2601*94d3b452SApple OSS Distributions 2602*94d3b452SApple OSS Distributions if (expect_zombie_child) { 2603*94d3b452SApple OSS Distributions NSNumber* pid_num = extra[zombie_child_pid_key]; 2604*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(pid_num, "zombie child pid provided"); 2605*94d3b452SApple OSS Distributions zombie_child_pid = [pid_num intValue]; 2606*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_GT(zombie_child_pid, 0, "zombie child pid greater than zero"); 2607*94d3b452SApple OSS Distributions } 2608*94d3b452SApple OSS Distributions 2609*94d3b452SApple OSS Distributions if (expect_postexec_child) { 2610*94d3b452SApple OSS Distributions NSNumber* unique_pid_num = extra[postexec_child_unique_pid_key]; 2611*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(unique_pid_num, "postexec child unique pid provided"); 2612*94d3b452SApple OSS Distributions postexec_child_unique_pid = [unique_pid_num unsignedLongLongValue]; 2613*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_GT(postexec_child_unique_pid, 0ull, "postexec child unique pid greater than zero"); 2614*94d3b452SApple OSS Distributions } 2615*94d3b452SApple OSS Distributions 2616*94d3b452SApple OSS Distributions if (expect_cseg_waitinfo) { 2617*94d3b452SApple OSS Distributions NSNumber* tid_num = extra[cseg_expected_threadid_key]; 2618*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(tid_num, "cseg's expected thread id provided"); 2619*94d3b452SApple OSS Distributions cseg_expected_threadid = tid_num.unsignedLongValue; 2620*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_GT(cseg_expected_threadid, UINT64_C(0), "compressor segment thread is present"); 2621*94d3b452SApple OSS Distributions } 2622*94d3b452SApple OSS Distributions 2623*94d3b452SApple OSS Distributions if (expect_srp_waitinfo) { 2624*94d3b452SApple OSS Distributions NSNumber* threadid_num = extra[srp_expected_threadid_key]; 2625*94d3b452SApple OSS Distributions NSNumber* pid_num = extra[srp_expected_pid_key]; 2626*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(threadid_num != nil || pid_num != nil, "expected SRP threadid or pid"); 2627*94d3b452SApple OSS Distributions if (threadid_num != nil) { 2628*94d3b452SApple OSS Distributions srp_expected_threadid = [threadid_num unsignedLongLongValue]; 2629*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_GT(srp_expected_threadid, 0ull, "srp_expected_threadid greater than zero"); 2630*94d3b452SApple OSS Distributions } 2631*94d3b452SApple OSS Distributions if (pid_num != nil) { 2632*94d3b452SApple OSS Distributions srp_expected_pid = [pid_num intValue]; 2633*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_GT(srp_expected_pid, 0, "srp_expected_pid greater than zero"); 2634*94d3b452SApple OSS Distributions } 2635*94d3b452SApple OSS Distributions T_LOG("looking for SRP pid: %d threadid: %llu", srp_expected_pid, srp_expected_threadid); 2636*94d3b452SApple OSS Distributions } 2637*94d3b452SApple OSS Distributions 2638*94d3b452SApple OSS Distributions if (expect_sp_throttled) { 2639*94d3b452SApple OSS Distributions NSNumber* ctx = extra[sp_throttled_expected_ctxt_key]; 2640*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(ctx != nil, "expected pid"); 2641*94d3b452SApple OSS Distributions throttled_service_ctx = [ctx intValue]; 2642*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_GT(throttled_service_ctx, 0, "expected pid greater than zero"); 2643*94d3b452SApple OSS Distributions 2644*94d3b452SApple OSS Distributions NSNumber *throttled = extra[sp_throttled_expect_flag]; 2645*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(throttled != nil, "expected flag value"); 2646*94d3b452SApple OSS Distributions is_throttled = ([throttled intValue] != 0); 2647*94d3b452SApple OSS Distributions 2648*94d3b452SApple OSS Distributions T_LOG("Looking for service with ctxt: %d, thottled:%d", throttled_service_ctx, is_throttled); 2649*94d3b452SApple OSS Distributions } 2650*94d3b452SApple OSS Distributions 2651*94d3b452SApple OSS Distributions if (expect_translated_child) { 2652*94d3b452SApple OSS Distributions NSNumber* pid_num = extra[translated_child_pid_key]; 2653*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(pid_num, "translated child pid provided"); 2654*94d3b452SApple OSS Distributions translated_child_pid = [pid_num intValue]; 2655*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_GT(translated_child_pid, 0, "translated child pid greater than zero"); 2656*94d3b452SApple OSS Distributions } 2657*94d3b452SApple OSS Distributions if (expect_exec_inprogress) { 2658*94d3b452SApple OSS Distributions NSNumber* pid_num = extra[exec_inprogress_pid_key]; 2659*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(pid_num, "exec inprogress pid provided"); 2660*94d3b452SApple OSS Distributions exec_inprogress_pid = [pid_num intValue]; 2661*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_GT(exec_inprogress_pid, 0, "exec inprogress pid greater than zero"); 2662*94d3b452SApple OSS Distributions 2663*94d3b452SApple OSS Distributions exec_inprogress_cb = extra[exec_inprogress_found_key]; 2664*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(exec_inprogress_cb, "exec inprogress found callback provided"); 2665*94d3b452SApple OSS Distributions } 2666*94d3b452SApple OSS Distributions if (expect_driverkit) { 2667*94d3b452SApple OSS Distributions driverkit_cb = extra[driverkit_found_key]; 2668*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(driverkit_cb, "driverkit found callback provided"); 2669*94d3b452SApple OSS Distributions } 2670*94d3b452SApple OSS Distributions 2671*94d3b452SApple OSS Distributions if (expect_asyncstack) { 2672*94d3b452SApple OSS Distributions NSNumber* threadid_id = extra[asyncstack_expected_threadid_key]; 2673*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(threadid_id, "asyncstack threadid provided"); 2674*94d3b452SApple OSS Distributions asyncstack_threadid = [threadid_id unsignedLongLongValue]; 2675*94d3b452SApple OSS Distributions asyncstack_stack = extra[asyncstack_expected_stack_key]; 2676*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(asyncstack_stack, "asyncstack expected stack provided"); 2677*94d3b452SApple OSS Distributions } 2678*94d3b452SApple OSS Distributions 2679*94d3b452SApple OSS Distributions kcdata_iter_t iter = kcdata_iter(ssbuf, sslen); 2680*94d3b452SApple OSS Distributions if (delta) { 2681*94d3b452SApple OSS Distributions T_ASSERT_EQ(kcdata_iter_type(iter), KCDATA_BUFFER_BEGIN_DELTA_STACKSHOT, 2682*94d3b452SApple OSS Distributions "buffer provided is a delta stackshot"); 2683*94d3b452SApple OSS Distributions 2684*94d3b452SApple OSS Distributions iter = kcdata_iter_next(iter); 2685*94d3b452SApple OSS Distributions } else { 2686*94d3b452SApple OSS Distributions if (kcdata_iter_type(iter) != KCDATA_BUFFER_BEGIN_COMPRESSED) { 2687*94d3b452SApple OSS Distributions T_ASSERT_EQ(kcdata_iter_type(iter), KCDATA_BUFFER_BEGIN_STACKSHOT, 2688*94d3b452SApple OSS Distributions "buffer provided is a stackshot"); 2689*94d3b452SApple OSS Distributions 2690*94d3b452SApple OSS Distributions iter = kcdata_iter_next(iter); 2691*94d3b452SApple OSS Distributions } else { 2692*94d3b452SApple OSS Distributions /* we are dealing with a compressed buffer */ 2693*94d3b452SApple OSS Distributions iter = kcdata_iter_next(iter); 2694*94d3b452SApple OSS Distributions uint64_t compression_type = 0, totalout = 0, totalin = 0; 2695*94d3b452SApple OSS Distributions 2696*94d3b452SApple OSS Distributions uint64_t *data; 2697*94d3b452SApple OSS Distributions char *desc; 2698*94d3b452SApple OSS Distributions for (int i = 0; i < 3; i ++) { 2699*94d3b452SApple OSS Distributions kcdata_iter_get_data_with_desc(iter, &desc, (void **)&data, NULL); 2700*94d3b452SApple OSS Distributions if (strcmp(desc, "kcd_c_type") == 0) { 2701*94d3b452SApple OSS Distributions compression_type = *data; 2702*94d3b452SApple OSS Distributions } else if (strcmp(desc, "kcd_c_totalout") == 0){ 2703*94d3b452SApple OSS Distributions totalout = *data; 2704*94d3b452SApple OSS Distributions } else if (strcmp(desc, "kcd_c_totalin") == 0){ 2705*94d3b452SApple OSS Distributions totalin = *data; 2706*94d3b452SApple OSS Distributions } 2707*94d3b452SApple OSS Distributions 2708*94d3b452SApple OSS Distributions iter = kcdata_iter_next(iter); 2709*94d3b452SApple OSS Distributions } 2710*94d3b452SApple OSS Distributions 2711*94d3b452SApple OSS Distributions T_ASSERT_EQ(compression_type, UINT64_C(1), "zlib compression is used"); 2712*94d3b452SApple OSS Distributions T_ASSERT_GT(totalout, UINT64_C(0), "successfully gathered how long the compressed buffer is"); 2713*94d3b452SApple OSS Distributions T_ASSERT_GT(totalin, UINT64_C(0), "successfully gathered how long the uncompressed buffer will be at least"); 2714*94d3b452SApple OSS Distributions 2715*94d3b452SApple OSS Distributions /* progress to the next kcdata item */ 2716*94d3b452SApple OSS Distributions T_ASSERT_EQ(kcdata_iter_type(iter), KCDATA_BUFFER_BEGIN_STACKSHOT, "compressed stackshot found"); 2717*94d3b452SApple OSS Distributions 2718*94d3b452SApple OSS Distributions char *bufferBase = kcdata_iter_payload(iter); 2719*94d3b452SApple OSS Distributions 2720*94d3b452SApple OSS Distributions /* 2721*94d3b452SApple OSS Distributions * zlib is used, allocate a buffer based on the metadata, plus 2722*94d3b452SApple OSS Distributions * extra scratch space (+12.5%) in case totalin was inconsistent 2723*94d3b452SApple OSS Distributions */ 2724*94d3b452SApple OSS Distributions size_t inflatedBufferSize = totalin + (totalin >> 3); 2725*94d3b452SApple OSS Distributions inflatedBufferBase = malloc(inflatedBufferSize); 2726*94d3b452SApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(inflatedBufferBase, "allocated temporary output buffer"); 2727*94d3b452SApple OSS Distributions 2728*94d3b452SApple OSS Distributions z_stream zs; 2729*94d3b452SApple OSS Distributions memset(&zs, 0, sizeof(zs)); 2730*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(inflateInit(&zs), Z_OK, "inflateInit OK"); 2731*94d3b452SApple OSS Distributions zs.next_in = (unsigned char *)bufferBase; 2732*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_LE(totalout, (uint64_t)UINT_MAX, "stackshot is not too large"); 2733*94d3b452SApple OSS Distributions zs.avail_in = (uInt)totalout; 2734*94d3b452SApple OSS Distributions zs.next_out = (unsigned char *)inflatedBufferBase; 2735*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_LE(inflatedBufferSize, (size_t)UINT_MAX, "output region is not too large"); 2736*94d3b452SApple OSS Distributions zs.avail_out = (uInt)inflatedBufferSize; 2737*94d3b452SApple OSS Distributions T_ASSERT_EQ(inflate(&zs, Z_FINISH), Z_STREAM_END, "inflated buffer"); 2738*94d3b452SApple OSS Distributions inflateEnd(&zs); 2739*94d3b452SApple OSS Distributions 2740*94d3b452SApple OSS Distributions T_ASSERT_EQ((uint64_t)zs.total_out, totalin, "expected number of bytes inflated"); 2741*94d3b452SApple OSS Distributions 2742*94d3b452SApple OSS Distributions /* copy the data after the compressed area */ 2743*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_GE((void *)bufferBase, ssbuf, 2744*94d3b452SApple OSS Distributions "base of compressed stackshot is after the returned stackshot buffer"); 2745*94d3b452SApple OSS Distributions size_t header_size = (size_t)(bufferBase - (char *)ssbuf); 2746*94d3b452SApple OSS Distributions size_t data_after_compressed_size = sslen - totalout - header_size; 2747*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_LE(data_after_compressed_size, 2748*94d3b452SApple OSS Distributions inflatedBufferSize - zs.total_out, 2749*94d3b452SApple OSS Distributions "footer fits in the buffer"); 2750*94d3b452SApple OSS Distributions memcpy(inflatedBufferBase + zs.total_out, 2751*94d3b452SApple OSS Distributions bufferBase + totalout, 2752*94d3b452SApple OSS Distributions data_after_compressed_size); 2753*94d3b452SApple OSS Distributions 2754*94d3b452SApple OSS Distributions iter = kcdata_iter(inflatedBufferBase, inflatedBufferSize); 2755*94d3b452SApple OSS Distributions } 2756*94d3b452SApple OSS Distributions } 2757*94d3b452SApple OSS Distributions 2758*94d3b452SApple OSS Distributions KCDATA_ITER_FOREACH(iter) { 2759*94d3b452SApple OSS Distributions NSError *error = nil; 2760*94d3b452SApple OSS Distributions 2761*94d3b452SApple OSS Distributions switch (kcdata_iter_type(iter)) { 2762*94d3b452SApple OSS Distributions case KCDATA_TYPE_ARRAY: { 2763*94d3b452SApple OSS Distributions T_QUIET; 2764*94d3b452SApple OSS Distributions T_ASSERT_TRUE(kcdata_iter_array_valid(iter), 2765*94d3b452SApple OSS Distributions "checked that array is valid"); 2766*94d3b452SApple OSS Distributions 2767*94d3b452SApple OSS Distributions NSMutableDictionary *array = parseKCDataArray(iter, &error); 2768*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(array, "parsed array from stackshot"); 2769*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NULL(error, "error unset after parsing array"); 2770*94d3b452SApple OSS Distributions 2771*94d3b452SApple OSS Distributions if (kcdata_iter_array_elem_type(iter) == STACKSHOT_KCTYPE_SYS_SHAREDCACHE_LAYOUT) { 2772*94d3b452SApple OSS Distributions struct dyld_uuid_info_64 *shared_cache_uuids = kcdata_iter_payload(iter); 2773*94d3b452SApple OSS Distributions uint32_t uuid_count = kcdata_iter_array_elem_count(iter); 2774*94d3b452SApple OSS Distributions T_ASSERT_NOTNULL(shared_cache_uuids, "parsed shared cache layout array"); 2775*94d3b452SApple OSS Distributions T_ASSERT_GT(uuid_count, 0, "returned valid number of UUIDs from shared cache"); 2776*94d3b452SApple OSS Distributions verify_stackshot_sharedcache_layout(shared_cache_uuids, uuid_count); 2777*94d3b452SApple OSS Distributions found_shared_cache_layout = true; 2778*94d3b452SApple OSS Distributions } 2779*94d3b452SApple OSS Distributions 2780*94d3b452SApple OSS Distributions break; 2781*94d3b452SApple OSS Distributions } 2782*94d3b452SApple OSS Distributions 2783*94d3b452SApple OSS Distributions case KCDATA_TYPE_CONTAINER_BEGIN: { 2784*94d3b452SApple OSS Distributions T_QUIET; 2785*94d3b452SApple OSS Distributions T_ASSERT_TRUE(kcdata_iter_container_valid(iter), 2786*94d3b452SApple OSS Distributions "checked that container is valid"); 2787*94d3b452SApple OSS Distributions 2788*94d3b452SApple OSS Distributions uint64_t containerid = kcdata_iter_container_id(iter); 2789*94d3b452SApple OSS Distributions uint32_t container_type = kcdata_iter_container_type(iter); 2790*94d3b452SApple OSS Distributions 2791*94d3b452SApple OSS Distributions if (container_type == STACKSHOT_KCCONTAINER_SHAREDCACHE) { 2792*94d3b452SApple OSS Distributions NSDictionary *container = parseKCDataContainer(&iter, &error); 2793*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(container, "parsed sharedcache container from stackshot"); 2794*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NULL(error, "error unset after parsing sharedcache container"); 2795*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_EQ(sharedCaches[@(containerid)], nil, "sharedcache containerid %lld should be unique", containerid); 2796*94d3b452SApple OSS Distributions sharedCaches[@(containerid)] = container; 2797*94d3b452SApple OSS Distributions break; 2798*94d3b452SApple OSS Distributions } 2799*94d3b452SApple OSS Distributions 2800*94d3b452SApple OSS Distributions if (container_type == STACKSHOT_KCCONTAINER_EXCLAVES) { 2801*94d3b452SApple OSS Distributions break; 2802*94d3b452SApple OSS Distributions } 2803*94d3b452SApple OSS Distributions 2804*94d3b452SApple OSS Distributions /* 2805*94d3b452SApple OSS Distributions * treat containers other than tasks/transitioning_tasks 2806*94d3b452SApple OSS Distributions * as expanded in-line. 2807*94d3b452SApple OSS Distributions */ 2808*94d3b452SApple OSS Distributions if (container_type != STACKSHOT_KCCONTAINER_TASK && 2809*94d3b452SApple OSS Distributions container_type != STACKSHOT_KCCONTAINER_TRANSITIONING_TASK) { 2810*94d3b452SApple OSS Distributions T_LOG("container skipped: %d", container_type); 2811*94d3b452SApple OSS Distributions break; 2812*94d3b452SApple OSS Distributions } 2813*94d3b452SApple OSS Distributions NSDictionary *container = parseKCDataContainer(&iter, &error); 2814*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(container, "parsed task/transitioning_task container from stackshot"); 2815*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NULL(error, "error unset after parsing container"); 2816*94d3b452SApple OSS Distributions 2817*94d3b452SApple OSS Distributions NSDictionary* task_snapshot = container[@"task_snapshots"][@"task_snapshot"]; 2818*94d3b452SApple OSS Distributions NSDictionary* task_delta_snapshot = container[@"task_snapshots"][@"task_delta_snapshot"]; 2819*94d3b452SApple OSS Distributions NSDictionary* transitioning_task_snapshot = container[@"transitioning_task_snapshots"][@"transitioning_task_snapshot"]; 2820*94d3b452SApple OSS Distributions 2821*94d3b452SApple OSS Distributions /* 2822*94d3b452SApple OSS Distributions * Having processed the container, we now only check it 2823*94d3b452SApple OSS Distributions * if it's the correct type. 2824*94d3b452SApple OSS Distributions */ 2825*94d3b452SApple OSS Distributions if ((!expect_transitioning_task && (container_type != STACKSHOT_KCCONTAINER_TASK)) || 2826*94d3b452SApple OSS Distributions (expect_transitioning_task && (container_type != STACKSHOT_KCCONTAINER_TRANSITIONING_TASK))) { 2827*94d3b452SApple OSS Distributions break; 2828*94d3b452SApple OSS Distributions } 2829*94d3b452SApple OSS Distributions if (!expect_transitioning_task) { 2830*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(!!task_snapshot != !!task_delta_snapshot, "Either task_snapshot xor task_delta_snapshot provided"); 2831*94d3b452SApple OSS Distributions } 2832*94d3b452SApple OSS Distributions 2833*94d3b452SApple OSS Distributions if (expect_dispatch_queue_label && !found_dispatch_queue_label) { 2834*94d3b452SApple OSS Distributions for (id thread_key in container[@"task_snapshots"][@"thread_snapshots"]) { 2835*94d3b452SApple OSS Distributions NSMutableDictionary *thread = container[@"task_snapshots"][@"thread_snapshots"][thread_key]; 2836*94d3b452SApple OSS Distributions NSString *dql = thread[@"dispatch_queue_label"]; 2837*94d3b452SApple OSS Distributions 2838*94d3b452SApple OSS Distributions if ([dql isEqualToString:@TEST_STACKSHOT_QUEUE_LABEL]) { 2839*94d3b452SApple OSS Distributions found_dispatch_queue_label = true; 2840*94d3b452SApple OSS Distributions break; 2841*94d3b452SApple OSS Distributions } 2842*94d3b452SApple OSS Distributions } 2843*94d3b452SApple OSS Distributions } 2844*94d3b452SApple OSS Distributions 2845*94d3b452SApple OSS Distributions if (expect_transitioning_task && !found_transitioning_task) { 2846*94d3b452SApple OSS Distributions if (transitioning_task_snapshot) { 2847*94d3b452SApple OSS Distributions uint64_t the_pid = [transitioning_task_snapshot[@"tts_pid"] unsignedLongLongValue]; 2848*94d3b452SApple OSS Distributions if (the_pid == (uint64_t)transistioning_task_pid) { 2849*94d3b452SApple OSS Distributions found_transitioning_task = true; 2850*94d3b452SApple OSS Distributions T_PASS("FOUND Transitioning task %llu has a transitioning task snapshot", (uint64_t) transistioning_task_pid); 2851*94d3b452SApple OSS Distributions break; 2852*94d3b452SApple OSS Distributions } 2853*94d3b452SApple OSS Distributions } 2854*94d3b452SApple OSS Distributions } 2855*94d3b452SApple OSS Distributions 2856*94d3b452SApple OSS Distributions if (expect_postexec_child && !found_postexec_child) { 2857*94d3b452SApple OSS Distributions if (task_snapshot) { 2858*94d3b452SApple OSS Distributions uint64_t unique_pid = [task_snapshot[@"ts_unique_pid"] unsignedLongLongValue]; 2859*94d3b452SApple OSS Distributions if (unique_pid == postexec_child_unique_pid) { 2860*94d3b452SApple OSS Distributions found_postexec_child = true; 2861*94d3b452SApple OSS Distributions 2862*94d3b452SApple OSS Distributions T_PASS("post-exec child %llu has a task snapshot", postexec_child_unique_pid); 2863*94d3b452SApple OSS Distributions 2864*94d3b452SApple OSS Distributions break; 2865*94d3b452SApple OSS Distributions } 2866*94d3b452SApple OSS Distributions } 2867*94d3b452SApple OSS Distributions 2868*94d3b452SApple OSS Distributions if (task_delta_snapshot) { 2869*94d3b452SApple OSS Distributions uint64_t unique_pid = [task_delta_snapshot[@"tds_unique_pid"] unsignedLongLongValue]; 2870*94d3b452SApple OSS Distributions if (unique_pid == postexec_child_unique_pid) { 2871*94d3b452SApple OSS Distributions found_postexec_child = true; 2872*94d3b452SApple OSS Distributions 2873*94d3b452SApple OSS Distributions T_FAIL("post-exec child %llu shouldn't have a delta task snapshot", postexec_child_unique_pid); 2874*94d3b452SApple OSS Distributions 2875*94d3b452SApple OSS Distributions break; 2876*94d3b452SApple OSS Distributions } 2877*94d3b452SApple OSS Distributions } 2878*94d3b452SApple OSS Distributions } 2879*94d3b452SApple OSS Distributions 2880*94d3b452SApple OSS Distributions if (!task_snapshot) { 2881*94d3b452SApple OSS Distributions break; 2882*94d3b452SApple OSS Distributions } 2883*94d3b452SApple OSS Distributions 2884*94d3b452SApple OSS Distributions int pid = [task_snapshot[@"ts_pid"] intValue]; 2885*94d3b452SApple OSS Distributions 2886*94d3b452SApple OSS Distributions if (pid && expect_shared_cache_uuid && !found_shared_cache_uuid) { 2887*94d3b452SApple OSS Distributions id ptr = container[@"task_snapshots"][@"shared_cache_dyld_load_info"]; 2888*94d3b452SApple OSS Distributions if (ptr) { 2889*94d3b452SApple OSS Distributions id uuid = ptr[@"imageUUID"]; 2890*94d3b452SApple OSS Distributions 2891*94d3b452SApple OSS Distributions uint8_t uuid_p[16]; 2892*94d3b452SApple OSS Distributions for (unsigned int i = 0; i < 16; i ++) { 2893*94d3b452SApple OSS Distributions NSNumber *uuidByte = uuid[i]; 2894*94d3b452SApple OSS Distributions uuid_p[i] = (uint8_t)uuidByte.charValue; 2895*94d3b452SApple OSS Distributions } 2896*94d3b452SApple OSS Distributions 2897*94d3b452SApple OSS Distributions check_shared_cache_uuid(uuid_p); 2898*94d3b452SApple OSS Distributions 2899*94d3b452SApple OSS Distributions uint64_t baseAddress = (uint64_t)((NSNumber *)ptr[@"imageSlidBaseAddress"]).longLongValue; 2900*94d3b452SApple OSS Distributions uint64_t firstMapping = (uint64_t)((NSNumber *)ptr[@"sharedCacheSlidFirstMapping"]).longLongValue; 2901*94d3b452SApple OSS Distributions 2902*94d3b452SApple OSS Distributions T_EXPECT_LE(baseAddress, firstMapping, 2903*94d3b452SApple OSS Distributions "in per-task shared_cache_dyld_load_info, " 2904*94d3b452SApple OSS Distributions "baseAddress <= firstMapping"); 2905*94d3b452SApple OSS Distributions T_EXPECT_GE(baseAddress + (7ull << 32) + (1ull << 29), 2906*94d3b452SApple OSS Distributions firstMapping, 2907*94d3b452SApple OSS Distributions "in per-task shared_cache_dyld_load_info, " 2908*94d3b452SApple OSS Distributions "baseAddress + 28.5gig >= firstMapping"); 2909*94d3b452SApple OSS Distributions 2910*94d3b452SApple OSS Distributions size_t shared_cache_len; 2911*94d3b452SApple OSS Distributions const void *addr = _dyld_get_shared_cache_range(&shared_cache_len); 2912*94d3b452SApple OSS Distributions T_EXPECT_EQ((uint64_t)addr, firstMapping, 2913*94d3b452SApple OSS Distributions "SlidFirstMapping should match shared_cache_range"); 2914*94d3b452SApple OSS Distributions 2915*94d3b452SApple OSS Distributions /* 2916*94d3b452SApple OSS Distributions * check_shared_cache_uuid() will assert on failure, so if 2917*94d3b452SApple OSS Distributions * we get here, then we have found the shared cache UUID 2918*94d3b452SApple OSS Distributions * and it's correct 2919*94d3b452SApple OSS Distributions */ 2920*94d3b452SApple OSS Distributions found_shared_cache_uuid = true; 2921*94d3b452SApple OSS Distributions } 2922*94d3b452SApple OSS Distributions } 2923*94d3b452SApple OSS Distributions 2924*94d3b452SApple OSS Distributions if (expect_sharedcache_child) { 2925*94d3b452SApple OSS Distributions uint64_t task_flags = [task_snapshot[@"ts_ss_flags"] unsignedLongLongValue]; 2926*94d3b452SApple OSS Distributions uint64_t sharedregion_flags = (task_flags & (kTaskSharedRegionNone | kTaskSharedRegionSystem | kTaskSharedRegionOther)); 2927*94d3b452SApple OSS Distributions id sharedregion_info = container[@"task_snapshots"][@"shared_cache_dyld_load_info"]; 2928*94d3b452SApple OSS Distributions id sharedcache_id = container[@"task_snapshots"][@"sharedCacheID"]; 2929*94d3b452SApple OSS Distributions if (!found_sharedcache_badflags) { 2930*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_NE(sharedregion_flags, 0ll, "one of the kTaskSharedRegion flags should be set on all tasks"); 2931*94d3b452SApple OSS Distributions bool multiple = (sharedregion_flags & (sharedregion_flags - 1)) != 0; 2932*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_FALSE(multiple, "only one kTaskSharedRegion flag should be set on each task"); 2933*94d3b452SApple OSS Distributions found_sharedcache_badflags = (sharedregion_flags == 0 || multiple); 2934*94d3b452SApple OSS Distributions } 2935*94d3b452SApple OSS Distributions if (pid == 0) { 2936*94d3b452SApple OSS Distributions T_ASSERT_EQ(sharedregion_flags, (uint64_t)kTaskSharedRegionNone, "Kernel proc (pid 0) should have no shared region"); 2937*94d3b452SApple OSS Distributions } else if (pid == sharedcache_child_pid) { 2938*94d3b452SApple OSS Distributions found_sharedcache_child = true; 2939*94d3b452SApple OSS Distributions sharedcache_child_flags = sharedregion_flags; 2940*94d3b452SApple OSS Distributions } else if (pid == getpid()) { 2941*94d3b452SApple OSS Distributions found_sharedcache_self = true; 2942*94d3b452SApple OSS Distributions sharedcache_self_flags = sharedregion_flags; 2943*94d3b452SApple OSS Distributions } 2944*94d3b452SApple OSS Distributions if (sharedregion_flags == kTaskSharedRegionOther && !(task_flags & kTaskSharedRegionInfoUnavailable)) { 2945*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_NOTNULL(sharedregion_info, "kTaskSharedRegionOther should have a shared_cache_dyld_load_info struct"); 2946*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_NOTNULL(sharedcache_id, "kTaskSharedRegionOther should have a sharedCacheID"); 2947*94d3b452SApple OSS Distributions if (sharedcache_id != nil) { 2948*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_NOTNULL(sharedCaches[sharedcache_id], "sharedCacheID %d should exist", [sharedcache_id intValue]); 2949*94d3b452SApple OSS Distributions } 2950*94d3b452SApple OSS Distributions } else { 2951*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_NULL(sharedregion_info, "non-kTaskSharedRegionOther should have no shared_cache_dyld_load_info struct"); 2952*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_NULL(sharedcache_id, "non-kTaskSharedRegionOther should have no sharedCacheID"); 2953*94d3b452SApple OSS Distributions } 2954*94d3b452SApple OSS Distributions } 2955*94d3b452SApple OSS Distributions 2956*94d3b452SApple OSS Distributions if (expect_zombie_child && (pid == zombie_child_pid)) { 2957*94d3b452SApple OSS Distributions found_zombie_child = true; 2958*94d3b452SApple OSS Distributions 2959*94d3b452SApple OSS Distributions uint64_t task_flags = [task_snapshot[@"ts_ss_flags"] unsignedLongLongValue]; 2960*94d3b452SApple OSS Distributions T_ASSERT_TRUE((task_flags & kTerminatedSnapshot) == kTerminatedSnapshot, "child zombie marked as terminated"); 2961*94d3b452SApple OSS Distributions 2962*94d3b452SApple OSS Distributions continue; 2963*94d3b452SApple OSS Distributions } 2964*94d3b452SApple OSS Distributions 2965*94d3b452SApple OSS Distributions if (expect_translated_child && (pid == translated_child_pid)) { 2966*94d3b452SApple OSS Distributions found_translated_child = true; 2967*94d3b452SApple OSS Distributions 2968*94d3b452SApple OSS Distributions uint64_t task_flags = [task_snapshot[@"ts_ss_flags"] unsignedLongLongValue]; 2969*94d3b452SApple OSS Distributions T_EXPECT_BITS_SET(task_flags, kTaskIsTranslated, "child marked as translated"); 2970*94d3b452SApple OSS Distributions 2971*94d3b452SApple OSS Distributions continue; 2972*94d3b452SApple OSS Distributions } 2973*94d3b452SApple OSS Distributions if (expect_exec_inprogress && (pid == exec_inprogress_pid || pid == -exec_inprogress_pid)) { 2974*94d3b452SApple OSS Distributions exec_inprogress_found++; 2975*94d3b452SApple OSS Distributions T_LOG("found exec task with pid %d, instance %d", pid, exec_inprogress_found); 2976*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_LE(exec_inprogress_found, 2, "no more than two with the expected pid"); 2977*94d3b452SApple OSS Distributions if (exec_inprogress_found == 2) { 2978*94d3b452SApple OSS Distributions T_LOG("found 2 tasks with pid %d", exec_inprogress_pid); 2979*94d3b452SApple OSS Distributions exec_inprogress_cb(containerid, exec_inprogress_containerid); 2980*94d3b452SApple OSS Distributions } else { 2981*94d3b452SApple OSS Distributions exec_inprogress_containerid = containerid; 2982*94d3b452SApple OSS Distributions } 2983*94d3b452SApple OSS Distributions } 2984*94d3b452SApple OSS Distributions if (expect_driverkit && driverkit_cb != NULL) { 2985*94d3b452SApple OSS Distributions driverkit_cb(pid); 2986*94d3b452SApple OSS Distributions } 2987*94d3b452SApple OSS Distributions if (expect_cseg_waitinfo) { 2988*94d3b452SApple OSS Distributions NSArray *winfos = container[@"task_snapshots"][@"thread_waitinfo"]; 2989*94d3b452SApple OSS Distributions 2990*94d3b452SApple OSS Distributions for (id i in winfos) { 2991*94d3b452SApple OSS Distributions NSNumber *waitType = i[@"wait_type"]; 2992*94d3b452SApple OSS Distributions NSNumber *owner = i[@"owner"]; 2993*94d3b452SApple OSS Distributions if (waitType.intValue == kThreadWaitCompressor && 2994*94d3b452SApple OSS Distributions owner.unsignedLongValue == cseg_expected_threadid) { 2995*94d3b452SApple OSS Distributions found_cseg_waitinfo = true; 2996*94d3b452SApple OSS Distributions break; 2997*94d3b452SApple OSS Distributions } 2998*94d3b452SApple OSS Distributions } 2999*94d3b452SApple OSS Distributions } 3000*94d3b452SApple OSS Distributions 3001*94d3b452SApple OSS Distributions if (expect_srp_waitinfo) { 3002*94d3b452SApple OSS Distributions NSArray *tinfos = container[@"task_snapshots"][@"thread_turnstileinfo"]; 3003*94d3b452SApple OSS Distributions NSArray *winfos = container[@"task_snapshots"][@"thread_waitinfo"]; 3004*94d3b452SApple OSS Distributions for (id i in tinfos) { 3005*94d3b452SApple OSS Distributions if (!found_srp_waitinfo) { 3006*94d3b452SApple OSS Distributions bool found_thread = false; 3007*94d3b452SApple OSS Distributions bool found_pid = false; 3008*94d3b452SApple OSS Distributions if (([i[@"turnstile_flags"] intValue] & STACKSHOT_TURNSTILE_STATUS_THREAD) && 3009*94d3b452SApple OSS Distributions [i[@"turnstile_context"] unsignedLongLongValue] == srp_expected_threadid && 3010*94d3b452SApple OSS Distributions srp_expected_threadid != 0) { 3011*94d3b452SApple OSS Distributions found_thread = true; 3012*94d3b452SApple OSS Distributions } 3013*94d3b452SApple OSS Distributions if (([i[@"turnstile_flags"] intValue] & STACKSHOT_TURNSTILE_STATUS_BLOCKED_ON_TASK) && 3014*94d3b452SApple OSS Distributions [i[@"turnstile_context"] intValue] == srp_expected_pid && 3015*94d3b452SApple OSS Distributions srp_expected_pid != -1) { 3016*94d3b452SApple OSS Distributions found_pid = true; 3017*94d3b452SApple OSS Distributions } 3018*94d3b452SApple OSS Distributions if (found_pid || found_thread) { 3019*94d3b452SApple OSS Distributions T_LOG("found SRP %s %lld waiter: %d", (found_thread ? "thread" : "pid"), 3020*94d3b452SApple OSS Distributions [i[@"turnstile_context"] unsignedLongLongValue], [i[@"waiter"] intValue]); 3021*94d3b452SApple OSS Distributions /* we found something that is blocking the correct threadid */ 3022*94d3b452SApple OSS Distributions for (id j in winfos) { 3023*94d3b452SApple OSS Distributions if ([j[@"waiter"] intValue] == [i[@"waiter"] intValue] && 3024*94d3b452SApple OSS Distributions [j[@"wait_type"] intValue] == kThreadWaitPortReceive) { 3025*94d3b452SApple OSS Distributions found_srp_waitinfo = true; 3026*94d3b452SApple OSS Distributions T_EXPECT_EQ([j[@"wait_flags"] intValue], STACKSHOT_WAITINFO_FLAGS_SPECIALREPLY, 3027*94d3b452SApple OSS Distributions "SRP waitinfo should be marked as a special reply"); 3028*94d3b452SApple OSS Distributions break; 3029*94d3b452SApple OSS Distributions } 3030*94d3b452SApple OSS Distributions } 3031*94d3b452SApple OSS Distributions 3032*94d3b452SApple OSS Distributions if (found_srp_waitinfo) { 3033*94d3b452SApple OSS Distributions break; 3034*94d3b452SApple OSS Distributions } 3035*94d3b452SApple OSS Distributions } 3036*94d3b452SApple OSS Distributions } 3037*94d3b452SApple OSS Distributions } 3038*94d3b452SApple OSS Distributions } 3039*94d3b452SApple OSS Distributions 3040*94d3b452SApple OSS Distributions if (expect_sp_throttled) { 3041*94d3b452SApple OSS Distributions NSArray *tinfos = container[@"task_snapshots"][@"thread_turnstileinfo"]; 3042*94d3b452SApple OSS Distributions for (id i in tinfos) { 3043*94d3b452SApple OSS Distributions if (([i[@"turnstile_flags"] intValue] & STACKSHOT_TURNSTILE_STATUS_PORTFLAGS) 3044*94d3b452SApple OSS Distributions && [i[@"turnstile_context"] intValue] == throttled_service_ctx) { 3045*94d3b452SApple OSS Distributions int portlabel_id = [i[@"portlabel_id"] intValue]; 3046*94d3b452SApple OSS Distributions T_LOG("[pid:%d] Turnstile (flags = 0x%x, ctx = %d, portlabel_id = %d)", pid, 3047*94d3b452SApple OSS Distributions [i[@"turnstile_flags"] intValue], [i[@"turnstile_context"] intValue], portlabel_id); 3048*94d3b452SApple OSS Distributions for (id portid in container[@"task_snapshots"][@"portlabels"]) { 3049*94d3b452SApple OSS Distributions if (portlabel_id != [portid intValue]) { 3050*94d3b452SApple OSS Distributions continue; 3051*94d3b452SApple OSS Distributions } 3052*94d3b452SApple OSS Distributions 3053*94d3b452SApple OSS Distributions NSMutableDictionary *portlabel = container[@"task_snapshots"][@"portlabels"][portid]; 3054*94d3b452SApple OSS Distributions T_ASSERT_TRUE(portlabel != nil, "Found portlabel id: %d", [portid intValue]); 3055*94d3b452SApple OSS Distributions NSString *portlabel_name = portlabel[@"portlabel_name"]; 3056*94d3b452SApple OSS Distributions T_EXPECT_TRUE(portlabel_name != nil, "Found portlabel %s", portlabel_name.UTF8String); 3057*94d3b452SApple OSS Distributions T_EXPECT_EQ_STR(portlabel_name.UTF8String, THROTTLED_SERVICE_NAME, "throttled service port name matches"); 3058*94d3b452SApple OSS Distributions T_EXPECT_EQ(([portlabel[@"portlabel_flags"] intValue] & STACKSHOT_PORTLABEL_THROTTLED) != 0, 3059*94d3b452SApple OSS Distributions is_throttled, "Port %s throttled", is_throttled ? "is" : "isn't"); 3060*94d3b452SApple OSS Distributions found_throttled_service = true; 3061*94d3b452SApple OSS Distributions break; 3062*94d3b452SApple OSS Distributions } 3063*94d3b452SApple OSS Distributions } 3064*94d3b452SApple OSS Distributions 3065*94d3b452SApple OSS Distributions if (found_throttled_service) { 3066*94d3b452SApple OSS Distributions break; 3067*94d3b452SApple OSS Distributions } 3068*94d3b452SApple OSS Distributions } 3069*94d3b452SApple OSS Distributions } 3070*94d3b452SApple OSS Distributions 3071*94d3b452SApple OSS Distributions if (expect_suspendinfo) { 3072*94d3b452SApple OSS Distributions // TODO: rdar://112563110 3073*94d3b452SApple OSS Distributions } 3074*94d3b452SApple OSS Distributions 3075*94d3b452SApple OSS Distributions if (pid != getpid()) { 3076*94d3b452SApple OSS Distributions break; 3077*94d3b452SApple OSS Distributions } 3078*94d3b452SApple OSS Distributions 3079*94d3b452SApple OSS Distributions T_EXPECT_EQ_STR(current_process_name(), 3080*94d3b452SApple OSS Distributions [task_snapshot[@"ts_p_comm"] UTF8String], 3081*94d3b452SApple OSS Distributions "current process name matches in stackshot"); 3082*94d3b452SApple OSS Distributions 3083*94d3b452SApple OSS Distributions uint64_t task_flags = [task_snapshot[@"ts_ss_flags"] unsignedLongLongValue]; 3084*94d3b452SApple OSS Distributions T_ASSERT_BITS_NOTSET(task_flags, kTerminatedSnapshot, "current process not marked as terminated"); 3085*94d3b452SApple OSS Distributions T_ASSERT_BITS_NOTSET(task_flags, kTaskIsTranslated, "current process not marked as translated"); 3086*94d3b452SApple OSS Distributions 3087*94d3b452SApple OSS Distributions T_QUIET; 3088*94d3b452SApple OSS Distributions T_EXPECT_LE(pid, [task_snapshot[@"ts_unique_pid"] intValue], 3089*94d3b452SApple OSS Distributions "unique pid is greater than pid"); 3090*94d3b452SApple OSS Distributions 3091*94d3b452SApple OSS Distributions NSDictionary* task_cpu_architecture = container[@"task_snapshots"][@"task_cpu_architecture"]; 3092*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(task_cpu_architecture[@"cputype"], "have cputype"); 3093*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(task_cpu_architecture[@"cpusubtype"], "have cputype"); 3094*94d3b452SApple OSS Distributions int cputype = [task_cpu_architecture[@"cputype"] intValue]; 3095*94d3b452SApple OSS Distributions int cpusubtype = [task_cpu_architecture[@"cpusubtype"] intValue]; 3096*94d3b452SApple OSS Distributions 3097*94d3b452SApple OSS Distributions struct proc_archinfo archinfo; 3098*94d3b452SApple OSS Distributions int retval = proc_pidinfo(pid, PROC_PIDARCHINFO, 0, &archinfo, sizeof(archinfo)); 3099*94d3b452SApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_GT(retval, 0, "proc_pidinfo(PROC_PIDARCHINFO) returned a value > 0"); 3100*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(retval, (int)sizeof(struct proc_archinfo), "proc_pidinfo call for PROC_PIDARCHINFO returned expected size"); 3101*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_EQ(cputype, archinfo.p_cputype, "cpu type is correct"); 3102*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_EQ(cpusubtype, archinfo.p_cpusubtype, "cpu subtype is correct"); 3103*94d3b452SApple OSS Distributions 3104*94d3b452SApple OSS Distributions NSDictionary * codesigning_info = container[@"task_snapshots"][@"stackshot_task_codesigning_info"]; 3105*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(codesigning_info[@"csflags"], "have csflags"); 3106*94d3b452SApple OSS Distributions uint64_t flags = [codesigning_info[@"csflags"] unsignedLongLongValue]; 3107*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_GT(flags, 0, "nonzero csflags"); 3108*94d3b452SApple OSS Distributions 3109*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(container[@"task_snapshots"][@"jetsam_coalition"], "have jetsam coalition"); 3110*94d3b452SApple OSS Distributions uint64_t jetsam_coalition = [container[@"task_snapshots"][@"jetsam_coalition"] unsignedLongLongValue]; 3111*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_GT(jetsam_coalition, 0, "nonzero jetsam coalition"); 3112*94d3b452SApple OSS Distributions 3113*94d3b452SApple OSS Distributions bool found_main_thread = false; 3114*94d3b452SApple OSS Distributions uint64_t main_thread_id = -1ULL; 3115*94d3b452SApple OSS Distributions bool found_null_kernel_frame = false; 3116*94d3b452SApple OSS Distributions for (id thread_key in container[@"task_snapshots"][@"thread_snapshots"]) { 3117*94d3b452SApple OSS Distributions NSMutableDictionary *thread = container[@"task_snapshots"][@"thread_snapshots"][thread_key]; 3118*94d3b452SApple OSS Distributions NSDictionary *thread_snap = thread[@"thread_snapshot"]; 3119*94d3b452SApple OSS Distributions 3120*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_GT([thread_snap[@"ths_thread_id"] intValue], 0, 3121*94d3b452SApple OSS Distributions "thread ID of thread in current task is valid"); 3122*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_GT([thread_snap[@"ths_base_priority"] intValue], 0, 3123*94d3b452SApple OSS Distributions "base priority of thread in current task is valid"); 3124*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_GT([thread_snap[@"ths_sched_priority"] intValue], 0, 3125*94d3b452SApple OSS Distributions "scheduling priority of thread in current task is valid"); 3126*94d3b452SApple OSS Distributions 3127*94d3b452SApple OSS Distributions NSString *pth_name = thread[@"pth_name"]; 3128*94d3b452SApple OSS Distributions if (pth_name != nil && [pth_name isEqualToString:@TEST_THREAD_NAME]) { 3129*94d3b452SApple OSS Distributions found_main_thread = true; 3130*94d3b452SApple OSS Distributions main_thread_id = [thread_snap[@"ths_thread_id"] unsignedLongLongValue]; 3131*94d3b452SApple OSS Distributions 3132*94d3b452SApple OSS Distributions T_QUIET; T_EXPECT_GT([thread_snap[@"ths_total_syscalls"] intValue], 0, 3133*94d3b452SApple OSS Distributions "total syscalls of current thread is valid"); 3134*94d3b452SApple OSS Distributions 3135*94d3b452SApple OSS Distributions NSDictionary *cpu_times = thread[@"cpu_times"]; 3136*94d3b452SApple OSS Distributions T_EXPECT_GE([cpu_times[@"runnable_time"] intValue], 3137*94d3b452SApple OSS Distributions [cpu_times[@"system_time"] intValue] + 3138*94d3b452SApple OSS Distributions [cpu_times[@"user_time"] intValue], 3139*94d3b452SApple OSS Distributions "runnable time of current thread is valid"); 3140*94d3b452SApple OSS Distributions } 3141*94d3b452SApple OSS Distributions if (!found_null_kernel_frame) { 3142*94d3b452SApple OSS Distributions for (NSNumber *frame in thread[@"kernel_frames"]) { 3143*94d3b452SApple OSS Distributions if (frame.unsignedLongValue == 0) { 3144*94d3b452SApple OSS Distributions found_null_kernel_frame = true; 3145*94d3b452SApple OSS Distributions break; 3146*94d3b452SApple OSS Distributions } 3147*94d3b452SApple OSS Distributions } 3148*94d3b452SApple OSS Distributions } 3149*94d3b452SApple OSS Distributions if (expect_asyncstack && !found_asyncstack && 3150*94d3b452SApple OSS Distributions asyncstack_threadid == [thread_snap[@"ths_thread_id"] unsignedLongLongValue]) { 3151*94d3b452SApple OSS Distributions found_asyncstack = true; 3152*94d3b452SApple OSS Distributions NSArray* async_stack = thread[@"user_async_stack_frames"]; 3153*94d3b452SApple OSS Distributions NSNumber* start_idx = thread[@"user_async_start_index"]; 3154*94d3b452SApple OSS Distributions NSArray* user_stack = thread[@"user_stack_frames"]; 3155*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(async_stack, "async thread %#llx has user_async_stack_frames", asyncstack_threadid); 3156*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(start_idx, "async thread %#llx has user_async_start_index", asyncstack_threadid); 3157*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(user_stack, "async thread %#llx has user_stack_frames", asyncstack_threadid); 3158*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_EQ(async_stack.count, asyncstack_stack.count, 3159*94d3b452SApple OSS Distributions "actual async_stack count == expected async_stack count"); 3160*94d3b452SApple OSS Distributions for (size_t i = 0; i < async_stack.count; i++) { 3161*94d3b452SApple OSS Distributions T_EXPECT_EQ([async_stack[i][@"lr"] unsignedLongLongValue], 3162*94d3b452SApple OSS Distributions [asyncstack_stack[i] unsignedLongLongValue], "frame %zu matches", i); 3163*94d3b452SApple OSS Distributions } 3164*94d3b452SApple OSS Distributions } 3165*94d3b452SApple OSS Distributions 3166*94d3b452SApple OSS Distributions } 3167*94d3b452SApple OSS Distributions T_EXPECT_TRUE(found_main_thread, "found main thread for current task in stackshot"); 3168*94d3b452SApple OSS Distributions T_EXPECT_FALSE(found_null_kernel_frame, "should not see any NULL kernel frames"); 3169*94d3b452SApple OSS Distributions 3170*94d3b452SApple OSS Distributions if (expect_turnstile_lock && !found_turnstile_lock) { 3171*94d3b452SApple OSS Distributions NSArray *tsinfos = container[@"task_snapshots"][@"thread_turnstileinfo"]; 3172*94d3b452SApple OSS Distributions 3173*94d3b452SApple OSS Distributions for (id i in tsinfos) { 3174*94d3b452SApple OSS Distributions if ([i[@"turnstile_context"] unsignedLongLongValue] == main_thread_id) { 3175*94d3b452SApple OSS Distributions found_turnstile_lock = true; 3176*94d3b452SApple OSS Distributions break; 3177*94d3b452SApple OSS Distributions } 3178*94d3b452SApple OSS Distributions } 3179*94d3b452SApple OSS Distributions } 3180*94d3b452SApple OSS Distributions break; 3181*94d3b452SApple OSS Distributions } 3182*94d3b452SApple OSS Distributions case STACKSHOT_KCTYPE_SHAREDCACHE_LOADINFO: { 3183*94d3b452SApple OSS Distributions // Legacy shared cache info 3184*94d3b452SApple OSS Distributions struct dyld_shared_cache_loadinfo *payload = kcdata_iter_payload(iter); 3185*94d3b452SApple OSS Distributions T_ASSERT_EQ((size_t)kcdata_iter_size(iter), sizeof(*payload), "valid dyld_shared_cache_loadinfo struct"); 3186*94d3b452SApple OSS Distributions 3187*94d3b452SApple OSS Distributions check_shared_cache_uuid(payload->sharedCacheUUID); 3188*94d3b452SApple OSS Distributions 3189*94d3b452SApple OSS Distributions T_EXPECT_LE(payload->sharedCacheUnreliableSlidBaseAddress, 3190*94d3b452SApple OSS Distributions payload->sharedCacheSlidFirstMapping, 3191*94d3b452SApple OSS Distributions "SlidBaseAddress <= SlidFirstMapping"); 3192*94d3b452SApple OSS Distributions T_EXPECT_GE(payload->sharedCacheUnreliableSlidBaseAddress + (7ull << 32) + (1ull << 29), 3193*94d3b452SApple OSS Distributions payload->sharedCacheSlidFirstMapping, 3194*94d3b452SApple OSS Distributions "SlidFirstMapping should be within 28.5gigs of SlidBaseAddress"); 3195*94d3b452SApple OSS Distributions 3196*94d3b452SApple OSS Distributions size_t shared_cache_len; 3197*94d3b452SApple OSS Distributions const void *addr = _dyld_get_shared_cache_range(&shared_cache_len); 3198*94d3b452SApple OSS Distributions T_EXPECT_EQ((uint64_t)addr, payload->sharedCacheSlidFirstMapping, 3199*94d3b452SApple OSS Distributions "SlidFirstMapping should match shared_cache_range"); 3200*94d3b452SApple OSS Distributions 3201*94d3b452SApple OSS Distributions /* 3202*94d3b452SApple OSS Distributions * check_shared_cache_uuid() asserts on failure, so we must have 3203*94d3b452SApple OSS Distributions * found the shared cache UUID to be correct. 3204*94d3b452SApple OSS Distributions */ 3205*94d3b452SApple OSS Distributions found_shared_cache_uuid = true; 3206*94d3b452SApple OSS Distributions break; 3207*94d3b452SApple OSS Distributions } 3208*94d3b452SApple OSS Distributions } 3209*94d3b452SApple OSS Distributions } 3210*94d3b452SApple OSS Distributions 3211*94d3b452SApple OSS Distributions if (expect_sharedcache_child) { 3212*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(found_sharedcache_child, "found sharedcache child in kcdata"); 3213*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(found_sharedcache_self, "found self in kcdata"); 3214*94d3b452SApple OSS Distributions if (found_sharedcache_child && found_sharedcache_self) { 3215*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NE(sharedcache_child_flags, (uint64_t)kTaskSharedRegionNone, "sharedcache child should have shared region"); 3216*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_NE(sharedcache_self_flags, (uint64_t)kTaskSharedRegionNone, "sharedcache: self should have shared region"); 3217*94d3b452SApple OSS Distributions if (sharedcache_self_flags == kTaskSharedRegionSystem && !sharedcache_child_sameaddr) { 3218*94d3b452SApple OSS Distributions /* If we're in the system shared region, and the child has a different address, child must have an Other shared region */ 3219*94d3b452SApple OSS Distributions T_ASSERT_EQ(sharedcache_child_flags, (uint64_t)kTaskSharedRegionOther, 3220*94d3b452SApple OSS Distributions "sharedcache child should have Other shared region"); 3221*94d3b452SApple OSS Distributions } 3222*94d3b452SApple OSS Distributions } 3223*94d3b452SApple OSS Distributions } 3224*94d3b452SApple OSS Distributions 3225*94d3b452SApple OSS Distributions if (expect_transitioning_task) { 3226*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(found_transitioning_task, "found transitioning_task child in kcdata"); 3227*94d3b452SApple OSS Distributions } 3228*94d3b452SApple OSS Distributions 3229*94d3b452SApple OSS Distributions if (expect_exec_inprogress) { 3230*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_GT(exec_inprogress_found, 0, "found at least 1 task for execing process"); 3231*94d3b452SApple OSS Distributions } 3232*94d3b452SApple OSS Distributions 3233*94d3b452SApple OSS Distributions if (expect_zombie_child) { 3234*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(found_zombie_child, "found zombie child in kcdata"); 3235*94d3b452SApple OSS Distributions } 3236*94d3b452SApple OSS Distributions 3237*94d3b452SApple OSS Distributions if (expect_postexec_child) { 3238*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(found_postexec_child, "found post-exec child in kcdata"); 3239*94d3b452SApple OSS Distributions } 3240*94d3b452SApple OSS Distributions 3241*94d3b452SApple OSS Distributions if (expect_translated_child) { 3242*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(found_translated_child, "found translated child in kcdata"); 3243*94d3b452SApple OSS Distributions } 3244*94d3b452SApple OSS Distributions 3245*94d3b452SApple OSS Distributions if (expect_shared_cache_layout) { 3246*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(found_shared_cache_layout, "shared cache layout found in kcdata"); 3247*94d3b452SApple OSS Distributions } 3248*94d3b452SApple OSS Distributions 3249*94d3b452SApple OSS Distributions if (expect_shared_cache_uuid) { 3250*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(found_shared_cache_uuid, "shared cache UUID found in kcdata"); 3251*94d3b452SApple OSS Distributions } 3252*94d3b452SApple OSS Distributions 3253*94d3b452SApple OSS Distributions if (expect_dispatch_queue_label) { 3254*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(found_dispatch_queue_label, "dispatch queue label found in kcdata"); 3255*94d3b452SApple OSS Distributions } 3256*94d3b452SApple OSS Distributions 3257*94d3b452SApple OSS Distributions if (expect_turnstile_lock) { 3258*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(found_turnstile_lock, "found expected deadlock"); 3259*94d3b452SApple OSS Distributions } 3260*94d3b452SApple OSS Distributions 3261*94d3b452SApple OSS Distributions if (expect_cseg_waitinfo) { 3262*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(found_cseg_waitinfo, "found c_seg waitinfo"); 3263*94d3b452SApple OSS Distributions } 3264*94d3b452SApple OSS Distributions 3265*94d3b452SApple OSS Distributions if (expect_srp_waitinfo) { 3266*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(found_srp_waitinfo, "found special reply port waitinfo"); 3267*94d3b452SApple OSS Distributions } 3268*94d3b452SApple OSS Distributions 3269*94d3b452SApple OSS Distributions if (expect_sp_throttled) { 3270*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(found_throttled_service, "found the throttled service"); 3271*94d3b452SApple OSS Distributions } 3272*94d3b452SApple OSS Distributions 3273*94d3b452SApple OSS Distributions if (expect_asyncstack) { 3274*94d3b452SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(found_asyncstack, "found async stack threadid"); 3275*94d3b452SApple OSS Distributions } 3276*94d3b452SApple OSS Distributions 3277*94d3b452SApple OSS Distributions 3278*94d3b452SApple OSS Distributions T_ASSERT_FALSE(KCDATA_ITER_FOREACH_FAILED(iter), "successfully iterated kcdata"); 3279*94d3b452SApple OSS Distributions 3280*94d3b452SApple OSS Distributions free(inflatedBufferBase); 3281*94d3b452SApple OSS Distributions} 3282*94d3b452SApple OSS Distributions 3283*94d3b452SApple OSS Distributionsstatic const char * 3284*94d3b452SApple OSS Distributionscurrent_process_name(void) 3285*94d3b452SApple OSS Distributions{ 3286*94d3b452SApple OSS Distributions static char name[64]; 3287*94d3b452SApple OSS Distributions 3288*94d3b452SApple OSS Distributions if (!name[0]) { 3289*94d3b452SApple OSS Distributions int ret = proc_name(getpid(), name, sizeof(name)); 3290*94d3b452SApple OSS Distributions T_QUIET; 3291*94d3b452SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "proc_name failed for current process"); 3292*94d3b452SApple OSS Distributions } 3293*94d3b452SApple OSS Distributions 3294*94d3b452SApple OSS Distributions return name; 3295*94d3b452SApple OSS Distributions} 3296*94d3b452SApple OSS Distributions 3297*94d3b452SApple OSS Distributionsstatic void 3298*94d3b452SApple OSS Distributionsinitialize_thread(void) 3299*94d3b452SApple OSS Distributions{ 3300*94d3b452SApple OSS Distributions int ret = pthread_setname_np(TEST_THREAD_NAME); 3301*94d3b452SApple OSS Distributions T_QUIET; 3302*94d3b452SApple OSS Distributions T_ASSERT_POSIX_ZERO(ret, "set thread name to %s", TEST_THREAD_NAME); 3303*94d3b452SApple OSS Distributions} 3304