]> git.saurik.com Git - apple/system_cmds.git/blob - stackshot.tproj/stackshot.c
7b0ddc8e782cc43ac69af83d7f9bea8039d5e2ab
[apple/system_cmds.git] / stackshot.tproj / stackshot.c
1 /* Copyright (c) 2017 Apple Inc. All rights reserved. */
2
3 #include <stdio.h>
4 #include <dispatch/dispatch.h>
5 #include <sysexits.h>
6 #include <inttypes.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <sys/syscall.h>
10 #include <sys/wait.h>
11 #include <mach/mach_time.h>
12 #include <sys/stackshot.h>
13 #include <sys/types.h>
14 #include <kern/debug.h>
15 #include <unistd.h>
16 #include <assert.h>
17
18 #include <kern/kcdata.h>
19
20 uint64_t
21 stackshot_get_mach_absolute_time(void *buffer, uint32_t size)
22 {
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");
26 exit(1);
27 }
28 return *(uint64_t *)kcdata_iter_payload(iter);
29 }
30
31 static void usage(char **argv)
32 {
33 fprintf (stderr, "usage: %s [-d] [-t] >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, " -t : enable tailspin mode\n");
39 fprintf (stderr, " -g : get thread group data\n");
40 fprintf (stderr, " -s : fork a sleep process\n");
41 fprintf (stderr, " -L : disable loadinfo\n");
42 fprintf (stderr, " -k : active kernel threads only\n");
43 fprintf (stderr, " -I : disable io statistics\n");
44 fprintf (stderr, " -S : stress test: while(1) stackshot; \n");
45 fprintf (stderr, " -p PID : target a pid\n");
46 fprintf (stderr, " -E : grab existing kernel buffer\n");
47 exit(1);
48 }
49
50 void forksleep() {
51 pid_t pid = fork();
52 if (pid < 0) {
53 perror("fork");
54 exit(1);
55 }
56
57 if (pid == 0) {
58 execlp("sleep", "sleep", "30", NULL);
59 perror("execlp");
60 exit(1);
61 }
62 }
63
64
65 int main(int argc, char **argv) {
66
67 uint32_t iostats = 0;
68 uint32_t active_kernel_threads_only = 0;
69 uint32_t tailspin = 0;
70 uint32_t bootprofile = 0;
71 uint32_t thread_group = 0;
72 uint32_t coalition = 0;
73 uint32_t instrs_cycles = 0;
74 uint32_t flags = 0;
75 uint32_t loadinfo = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO;
76 boolean_t delta = FALSE;
77 boolean_t sleep = FALSE;
78 boolean_t stress = FALSE;
79 pid_t pid = -1;
80 int c;
81
82 while ((c = getopt(argc, argv, "SgIikbcLdtsp:E")) != EOF) {
83 switch(c) {
84 case 'I':
85 iostats |= STACKSHOT_NO_IO_STATS;
86 break;
87 case 'k':
88 active_kernel_threads_only |= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY;
89 loadinfo &= ~STACKSHOT_SAVE_LOADINFO;
90 break;
91 case 'b':
92 bootprofile |= STACKSHOT_GET_BOOT_PROFILE;
93 break;
94 case 'c':
95 coalition |= STACKSHOT_SAVE_JETSAM_COALITIONS;
96 break;
97 case 'i':
98 instrs_cycles |= STACKSHOT_INSTRS_CYCLES;
99 break;
100 case 'L':
101 loadinfo = 0;
102 break;
103 case 'g':
104 thread_group |= STACKSHOT_THREAD_GROUP;
105 break;
106 case 't':
107 tailspin |= STACKSHOT_TAILSPIN;
108 break;
109 case 'd':
110 delta = TRUE;
111 break;
112 case 's':
113 sleep = TRUE;
114 break;
115 case 'p':
116 pid = atoi(optarg);
117 break;
118 case 'S':
119 stress = TRUE;
120 break;
121 case 'E':
122 flags = flags | STACKSHOT_RETRIEVE_EXISTING_BUFFER;
123 break;
124 case '?':
125 case 'h':
126 default:
127 usage(argv);
128 break;
129 }
130 }
131
132 if (thread_group && delta) {
133 fprintf(stderr, "stackshot does not support delta snapshots with thread groups\n");
134 return 1;
135 }
136
137 if (optind < argc) {
138 usage(argv);
139 }
140
141 top:
142 ;
143
144 void * config = stackshot_config_create();
145 if (!config) {
146 perror("stackshot_config_create");
147 return 1;
148 }
149 flags = flags | loadinfo | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_GET_DQ | STACKSHOT_KCDATA_FORMAT |
150 tailspin | bootprofile | active_kernel_threads_only | iostats | thread_group | coalition | instrs_cycles;
151
152 int err = stackshot_config_set_flags(config, flags);
153 if (err != 0) {
154 perror("stackshot_config_set_flags");
155 return 1;
156 }
157
158 if (pid != -1) {
159 int err = stackshot_config_set_pid(config, pid);
160 if (err != 0) {
161 perror("stackshot_config_set_flags");
162 return 1;
163 }
164 }
165
166 err = stackshot_capture_with_config(config);
167 if (err != 0) {
168 perror("stackshot_capture_with_config");
169 return 1;
170 }
171
172 void *buf = stackshot_config_get_stackshot_buffer(config);
173 if (!buf) {
174 perror("stackshot_config_get_stackshot_buffer");
175 return 1;
176 }
177
178 uint32_t size = stackshot_config_get_stackshot_size(config);
179
180 if (delta) {
181 // output the original somewhere?
182
183 uint64_t time = stackshot_get_mach_absolute_time(buf, size);
184
185 err = stackshot_config_dealloc_buffer(config);
186 assert(!err);
187
188 flags |= STACKSHOT_COLLECT_DELTA_SNAPSHOT;
189 int err = stackshot_config_set_flags(config, flags);
190 if (err != 0) {
191 perror("stackshot_config_set_flags");
192 return 1;
193 }
194
195 err = stackshot_config_set_delta_timestamp(config, time);
196 if (err != 0) {
197 perror("stackshot_config_delta_timestamp");
198 return 1;
199 }
200
201 if (sleep) {
202 forksleep();
203 }
204 usleep(10000);
205
206 err = stackshot_capture_with_config(config);
207 if (err != 0) {
208 perror("stackshot_capture_with_config");
209 return 1;
210 }
211
212 buf = stackshot_config_get_stackshot_buffer(config);
213 if (!buf) {
214 perror("stackshot_config_get_stackshot_buffer");
215 return 1;
216 }
217
218 size = stackshot_config_get_stackshot_size(config);
219
220
221 }
222
223
224 if (stress) {
225 if (config) {
226 stackshot_config_dealloc(config);
227 config = NULL;
228 }
229 goto top;
230 }
231
232 fwrite(buf, size, 1, stdout);
233 }