]> git.saurik.com Git - apple/xnu.git/blob - tools/stackshot/stackshot.c
854e00a7d04e39751a927bf845d02ba4a8f3530a
[apple/xnu.git] / tools / stackshot / stackshot.c
1
2 #include <stdio.h>
3 #include <dispatch/dispatch.h>
4 #include <sysexits.h>
5 #include <inttypes.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <sys/syscall.h>
9 #include <sys/wait.h>
10 #include <mach/mach_time.h>
11 #include <sys/stackshot.h>
12 #include <sys/types.h>
13 #include <kern/debug.h>
14 #include <unistd.h>
15 #include <assert.h>
16
17 #include <kern/kcdata.h>
18
19 #define STACKSHOT_TAILSPIN (0x80000)
20
21 uint64_t
22 stackshot_get_mach_absolute_time(void *buffer, uint32_t size)
23 {
24 kcdata_iter_t iter = kcdata_iter_find_type(kcdata_iter(buffer, size), KCDATA_TYPE_MACH_ABSOLUTE_TIME);
25 if (!kcdata_iter_valid(iter) || kcdata_iter_size(iter) < sizeof(uint64_t)) {
26 fprintf(stderr, "bad kcdata\n");
27 exit(1);
28 }
29 return *(uint64_t *)kcdata_iter_payload(iter);
30 }
31
32 static void usage(char **argv)
33 {
34 fprintf (stderr, "usage: %s [-d] [-t] >file\n", argv[0]);
35 fprintf (stderr, " -d : take delta stackshot\n");
36 fprintf (stderr, " -b : get bootprofile\n");
37 fprintf (stderr, " -t : enable tailspin mode\n");
38 fprintf (stderr, " -s : fork a sleep process\n");
39 fprintf (stderr, " -L : disable loadinfo\n");
40 fprintf (stderr, " -k : active kernel threads only\n");
41 fprintf (stderr, " -I : disable io statistics\n");
42 fprintf (stderr, " -p PID : target a pid\n");
43 exit(1);
44 }
45
46 void forksleep() {
47 pid_t pid = fork();
48 if (pid < 0) {
49 perror("fork");
50 exit(1);
51 }
52
53 if (pid == 0) {
54 execlp("sleep", "sleep", "30", NULL);
55 perror("execlp");
56 exit(1);
57 }
58 }
59
60
61 int main(int argc, char **argv) {
62
63 uint32_t iostats = 0;
64 uint32_t active_kernel_threads_only = 0;
65 uint32_t tailspin = 0;
66 uint32_t bootprofile = 0;
67 uint32_t loadinfo = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO;
68 boolean_t delta = FALSE;
69 boolean_t sleep = FALSE;
70 pid_t pid = -1;
71 int c;
72
73 while ((c = getopt(argc, argv, "IkbLdtsp:")) != EOF) {
74 switch(c) {
75 case 'I':
76 iostats |= STACKSHOT_NO_IO_STATS;
77 break;
78 case 'k':
79 active_kernel_threads_only |= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY;
80 loadinfo &= ~STACKSHOT_SAVE_LOADINFO;
81 break;
82 case 'b':
83 bootprofile |= STACKSHOT_GET_BOOT_PROFILE;
84 break;
85 case 'L':
86 loadinfo = 0;
87 break;
88 case 't':
89 tailspin |= STACKSHOT_TAILSPIN;
90 break;
91 case 'd':
92 delta = TRUE;
93 break;
94 case 's':
95 sleep = TRUE;
96 break;
97 case 'p':
98 pid = atoi(optarg);
99 break;
100 case '?':
101 case 'h':
102 default:
103 usage(argv);
104 break;
105 }
106 }
107
108 if (optind < argc)
109 {
110 usage(argv);
111 }
112
113 void * config = stackshot_config_create();
114 if (!config) {
115 perror("stackshot_config_create");
116 return 1;
117 }
118 uint32_t flags = loadinfo | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_GET_DQ | STACKSHOT_KCDATA_FORMAT |
119 tailspin | bootprofile | active_kernel_threads_only | iostats;
120
121 int err = stackshot_config_set_flags(config, flags);
122 if (err != 0) {
123 perror("stackshot_config_set_flags");
124 return 1;
125 }
126
127 if (pid != -1) {
128 int err = stackshot_config_set_pid(config, pid);
129 if (err != 0) {
130 perror("stackshot_config_set_flags");
131 return 1;
132 }
133 }
134
135 err = stackshot_capture_with_config(config);
136 if (err != 0) {
137 perror("stackshot_capture_with_config");
138 return 1;
139 }
140
141 void *buf = stackshot_config_get_stackshot_buffer(config);
142 if (!buf) {
143 perror("stackshot_config_get_stackshot_buffer");
144 return 1;
145 }
146
147 uint32_t size = stackshot_config_get_stackshot_size(config);
148
149 if (delta) {
150 // output the original somewhere?
151
152 uint64_t time = stackshot_get_mach_absolute_time(buf, size);
153
154 err = stackshot_config_dealloc_buffer(config);
155 assert(!err);
156
157 flags |= STACKSHOT_COLLECT_DELTA_SNAPSHOT;
158 int err = stackshot_config_set_flags(config, flags);
159 if (err != 0) {
160 perror("stackshot_config_set_flags");
161 return 1;
162 }
163
164 err = stackshot_config_set_delta_timestamp(config, time);
165 if (err != 0) {
166 perror("stackshot_config_delta_timestamp");
167 return 1;
168 }
169
170 if (sleep) {
171 forksleep();
172 }
173 usleep(10000);
174
175 err = stackshot_capture_with_config(config);
176 if (err != 0) {
177 perror("stackshot_capture_with_config");
178 return 1;
179 }
180
181 buf = stackshot_config_get_stackshot_buffer(config);
182 if (!buf) {
183 perror("stackshot_config_get_stackshot_buffer");
184 return 1;
185 }
186
187 size = stackshot_config_get_stackshot_size(config);
188
189 }
190
191 fwrite(buf, size, 1, stdout);
192 }