1 /* Copyright (c) 2017 Apple Inc. All rights reserved. */
4 #include <dispatch/dispatch.h>
9 #include <sys/syscall.h>
11 #include <mach/mach_time.h>
12 #include <sys/stackshot.h>
13 #include <sys/types.h>
14 #include <kern/debug.h>
18 #include <kern/kcdata.h>
21 stackshot_get_mach_absolute_time(void *buffer
, uint32_t size
)
23 kcdata_iter_t iter
= kcdata_iter_find_type(kcdata_iter(buffer
, size
), KCDATA_TYPE_MACH_ABSOLUTE_TIME
);
24 if (!kcdata_iter_valid(iter
) || kcdata_iter_size(iter
) < sizeof(uint64_t)) {
25 fprintf(stderr
, "bad kcdata\n");
28 return *(uint64_t *)kcdata_iter_payload(iter
);
31 __dead2
static void usage(char **argv
)
33 fprintf (stderr
, "usage: %s [options] [file]\n", argv
[0]);
34 fprintf (stderr
, " -d : take delta stackshot\n");
35 fprintf (stderr
, " -b : get bootprofile\n");
36 fprintf (stderr
, " -c : get coalition data\n");
37 fprintf (stderr
, " -i : get instructions and cycles\n");
38 fprintf (stderr
, " -g : get thread group data\n");
39 fprintf (stderr
, " -s : fork a sleep process\n");
40 fprintf (stderr
, " -L : disable loadinfo\n");
41 fprintf (stderr
, " -k : active kernel threads only\n");
42 fprintf (stderr
, " -I : disable io statistics\n");
43 fprintf (stderr
, " -S : stress test: while(1) stackshot; \n");
44 fprintf (stderr
, " -p PID : target a pid\n");
45 fprintf (stderr
, " -E : grab existing kernel buffer\n");
46 fprintf (stderr
, "If no file is provided and stdout is not a TTY, the stackshot will be written to stdout.\n");
50 static void forksleep() {
58 execlp("sleep", "sleep", "30", NULL
);
65 int main(int argc
, char **argv
) {
68 uint32_t active_kernel_threads_only
= 0;
69 uint32_t bootprofile
= 0;
70 uint32_t thread_group
= 0;
71 uint32_t coalition
= 0;
72 uint32_t instrs_cycles
= 0;
74 uint32_t loadinfo
= STACKSHOT_SAVE_LOADINFO
| STACKSHOT_SAVE_KEXT_LOADINFO
;
75 boolean_t delta
= FALSE
;
76 boolean_t sleep
= FALSE
;
77 boolean_t stress
= FALSE
;
83 while ((c
= getopt(argc
, argv
, "SgIikbcLdtsp:E")) != -1) {
86 iostats
|= STACKSHOT_NO_IO_STATS
;
89 active_kernel_threads_only
|= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
;
90 loadinfo
&= ~STACKSHOT_SAVE_LOADINFO
;
93 bootprofile
|= STACKSHOT_GET_BOOT_PROFILE
;
96 coalition
|= STACKSHOT_SAVE_JETSAM_COALITIONS
;
99 instrs_cycles
|= STACKSHOT_INSTRS_CYCLES
;
105 thread_group
|= STACKSHOT_THREAD_GROUP
;
120 flags
= flags
| STACKSHOT_RETRIEVE_EXISTING_BUFFER
;
130 if (thread_group
&& delta
) {
131 fprintf(stderr
, "stackshot does not support delta snapshots with thread groups\n");
135 if (optind
== argc
- 1) {
136 const char *const filename
= argv
[optind
];
137 file
= fopen(filename
, "wx");
144 } else if (optind
== argc
&& !isatty(STDOUT_FILENO
)) {
154 void * config
= stackshot_config_create();
156 perror("stackshot_config_create");
159 flags
= flags
| loadinfo
| STACKSHOT_SAVE_IMP_DONATION_PIDS
| STACKSHOT_GET_DQ
| STACKSHOT_KCDATA_FORMAT
| STACKSHOT_THREAD_WAITINFO
|
160 bootprofile
| active_kernel_threads_only
| iostats
| thread_group
| coalition
| instrs_cycles
;
162 int err
= stackshot_config_set_flags(config
, flags
);
164 perror("stackshot_config_set_flags");
169 int err
= stackshot_config_set_pid(config
, pid
);
171 perror("stackshot_config_set_flags");
176 err
= stackshot_capture_with_config(config
);
178 perror("stackshot_capture_with_config");
182 void *buf
= stackshot_config_get_stackshot_buffer(config
);
184 perror("stackshot_config_get_stackshot_buffer");
188 uint32_t size
= stackshot_config_get_stackshot_size(config
);
191 // output the original somewhere?
193 uint64_t time
= stackshot_get_mach_absolute_time(buf
, size
);
195 err
= stackshot_config_dealloc_buffer(config
);
198 flags
|= STACKSHOT_COLLECT_DELTA_SNAPSHOT
;
199 int err
= stackshot_config_set_flags(config
, flags
);
201 perror("stackshot_config_set_flags");
205 err
= stackshot_config_set_delta_timestamp(config
, time
);
207 perror("stackshot_config_delta_timestamp");
216 err
= stackshot_capture_with_config(config
);
218 perror("stackshot_capture_with_config");
222 buf
= stackshot_config_get_stackshot_buffer(config
);
224 perror("stackshot_config_get_stackshot_buffer");
228 size
= stackshot_config_get_stackshot_size(config
);
235 stackshot_config_dealloc(config
);
241 fwrite(buf
, size
, 1, file
);