#include <kern/kcdata.h>
-uint64_t
+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);
return *(uint64_t *)kcdata_iter_payload(iter);
}
-static void usage(char **argv)
+__dead2 static void usage(char **argv)
{
- fprintf (stderr, "usage: %s [-d] [-t] >file\n", argv[0]);
+ 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, " -t : enable tailspin mode\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, " -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);
}
-void forksleep() {
+static void forksleep() {
pid_t pid = fork();
if (pid < 0) {
perror("fork");
uint32_t iostats = 0;
uint32_t active_kernel_threads_only = 0;
- uint32_t tailspin = 0;
uint32_t bootprofile = 0;
uint32_t thread_group = 0;
uint32_t coalition = 0;
boolean_t stress = FALSE;
pid_t pid = -1;
int c;
+ FILE *file;
+ bool closefile;
- while ((c = getopt(argc, argv, "SgIikbcLdtsp:E")) != EOF) {
+ while ((c = getopt(argc, argv, "SgIikbcLdtsp:E")) != -1) {
switch(c) {
case 'I':
iostats |= STACKSHOT_NO_IO_STATS;
case 'g':
thread_group |= STACKSHOT_THREAD_GROUP;
break;
- case 't':
- tailspin |= STACKSHOT_TAILSPIN;
- break;
case 'd':
delta = TRUE;
break;
return 1;
}
- if (optind < argc) {
+ 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);
}
perror("stackshot_config_create");
return 1;
}
- flags = flags | loadinfo | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_GET_DQ | STACKSHOT_KCDATA_FORMAT |
- tailspin | bootprofile | active_kernel_threads_only | iostats | thread_group | coalition | instrs_cycles;
+ 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) {
}
-
if (stress) {
if (config) {
stackshot_config_dealloc(config);
goto top;
}
- fwrite(buf, size, 1, stdout);
+ fwrite(buf, size, 1, file);
+
+ if (closefile) {
+ fclose(file);
+ }
+
+ return 0;
}