]>
Commit | Line | Data |
---|---|---|
39037602 A |
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 | } |