From 5fd83771641d15c418f747bd343ba6738d3875f7 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Sun, 9 May 2021 14:20:58 -0400 Subject: Import macOS userland adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106 --- system_cmds/stackshot.tproj/stackshot.c | 248 ++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 system_cmds/stackshot.tproj/stackshot.c (limited to 'system_cmds/stackshot.tproj') diff --git a/system_cmds/stackshot.tproj/stackshot.c b/system_cmds/stackshot.tproj/stackshot.c new file mode 100644 index 0000000..ecb3687 --- /dev/null +++ b/system_cmds/stackshot.tproj/stackshot.c @@ -0,0 +1,248 @@ +/* Copyright (c) 2017 Apple Inc. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static uint64_t +stackshot_get_mach_absolute_time(void *buffer, uint32_t size) +{ + kcdata_iter_t iter = kcdata_iter_find_type(kcdata_iter(buffer, size), KCDATA_TYPE_MACH_ABSOLUTE_TIME); + if (!kcdata_iter_valid(iter) || kcdata_iter_size(iter) < sizeof(uint64_t)) { + fprintf(stderr, "bad kcdata\n"); + exit(1); + } + return *(uint64_t *)kcdata_iter_payload(iter); +} + +__dead2 static void usage(char **argv) +{ + fprintf (stderr, "usage: %s [options] [file]\n", argv[0]); + fprintf (stderr, " -d : take delta stackshot\n"); + fprintf (stderr, " -b : get bootprofile\n"); + fprintf (stderr, " -c : get coalition data\n"); + fprintf (stderr, " -i : get instructions and cycles\n"); + fprintf (stderr, " -g : get thread group data\n"); + fprintf (stderr, " -s : fork a sleep process\n"); + fprintf (stderr, " -L : disable loadinfo\n"); + fprintf (stderr, " -k : active kernel threads only\n"); + fprintf (stderr, " -I : disable io statistics\n"); + fprintf (stderr, " -S : stress test: while(1) stackshot; \n"); + fprintf (stderr, " -p PID : target a pid\n"); + fprintf (stderr, " -E : grab existing kernel buffer\n"); + fprintf (stderr, "If no file is provided and stdout is not a TTY, the stackshot will be written to stdout.\n"); + exit(1); +} + +static void forksleep() { + pid_t pid = fork(); + if (pid < 0) { + perror("fork"); + exit(1); + } + + if (pid == 0) { + execlp("sleep", "sleep", "30", NULL); + perror("execlp"); + exit(1); + } +} + + +int main(int argc, char **argv) { + + uint32_t iostats = 0; + uint32_t active_kernel_threads_only = 0; + uint32_t bootprofile = 0; + uint32_t thread_group = 0; + uint32_t coalition = 0; + uint32_t instrs_cycles = 0; + uint32_t flags = 0; + uint32_t loadinfo = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO; + boolean_t delta = FALSE; + boolean_t sleep = FALSE; + boolean_t stress = FALSE; + pid_t pid = -1; + int c; + FILE *file; + bool closefile; + + while ((c = getopt(argc, argv, "SgIikbcLdtsp:E")) != -1) { + switch(c) { + case 'I': + iostats |= STACKSHOT_NO_IO_STATS; + break; + case 'k': + active_kernel_threads_only |= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY; + loadinfo &= ~STACKSHOT_SAVE_LOADINFO; + break; + case 'b': + bootprofile |= STACKSHOT_GET_BOOT_PROFILE; + break; + case 'c': + coalition |= STACKSHOT_SAVE_JETSAM_COALITIONS; + break; + case 'i': + instrs_cycles |= STACKSHOT_INSTRS_CYCLES; + break; + case 'L': + loadinfo = 0; + break; + case 'g': + thread_group |= STACKSHOT_THREAD_GROUP; + break; + case 'd': + delta = TRUE; + break; + case 's': + sleep = TRUE; + break; + case 'p': + pid = atoi(optarg); + break; + case 'S': + stress = TRUE; + break; + case 'E': + flags = flags | STACKSHOT_RETRIEVE_EXISTING_BUFFER; + break; + case '?': + case 'h': + default: + usage(argv); + break; + } + } + + if (thread_group && delta) { + fprintf(stderr, "stackshot does not support delta snapshots with thread groups\n"); + return 1; + } + + if (optind == argc - 1) { + const char *const filename = argv[optind]; + file = fopen(filename, "wx"); + closefile = true; + + if (file == NULL) { + perror("fopen"); + return EX_CANTCREAT; + } + } else if (optind == argc && !isatty(STDOUT_FILENO)) { + file = stdout; + closefile = false; + } else { + usage(argv); + } + +top: + ; + + void * config = stackshot_config_create(); + if (!config) { + perror("stackshot_config_create"); + return 1; + } + flags = flags | loadinfo | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_GET_DQ | STACKSHOT_KCDATA_FORMAT | STACKSHOT_THREAD_WAITINFO | + bootprofile | active_kernel_threads_only | iostats | thread_group | coalition | instrs_cycles; + + int err = stackshot_config_set_flags(config, flags); + if (err != 0) { + perror("stackshot_config_set_flags"); + return 1; + } + + if (pid != -1) { + int err = stackshot_config_set_pid(config, pid); + if (err != 0) { + perror("stackshot_config_set_flags"); + return 1; + } + } + + err = stackshot_capture_with_config(config); + if (err != 0) { + perror("stackshot_capture_with_config"); + return 1; + } + + void *buf = stackshot_config_get_stackshot_buffer(config); + if (!buf) { + perror("stackshot_config_get_stackshot_buffer"); + return 1; + } + + uint32_t size = stackshot_config_get_stackshot_size(config); + + if (delta) { + // output the original somewhere? + + uint64_t time = stackshot_get_mach_absolute_time(buf, size); + + err = stackshot_config_dealloc_buffer(config); + assert(!err); + + flags |= STACKSHOT_COLLECT_DELTA_SNAPSHOT; + int err = stackshot_config_set_flags(config, flags); + if (err != 0) { + perror("stackshot_config_set_flags"); + return 1; + } + + err = stackshot_config_set_delta_timestamp(config, time); + if (err != 0) { + perror("stackshot_config_delta_timestamp"); + return 1; + } + + if (sleep) { + forksleep(); + } + usleep(10000); + + err = stackshot_capture_with_config(config); + if (err != 0) { + perror("stackshot_capture_with_config"); + return 1; + } + + buf = stackshot_config_get_stackshot_buffer(config); + if (!buf) { + perror("stackshot_config_get_stackshot_buffer"); + return 1; + } + + size = stackshot_config_get_stackshot_size(config); + + + } + + if (stress) { + if (config) { + stackshot_config_dealloc(config); + config = NULL; + } + goto top; + } + + fwrite(buf, size, 1, file); + + if (closefile) { + fclose(file); + } + + return 0; +} -- cgit v1.2.3-56-ge451