]> git.saurik.com Git - apple/xnu.git/blob - tests/kdebug.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / tests / kdebug.c
1 #include <darwintest.h>
2 #include <darwintest_utils.h>
3 #include <dispatch/dispatch.h>
4 #include <inttypes.h>
5 #include <ktrace/session.h>
6 #include <ktrace/private.h>
7 #include <kperf/kperf.h>
8 #include <mach/clock_types.h>
9 #include <mach/dyld_kernel.h>
10 #include <mach/host_info.h>
11 #include <mach/mach.h>
12 #include <mach/mach_init.h>
13 #include <mach/task.h>
14 #include <os/assumes.h>
15 #include <stdlib.h>
16 #include <sys/kdebug.h>
17 #include <sys/kdebug_signpost.h>
18 #include <sys/sysctl.h>
19 #include <stdint.h>
20
21 #include "ktrace_helpers.h"
22 #include "test_utils.h"
23
24 T_GLOBAL_META(
25 T_META_NAMESPACE("xnu.ktrace"),
26 T_META_ASROOT(true));
27
28 #define KDBG_TEST_MACROS 1
29 #define KDBG_TEST_OLD_TIMES 2
30 #define KDBG_TEST_FUTURE_TIMES 3
31 #define KDBG_TEST_IOP_SYNC_FLUSH 4
32
33 static void
34 assert_kdebug_test(unsigned int flavor)
35 {
36 size_t size = flavor;
37 int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDTEST };
38 T_ASSERT_POSIX_SUCCESS(sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL,
39 &size, NULL, 0), "KERN_KDTEST sysctl");
40 }
41
42 #pragma mark kdebug syscalls
43
44 #define TRACE_DEBUGID (0xfedfed00U)
45
46 T_DECL(kdebug_trace_syscall, "test that kdebug_trace(2) emits correct events")
47 {
48 start_controlling_ktrace();
49
50 ktrace_session_t s = ktrace_session_create();
51 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "created session");
52
53 ktrace_events_class(s, DBG_MACH, ^(__unused struct trace_point *tp){});
54
55 __block int events_seen = 0;
56 ktrace_events_single(s, TRACE_DEBUGID, ^void (struct trace_point *tp) {
57 events_seen++;
58 T_PASS("saw traced event");
59
60 if (ktrace_is_kernel_64_bit(s)) {
61 T_EXPECT_EQ(tp->arg1, UINT64_C(0xfeedfacefeedface),
62 "argument 1 of traced event is correct");
63 } else {
64 T_EXPECT_EQ(tp->arg1, UINT64_C(0xfeedface),
65 "argument 1 of traced event is correct");
66 }
67 T_EXPECT_EQ(tp->arg2, 2ULL, "argument 2 of traced event is correct");
68 T_EXPECT_EQ(tp->arg3, 3ULL, "argument 3 of traced event is correct");
69 T_EXPECT_EQ(tp->arg4, 4ULL, "argument 4 of traced event is correct");
70
71 ktrace_end(s, 1);
72 });
73
74 ktrace_set_completion_handler(s, ^{
75 T_EXPECT_GE(events_seen, 1, NULL);
76 ktrace_session_destroy(s);
77 T_END;
78 });
79
80 ktrace_filter_pid(s, getpid());
81
82 T_ASSERT_POSIX_ZERO(ktrace_start(s, dispatch_get_main_queue()), NULL);
83 T_ASSERT_POSIX_SUCCESS(kdebug_trace(TRACE_DEBUGID, 0xfeedfacefeedface, 2,
84 3, 4), NULL);
85 ktrace_end(s, 0);
86
87 dispatch_main();
88 }
89
90 #define SIGNPOST_SINGLE_CODE (0x10U)
91 #define SIGNPOST_PAIRED_CODE (0x20U)
92
93 T_DECL(kdebug_signpost_syscall,
94 "test that kdebug_signpost(2) emits correct events")
95 {
96 start_controlling_ktrace();
97
98 ktrace_session_t s = ktrace_session_create();
99 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "created session");
100
101 __block int single_seen = 0;
102 __block int paired_seen = 0;
103
104 /* make sure to get enough events for the KDBUFWAIT to trigger */
105 // ktrace_events_class(s, DBG_MACH, ^(__unused struct trace_point *tp){});
106 ktrace_events_single(s,
107 APPSDBG_CODE(DBG_APP_SIGNPOST, SIGNPOST_SINGLE_CODE),
108 ^(struct trace_point *tp) {
109 single_seen++;
110 T_PASS("single signpost is traced");
111
112 T_EXPECT_EQ(tp->arg1, 1ULL, "argument 1 of single signpost is correct");
113 T_EXPECT_EQ(tp->arg2, 2ULL, "argument 2 of single signpost is correct");
114 T_EXPECT_EQ(tp->arg3, 3ULL, "argument 3 of single signpost is correct");
115 T_EXPECT_EQ(tp->arg4, 4ULL, "argument 4 of single signpost is correct");
116 });
117
118 ktrace_events_single_paired(s,
119 APPSDBG_CODE(DBG_APP_SIGNPOST, SIGNPOST_PAIRED_CODE),
120 ^(struct trace_point *start, struct trace_point *end) {
121 paired_seen++;
122 T_PASS("paired signposts are traced");
123
124 T_EXPECT_EQ(start->arg1, 5ULL, "argument 1 of start signpost is correct");
125 T_EXPECT_EQ(start->arg2, 6ULL, "argument 2 of start signpost is correct");
126 T_EXPECT_EQ(start->arg3, 7ULL, "argument 3 of start signpost is correct");
127 T_EXPECT_EQ(start->arg4, 8ULL, "argument 4 of start signpost is correct");
128
129 T_EXPECT_EQ(end->arg1, 9ULL, "argument 1 of end signpost is correct");
130 T_EXPECT_EQ(end->arg2, 10ULL, "argument 2 of end signpost is correct");
131 T_EXPECT_EQ(end->arg3, 11ULL, "argument 3 of end signpost is correct");
132 T_EXPECT_EQ(end->arg4, 12ULL, "argument 4 of end signpost is correct");
133
134 T_EXPECT_EQ(single_seen, 1, "signposts are traced in the correct order");
135
136 ktrace_end(s, 1);
137 });
138
139 ktrace_set_completion_handler(s, ^(void) {
140 T_QUIET; T_EXPECT_NE(single_seen, 0,
141 "did not see single tracepoint before timeout");
142 T_QUIET; T_EXPECT_NE(paired_seen, 0,
143 "did not see single tracepoint before timeout");
144 ktrace_session_destroy(s);
145 T_END;
146 });
147
148 ktrace_filter_pid(s, getpid());
149
150 T_ASSERT_POSIX_ZERO(ktrace_start(s, dispatch_get_main_queue()),
151 "started tracing");
152
153 #pragma clang diagnostic push
154 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
155 T_EXPECT_POSIX_SUCCESS(kdebug_signpost(SIGNPOST_SINGLE_CODE, 1, 2, 3, 4),
156 "emitted single signpost");
157 T_EXPECT_POSIX_SUCCESS(
158 kdebug_signpost_start(SIGNPOST_PAIRED_CODE, 5, 6, 7, 8),
159 "emitted start signpost");
160 T_EXPECT_POSIX_SUCCESS(
161 kdebug_signpost_end(SIGNPOST_PAIRED_CODE, 9, 10, 11, 12),
162 "emitted end signpost");
163 #pragma clang diagnostic pop
164 ktrace_end(s, 0);
165
166 dispatch_main();
167 }
168
169 T_DECL(syscall_tracing,
170 "ensure that syscall arguments are traced propertly")
171 {
172 ktrace_session_t s = ktrace_session_create();
173 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "created session");
174
175 __block bool seen = 0;
176
177 ktrace_filter_pid(s, getpid());
178
179 static const int telemetry_syscall_no = 451;
180 static const uint64_t arg1 = 0xfeedfacefeedface;
181
182 ktrace_events_single(s, BSDDBG_CODE(DBG_BSD_EXCP_SC, telemetry_syscall_no),
183 ^(struct trace_point *evt){
184 if (KDBG_EXTRACT_CODE(evt->debugid) != telemetry_syscall_no || seen) {
185 return;
186 }
187
188 seen = true;
189 if (ktrace_is_kernel_64_bit(s)) {
190 T_EXPECT_EQ(evt->arg1, arg1,
191 "argument 1 of syscall event is correct");
192 } else {
193 T_EXPECT_EQ(evt->arg1, (uint64_t)(uint32_t)(arg1),
194 "argument 1 of syscall event is correct");
195 }
196
197 ktrace_end(s, 1);
198 });
199
200 ktrace_set_completion_handler(s, ^{
201 T_ASSERT_TRUE(seen,
202 "should have seen a syscall event for kevent_id(2)");
203 ktrace_session_destroy(s);
204 T_END;
205 });
206
207 int error = ktrace_start(s, dispatch_get_main_queue());
208 T_ASSERT_POSIX_ZERO(error, "started tracing");
209
210 /*
211 * telemetry(2) has a 64-bit argument that will definitely be traced, and
212 * is unlikely to be used elsewhere by this process.
213 */
214 extern int __telemetry(uint64_t cmd, uint64_t deadline, uint64_t interval,
215 uint64_t leeway, uint64_t arg4, uint64_t arg5);
216 (void)__telemetry(arg1, 0, 0, 0, 0, 0);
217
218 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC),
219 dispatch_get_main_queue(), ^{
220 T_LOG("ending test due to timeout");
221 ktrace_end(s, 0);
222 });
223
224 dispatch_main();
225 }
226
227 #pragma mark kdebug behaviors
228
229 #define WRAPPING_EVENTS_COUNT (150000)
230 #define TRACE_ITERATIONS (5000)
231 #define WRAPPING_EVENTS_THRESHOLD (100)
232
233 T_DECL(wrapping,
234 "ensure that wrapping traces lost events and no events prior to the wrap",
235 T_META_CHECK_LEAKS(false))
236 {
237 kbufinfo_t buf_info;
238 int wait_wrapping_secs = (WRAPPING_EVENTS_COUNT / TRACE_ITERATIONS) + 5;
239 int current_secs = wait_wrapping_secs;
240
241 start_controlling_ktrace();
242
243 /* use sysctls manually to bypass libktrace assumptions */
244
245 int mib[4] = { CTL_KERN, KERN_KDEBUG };
246 mib[2] = KERN_KDSETBUF; mib[3] = WRAPPING_EVENTS_COUNT;
247 T_ASSERT_POSIX_SUCCESS(sysctl(mib, 4, NULL, 0, NULL, 0), "KERN_KDSETBUF");
248
249 mib[2] = KERN_KDSETUP; mib[3] = 0;
250 size_t needed = 0;
251 T_ASSERT_POSIX_SUCCESS(sysctl(mib, 3, NULL, &needed, NULL, 0),
252 "KERN_KDSETUP");
253
254 mib[2] = KERN_KDENABLE; mib[3] = 1;
255 T_ASSERT_POSIX_SUCCESS(sysctl(mib, 4, NULL, 0, NULL, 0), "KERN_KDENABLE");
256
257 /* wrapping is on by default */
258
259 /* wait until wrapped */
260 T_LOG("waiting for trace to wrap");
261 mib[2] = KERN_KDGETBUF;
262 needed = sizeof(buf_info);
263 do {
264 sleep(1);
265 for (int i = 0; i < TRACE_ITERATIONS; i++) {
266 T_QUIET;
267 T_ASSERT_POSIX_SUCCESS(kdebug_trace(0xfefe0000, 0, 0, 0, 0), NULL);
268 }
269 T_QUIET;
270 T_ASSERT_POSIX_SUCCESS(sysctl(mib, 3, &buf_info, &needed, NULL, 0),
271 NULL);
272 } while (!(buf_info.flags & KDBG_WRAPPED) && --current_secs > 0);
273
274 T_ASSERT_TRUE(buf_info.flags & KDBG_WRAPPED,
275 "trace wrapped (after %d seconds within %d second timeout)",
276 wait_wrapping_secs - current_secs, wait_wrapping_secs);
277
278 ktrace_session_t s = ktrace_session_create();
279 T_QUIET; T_ASSERT_NOTNULL(s, NULL);
280 T_QUIET; T_ASSERT_POSIX_ZERO(ktrace_set_use_existing(s), NULL);
281
282 __block int events = 0;
283
284 ktrace_events_all(s, ^(struct trace_point *tp) {
285 if (events == 0) {
286 T_EXPECT_EQ(tp->debugid, (unsigned int)TRACE_LOST_EVENTS,
287 "first event's debugid 0x%08x (%s) should be TRACE_LOST_EVENTS",
288 tp->debugid,
289 ktrace_name_for_eventid(s, tp->debugid & KDBG_EVENTID_MASK));
290 } else {
291 T_QUIET;
292 T_EXPECT_NE(tp->debugid, (unsigned int)TRACE_LOST_EVENTS,
293 "event debugid 0x%08x (%s) should not be TRACE_LOST_EVENTS",
294 tp->debugid,
295 ktrace_name_for_eventid(s, tp->debugid & KDBG_EVENTID_MASK));
296 }
297
298 events++;
299 if (events > WRAPPING_EVENTS_THRESHOLD) {
300 ktrace_end(s, 1);
301 }
302 });
303
304 ktrace_set_completion_handler(s, ^{
305 ktrace_session_destroy(s);
306 T_END;
307 });
308
309 T_ASSERT_POSIX_ZERO(ktrace_start(s, dispatch_get_main_queue()),
310 "started tracing");
311
312 dispatch_main();
313 }
314
315 T_DECL(reject_old_events,
316 "ensure that kdebug rejects events from before tracing began",
317 T_META_CHECK_LEAKS(false))
318 {
319 __block uint64_t event_horizon_ts;
320
321 start_controlling_ktrace();
322
323 ktrace_session_t s = ktrace_session_create();
324 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "created session");
325
326 __block int events = 0;
327 ktrace_events_single(s, KDBG_EVENTID(DBG_BSD, DBG_BSD_KDEBUG_TEST, 1),
328 ^(struct trace_point *tp) {
329 events++;
330 T_EXPECT_GT(tp->timestamp, event_horizon_ts,
331 "events in trace should be from after tracing began");
332 });
333
334 ktrace_set_completion_handler(s, ^{
335 T_EXPECT_EQ(events, 2, "should see only two events");
336 ktrace_session_destroy(s);
337 T_END;
338 });
339
340 event_horizon_ts = mach_absolute_time();
341
342 T_ASSERT_POSIX_ZERO(ktrace_start(s, dispatch_get_main_queue()), NULL);
343 /* first, try an old event at the beginning of trace */
344 assert_kdebug_test(KDBG_TEST_OLD_TIMES);
345 /* after a good event has been traced, old events should be rejected */
346 assert_kdebug_test(KDBG_TEST_OLD_TIMES);
347 ktrace_end(s, 0);
348
349 dispatch_main();
350 }
351
352 #define ORDERING_TIMEOUT_SEC 5
353
354 T_DECL(ascending_time_order,
355 "ensure that kdebug events are in ascending order based on time",
356 T_META_CHECK_LEAKS(false))
357 {
358 __block uint64_t prev_ts = 0;
359 __block uint32_t prev_debugid = 0;
360 __block unsigned int prev_cpu = 0;
361 __block bool in_order = true;
362
363 start_controlling_ktrace();
364
365 ktrace_session_t s = ktrace_session_create();
366 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "created session");
367
368 ktrace_events_all(s, ^(struct trace_point *tp) {
369 if (tp->timestamp < prev_ts) {
370 in_order = false;
371 T_LOG("%" PRIu64 ": %#" PRIx32 " (cpu %d)",
372 prev_ts, prev_debugid, prev_cpu);
373 T_LOG("%" PRIu64 ": %#" PRIx32 " (cpu %d)",
374 tp->timestamp, tp->debugid, tp->cpuid);
375 ktrace_end(s, 1);
376 }
377 });
378
379 ktrace_set_completion_handler(s, ^{
380 ktrace_session_destroy(s);
381 T_EXPECT_TRUE(in_order, "event timestamps were in-order");
382 T_END;
383 });
384
385 T_ASSERT_POSIX_ZERO(ktrace_start(s, dispatch_get_main_queue()),
386 "started tracing");
387
388 /* try to inject old timestamps into trace */
389 assert_kdebug_test(KDBG_TEST_OLD_TIMES);
390
391 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, ORDERING_TIMEOUT_SEC * NSEC_PER_SEC),
392 dispatch_get_main_queue(), ^{
393 T_LOG("ending test after timeout");
394 ktrace_end(s, 1);
395 });
396
397 dispatch_main();
398 }
399
400 #pragma mark dyld tracing
401
402 __attribute__((aligned(8)))
403 static const char map_uuid[16] = "map UUID";
404
405 __attribute__((aligned(8)))
406 static const char unmap_uuid[16] = "unmap UUID";
407
408 __attribute__((aligned(8)))
409 static const char sc_uuid[16] = "shared UUID";
410
411 static fsid_t map_fsid = { .val = { 42, 43 } };
412 static fsid_t unmap_fsid = { .val = { 44, 45 } };
413 static fsid_t sc_fsid = { .val = { 46, 47 } };
414
415 static fsobj_id_t map_fsobjid = { .fid_objno = 42, .fid_generation = 43 };
416 static fsobj_id_t unmap_fsobjid = { .fid_objno = 44, .fid_generation = 45 };
417 static fsobj_id_t sc_fsobjid = { .fid_objno = 46, .fid_generation = 47 };
418
419 #define MAP_LOAD_ADDR 0xabadcafe
420 #define UNMAP_LOAD_ADDR 0xfeedface
421 #define SC_LOAD_ADDR 0xfedfaced
422
423 __unused
424 static void
425 expect_dyld_image_info(struct trace_point *tp, const uint64_t *exp_uuid,
426 uint64_t exp_load_addr, fsid_t *exp_fsid, fsobj_id_t *exp_fsobjid,
427 int order)
428 {
429 #if defined(__LP64__) || defined(__arm64__)
430 if (order == 0) {
431 uint64_t uuid[2];
432 uint64_t load_addr;
433 fsid_t fsid;
434
435 uuid[0] = (uint64_t)tp->arg1;
436 uuid[1] = (uint64_t)tp->arg2;
437 load_addr = (uint64_t)tp->arg3;
438 fsid.val[0] = (int32_t)(tp->arg4 & UINT32_MAX);
439 fsid.val[1] = (int32_t)((uint64_t)tp->arg4 >> 32);
440
441 T_QUIET; T_EXPECT_EQ(uuid[0], exp_uuid[0], NULL);
442 T_QUIET; T_EXPECT_EQ(uuid[1], exp_uuid[1], NULL);
443 T_QUIET; T_EXPECT_EQ(load_addr, exp_load_addr, NULL);
444 T_QUIET; T_EXPECT_EQ(fsid.val[0], exp_fsid->val[0], NULL);
445 T_QUIET; T_EXPECT_EQ(fsid.val[1], exp_fsid->val[1], NULL);
446 } else if (order == 1) {
447 fsobj_id_t fsobjid;
448
449 fsobjid.fid_objno = (uint32_t)(tp->arg1 & UINT32_MAX);
450 fsobjid.fid_generation = (uint32_t)((uint64_t)tp->arg1 >> 32);
451
452 T_QUIET; T_EXPECT_EQ(fsobjid.fid_objno, exp_fsobjid->fid_objno, NULL);
453 T_QUIET; T_EXPECT_EQ(fsobjid.fid_generation,
454 exp_fsobjid->fid_generation, NULL);
455 } else {
456 T_ASSERT_FAIL("unrecognized order of events %d", order);
457 }
458 #else /* defined(__LP64__) */
459 if (order == 0) {
460 uint32_t uuid[4];
461
462 uuid[0] = (uint32_t)tp->arg1;
463 uuid[1] = (uint32_t)tp->arg2;
464 uuid[2] = (uint32_t)tp->arg3;
465 uuid[3] = (uint32_t)tp->arg4;
466
467 T_QUIET; T_EXPECT_EQ(uuid[0], (uint32_t)exp_uuid[0], NULL);
468 T_QUIET; T_EXPECT_EQ(uuid[1], (uint32_t)(exp_uuid[0] >> 32), NULL);
469 T_QUIET; T_EXPECT_EQ(uuid[2], (uint32_t)exp_uuid[1], NULL);
470 T_QUIET; T_EXPECT_EQ(uuid[3], (uint32_t)(exp_uuid[1] >> 32), NULL);
471 } else if (order == 1) {
472 uint32_t load_addr;
473 fsid_t fsid;
474 fsobj_id_t fsobjid;
475
476 load_addr = (uint32_t)tp->arg1;
477 fsid.val[0] = (int32_t)tp->arg2;
478 fsid.val[1] = (int32_t)tp->arg3;
479 fsobjid.fid_objno = (uint32_t)tp->arg4;
480
481 T_QUIET; T_EXPECT_EQ(load_addr, (uint32_t)exp_load_addr, NULL);
482 T_QUIET; T_EXPECT_EQ(fsid.val[0], exp_fsid->val[0], NULL);
483 T_QUIET; T_EXPECT_EQ(fsid.val[1], exp_fsid->val[1], NULL);
484 T_QUIET; T_EXPECT_EQ(fsobjid.fid_objno, exp_fsobjid->fid_objno, NULL);
485 } else if (order == 2) {
486 fsobj_id_t fsobjid;
487
488 fsobjid.fid_generation = tp->arg1;
489
490 T_QUIET; T_EXPECT_EQ(fsobjid.fid_generation,
491 exp_fsobjid->fid_generation, NULL);
492 } else {
493 T_ASSERT_FAIL("unrecognized order of events %d", order);
494 }
495 #endif /* defined(__LP64__) */
496 }
497
498 #if defined(__LP64__) || defined(__arm64__)
499 #define DYLD_CODE_OFFSET (0)
500 #define DYLD_EVENTS (2)
501 #else
502 #define DYLD_CODE_OFFSET (2)
503 #define DYLD_EVENTS (3)
504 #endif
505
506 static void
507 expect_dyld_events(ktrace_session_t s, const char *name, uint32_t base_code,
508 const char *exp_uuid, uint64_t exp_load_addr, fsid_t *exp_fsid,
509 fsobj_id_t *exp_fsobjid, uint8_t *saw_events)
510 {
511 for (int i = 0; i < DYLD_EVENTS; i++) {
512 ktrace_events_single(s, KDBG_EVENTID(DBG_DYLD, DBG_DYLD_UUID,
513 base_code + DYLD_CODE_OFFSET + (unsigned int)i),
514 ^(struct trace_point *tp) {
515 T_LOG("checking %s event %c", name, 'A' + i);
516 expect_dyld_image_info(tp, (const void *)exp_uuid, exp_load_addr,
517 exp_fsid, exp_fsobjid, i);
518 *saw_events |= (1U << i);
519 });
520 }
521 }
522
523 T_DECL(dyld_events, "test that dyld registering libraries emits events")
524 {
525 dyld_kernel_image_info_t info;
526
527 /*
528 * Use pointers instead of __block variables in order to use these variables
529 * in the completion block below _and_ pass pointers to them to the
530 * expect_dyld_events function.
531 */
532 uint8_t saw_events[3] = { 0 };
533 uint8_t *saw_mapping = &(saw_events[0]);
534 uint8_t *saw_unmapping = &(saw_events[1]);
535 uint8_t *saw_shared_cache = &(saw_events[2]);
536
537 start_controlling_ktrace();
538
539 ktrace_session_t s = ktrace_session_create();
540 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "created session");
541
542 T_QUIET;
543 T_ASSERT_POSIX_ZERO(ktrace_filter_pid(s, getpid()),
544 "filtered to current process");
545
546 expect_dyld_events(s, "mapping", DBG_DYLD_UUID_MAP_A, map_uuid,
547 MAP_LOAD_ADDR, &map_fsid, &map_fsobjid, saw_mapping);
548 expect_dyld_events(s, "unmapping", DBG_DYLD_UUID_UNMAP_A, unmap_uuid,
549 UNMAP_LOAD_ADDR, &unmap_fsid, &unmap_fsobjid, saw_unmapping);
550 expect_dyld_events(s, "shared cache", DBG_DYLD_UUID_SHARED_CACHE_A,
551 sc_uuid, SC_LOAD_ADDR, &sc_fsid, &sc_fsobjid, saw_shared_cache);
552
553 ktrace_set_completion_handler(s, ^{
554 ktrace_session_destroy(s);
555
556 T_EXPECT_EQ(__builtin_popcount(*saw_mapping), DYLD_EVENTS, NULL);
557 T_EXPECT_EQ(__builtin_popcount(*saw_unmapping), DYLD_EVENTS, NULL);
558 T_EXPECT_EQ(__builtin_popcount(*saw_shared_cache), DYLD_EVENTS, NULL);
559 T_END;
560 });
561
562 T_ASSERT_POSIX_ZERO(ktrace_start(s, dispatch_get_main_queue()), NULL);
563
564 info.load_addr = MAP_LOAD_ADDR;
565 memcpy(info.uuid, map_uuid, sizeof(info.uuid));
566 info.fsid = map_fsid;
567 info.fsobjid = map_fsobjid;
568 T_EXPECT_MACH_SUCCESS(task_register_dyld_image_infos(mach_task_self(),
569 &info, 1), "registered dyld image info");
570
571 info.load_addr = UNMAP_LOAD_ADDR;
572 memcpy(info.uuid, unmap_uuid, sizeof(info.uuid));
573 info.fsid = unmap_fsid;
574 info.fsobjid = unmap_fsobjid;
575 T_EXPECT_MACH_SUCCESS(task_unregister_dyld_image_infos(mach_task_self(),
576 &info, 1), "unregistered dyld image info");
577
578 info.load_addr = SC_LOAD_ADDR;
579 memcpy(info.uuid, sc_uuid, sizeof(info.uuid));
580 info.fsid = sc_fsid;
581 info.fsobjid = sc_fsobjid;
582 T_EXPECT_MACH_SUCCESS(task_register_dyld_shared_cache_image_info(
583 mach_task_self(), info, FALSE, FALSE),
584 "registered dyld shared cache image info");
585
586 ktrace_end(s, 0);
587
588 dispatch_main();
589 }
590
591 #pragma mark kdebug kernel macros
592
593 #define EXP_KERNEL_EVENTS 5U
594
595 static const uint32_t dev_evts[EXP_KERNEL_EVENTS] = {
596 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 0),
597 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 1),
598 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 2),
599 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 3),
600 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 4),
601 };
602
603 static const uint32_t rel_evts[EXP_KERNEL_EVENTS] = {
604 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 5),
605 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 6),
606 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 7),
607 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 8),
608 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 9),
609 };
610
611 static const uint32_t filt_evts[EXP_KERNEL_EVENTS] = {
612 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 10),
613 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 11),
614 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 12),
615 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 13),
616 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 14),
617 };
618
619 static const uint32_t noprocfilt_evts[EXP_KERNEL_EVENTS] = {
620 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 15),
621 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 16),
622 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 17),
623 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 18),
624 BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 19),
625 };
626
627 static void
628 expect_event(struct trace_point *tp, const char *name, unsigned int *events,
629 const uint32_t *event_ids, size_t event_ids_len)
630 {
631 unsigned int event_idx = *events;
632 bool event_found = false;
633 size_t i;
634 for (i = 0; i < event_ids_len; i++) {
635 if (event_ids[i] == (tp->debugid & KDBG_EVENTID_MASK)) {
636 T_LOG("found %s event 0x%x", name, tp->debugid);
637 event_found = true;
638 }
639 }
640
641 if (!event_found) {
642 return;
643 }
644
645 *events += 1;
646 for (i = 0; i < event_idx; i++) {
647 T_QUIET; T_EXPECT_EQ(((uint64_t *)&tp->arg1)[i], (uint64_t)i + 1,
648 NULL);
649 }
650 for (; i < 4; i++) {
651 T_QUIET; T_EXPECT_EQ(((uint64_t *)&tp->arg1)[i], (uint64_t)0, NULL);
652 }
653 }
654
655 static void
656 expect_release_event(struct trace_point *tp, unsigned int *events)
657 {
658 expect_event(tp, "release", events, rel_evts,
659 sizeof(rel_evts) / sizeof(rel_evts[0]));
660 }
661
662 static void
663 expect_development_event(struct trace_point *tp, unsigned int *events)
664 {
665 expect_event(tp, "dev", events, dev_evts, sizeof(dev_evts) / sizeof(dev_evts[0]));
666 }
667
668 static void
669 expect_filtered_event(struct trace_point *tp, unsigned int *events)
670 {
671 expect_event(tp, "filtered", events, filt_evts,
672 sizeof(filt_evts) / sizeof(filt_evts[0]));
673 }
674
675 static void
676 expect_noprocfilt_event(struct trace_point *tp, unsigned int *events)
677 {
678 expect_event(tp, "noprocfilt", events, noprocfilt_evts,
679 sizeof(noprocfilt_evts) / sizeof(noprocfilt_evts[0]));
680 }
681
682 static void
683 expect_kdbg_test_events(ktrace_session_t s, bool use_all_callback,
684 void (^cb)(unsigned int dev_seen, unsigned int rel_seen,
685 unsigned int filt_seen, unsigned int noprocfilt_seen))
686 {
687 __block unsigned int dev_seen = 0;
688 __block unsigned int rel_seen = 0;
689 __block unsigned int filt_seen = 0;
690 __block unsigned int noprocfilt_seen = 0;
691
692 void (^evtcb)(struct trace_point *tp) = ^(struct trace_point *tp) {
693 expect_development_event(tp, &dev_seen);
694 expect_release_event(tp, &rel_seen);
695 expect_filtered_event(tp, &filt_seen);
696 expect_noprocfilt_event(tp, &noprocfilt_seen);
697 };
698
699 if (use_all_callback) {
700 ktrace_events_all(s, evtcb);
701 } else {
702 ktrace_events_range(s, KDBG_EVENTID(DBG_BSD, DBG_BSD_KDEBUG_TEST, 0),
703 KDBG_EVENTID(DBG_BSD + 1, 0, 0), evtcb);
704 }
705
706 ktrace_set_completion_handler(s, ^{
707 ktrace_session_destroy(s);
708 cb(dev_seen, rel_seen, filt_seen, noprocfilt_seen);
709 T_END;
710 });
711
712 T_ASSERT_POSIX_ZERO(ktrace_start(s, dispatch_get_main_queue()), NULL);
713 assert_kdebug_test(KDBG_TEST_MACROS);
714
715 ktrace_end(s, 0);
716 }
717
718 T_DECL(kernel_events, "ensure kernel macros work")
719 {
720 start_controlling_ktrace();
721
722 ktrace_session_t s = ktrace_session_create();
723 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "created session");
724
725 T_QUIET; T_ASSERT_POSIX_ZERO(ktrace_filter_pid(s, getpid()),
726 "filtered events to current process");
727
728 expect_kdbg_test_events(s, false,
729 ^(unsigned int dev_seen, unsigned int rel_seen,
730 unsigned int filt_seen, unsigned int noprocfilt_seen) {
731 /*
732 * Development-only events are only filtered if running on an embedded
733 * OS.
734 */
735 unsigned int dev_exp;
736 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
737 dev_exp = is_development_kernel() ? EXP_KERNEL_EVENTS : 0U;
738 #else
739 dev_exp = EXP_KERNEL_EVENTS;
740 #endif
741
742 T_EXPECT_EQ(rel_seen, EXP_KERNEL_EVENTS,
743 "release and development events seen");
744 T_EXPECT_EQ(dev_seen, dev_exp, "development-only events %sseen",
745 dev_exp ? "" : "not ");
746 T_EXPECT_EQ(filt_seen, dev_exp, "filter-only events seen");
747 T_EXPECT_EQ(noprocfilt_seen, EXP_KERNEL_EVENTS,
748 "process filter-agnostic events seen");
749 });
750
751 dispatch_main();
752 }
753
754 T_DECL(kernel_events_filtered, "ensure that the filtered kernel macros work")
755 {
756 start_controlling_ktrace();
757
758 ktrace_session_t s = ktrace_session_create();
759 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "created session");
760
761 T_QUIET; T_ASSERT_POSIX_ZERO(ktrace_filter_pid(s, getpid()),
762 "filtered events to current process");
763
764 expect_kdbg_test_events(s, true,
765 ^(unsigned int dev_seen, unsigned int rel_seen,
766 unsigned int filt_seen, unsigned int noprocfilt_seen) {
767 T_EXPECT_EQ(rel_seen, EXP_KERNEL_EVENTS, NULL);
768 #if defined(__arm__) || defined(__arm64__)
769 T_EXPECT_EQ(dev_seen, is_development_kernel() ? EXP_KERNEL_EVENTS : 0U,
770 NULL);
771 #else
772 T_EXPECT_EQ(dev_seen, EXP_KERNEL_EVENTS,
773 "development-only events seen");
774 #endif /* defined(__arm__) || defined(__arm64__) */
775 T_EXPECT_EQ(filt_seen, 0U, "no filter-only events seen");
776 T_EXPECT_EQ(noprocfilt_seen, EXP_KERNEL_EVENTS,
777 "process filter-agnostic events seen");
778 });
779
780 dispatch_main();
781 }
782
783 T_DECL(kernel_events_noprocfilt,
784 "ensure that the no process filter kernel macros work")
785 {
786 start_controlling_ktrace();
787
788 ktrace_session_t s = ktrace_session_create();
789 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "created session");
790
791 /*
792 * Only allow launchd events through.
793 */
794 T_ASSERT_POSIX_ZERO(ktrace_filter_pid(s, 1), "filtered events to launchd");
795 for (size_t i = 0; i < sizeof(noprocfilt_evts) / sizeof(noprocfilt_evts[0]); i++) {
796 T_QUIET;
797 T_ASSERT_POSIX_ZERO(ktrace_ignore_process_filter_for_event(s,
798 noprocfilt_evts[i]),
799 "ignored process filter for noprocfilt event");
800 }
801
802 expect_kdbg_test_events(s, false,
803 ^(unsigned int dev_seen, unsigned int rel_seen,
804 unsigned int filt_seen, unsigned int noprocfilt_seen) {
805 T_EXPECT_EQ(rel_seen, 0U, "release and development events not seen");
806 T_EXPECT_EQ(dev_seen, 0U, "development-only events not seen");
807 T_EXPECT_EQ(filt_seen, 0U, "filter-only events not seen");
808
809 T_EXPECT_EQ(noprocfilt_seen, EXP_KERNEL_EVENTS,
810 "process filter-agnostic events seen");
811 });
812
813 dispatch_main();
814 }
815
816 static volatile bool continue_abuse = true;
817
818 #define STRESS_DEBUGID (0xfeedfac0)
819 #define ABUSE_SECS (2)
820 #define TIMER_NS (100 * NSEC_PER_USEC)
821 /*
822 * Use the quantum as the gap threshold.
823 */
824 #define GAP_THRESHOLD_NS (10 * NSEC_PER_MSEC)
825
826 static void *
827 kdebug_abuser_thread(void *ctx)
828 {
829 unsigned int id = (unsigned int)ctx;
830 uint64_t i = 0;
831 while (continue_abuse) {
832 kdebug_trace(STRESS_DEBUGID, id, i, 0, 0);
833 i++;
834 }
835
836 return NULL;
837 }
838
839 T_DECL(stress, "emit events on all but one CPU with a small buffer",
840 T_META_CHECK_LEAKS(false))
841 {
842 start_controlling_ktrace();
843
844 T_SETUPBEGIN;
845 ktrace_session_t s = ktrace_session_create();
846 T_WITH_ERRNO; T_QUIET; T_ASSERT_NOTNULL(s, "ktrace_session_create");
847
848 /* Let's not waste any time with pleasantries. */
849 ktrace_set_uuid_map_enabled(s, KTRACE_FEATURE_DISABLED);
850
851 /* Ouch. */
852 ktrace_events_all(s, ^(__unused struct trace_point *tp) {});
853 ktrace_set_vnode_paths_enabled(s, KTRACE_FEATURE_ENABLED);
854 (void)atexit_b(^{ kperf_reset(); });
855 (void)kperf_action_count_set(1);
856 (void)kperf_timer_count_set(1);
857 int kperror = kperf_timer_period_set(0, kperf_ns_to_ticks(TIMER_NS));
858 T_QUIET; T_ASSERT_POSIX_SUCCESS(kperror, "kperf_timer_period_set %llu ns",
859 TIMER_NS);
860 kperror = kperf_timer_action_set(0, 1);
861 T_QUIET; T_ASSERT_POSIX_SUCCESS(kperror, "kperf_timer_action_set");
862 kperror = kperf_action_samplers_set(1, KPERF_SAMPLER_TINFO |
863 KPERF_SAMPLER_TH_SNAPSHOT | KPERF_SAMPLER_KSTACK |
864 KPERF_SAMPLER_USTACK | KPERF_SAMPLER_MEMINFO |
865 KPERF_SAMPLER_TINFO_SCHED | KPERF_SAMPLER_TH_DISPATCH |
866 KPERF_SAMPLER_TK_SNAPSHOT | KPERF_SAMPLER_SYS_MEM |
867 KPERF_SAMPLER_TH_INSTRS_CYCLES);
868 T_QUIET; T_ASSERT_POSIX_SUCCESS(kperror, "kperf_action_samplers_set");
869 /* You monster... */
870
871 /* The coup-de-grace. */
872 ktrace_set_buffer_size(s, 10);
873
874 char filepath_arr[MAXPATHLEN] = "";
875 strlcpy(filepath_arr, dt_tmpdir(), sizeof(filepath_arr));
876 strlcat(filepath_arr, "/stress.ktrace", sizeof(filepath_arr));
877 char *filepath = filepath_arr;
878
879 int ncpus = 0;
880 size_t ncpus_size = sizeof(ncpus);
881 int ret = sysctlbyname("hw.logicalcpu_max", &ncpus, &ncpus_size, NULL, 0);
882 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "sysctlbyname(\"hw.logicalcpu_max\"");
883 T_QUIET; T_ASSERT_GT(ncpus, 0, "realistic number of CPUs");
884
885 pthread_t *threads = calloc((unsigned int)ncpus - 1, sizeof(pthread_t));
886 T_WITH_ERRNO; T_QUIET; T_ASSERT_NOTNULL(threads, "calloc(%d threads)",
887 ncpus - 1);
888
889 ktrace_set_completion_handler(s, ^{
890 T_SETUPBEGIN;
891 ktrace_session_destroy(s);
892
893 T_LOG("trace ended, searching for gaps");
894
895 ktrace_session_t sread = ktrace_session_create();
896 T_WITH_ERRNO; T_QUIET; T_ASSERT_NOTNULL(sread, "ktrace_session_create");
897
898 int error = ktrace_set_file(sread, filepath);
899 T_QUIET; T_ASSERT_POSIX_ZERO(error, "ktrace_set_file %s", filepath);
900
901 ktrace_file_t f = ktrace_file_open(filepath, false);
902 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(f, "ktrace_file_open %s",
903 filepath);
904 uint64_t first_timestamp = 0;
905 error = ktrace_file_earliest_timestamp(f, &first_timestamp);
906 T_QUIET; T_ASSERT_POSIX_ZERO(error, "ktrace_file_earliest_timestamp");
907
908 uint64_t last_timestamp = 0;
909 (void)ktrace_file_latest_timestamp(f, &last_timestamp);
910
911 __block uint64_t prev_timestamp = 0;
912 __block uint64_t nevents = 0;
913 ktrace_events_all(sread, ^(struct trace_point *tp) {
914 nevents++;
915 uint64_t delta_ns = 0;
916 T_QUIET; T_EXPECT_GE(tp->timestamp, prev_timestamp,
917 "timestamps are monotonically increasing");
918 int converror = ktrace_convert_timestamp_to_nanoseconds(sread,
919 tp->timestamp - prev_timestamp, &delta_ns);
920 T_QUIET; T_ASSERT_POSIX_ZERO(converror, "convert timestamp to ns");
921 if (prev_timestamp && delta_ns > GAP_THRESHOLD_NS) {
922 if (tp->debugname) {
923 T_LOG("gap: %gs at %llu - %llu on %d: %s (%#08x)",
924 (double)delta_ns / 1e9, prev_timestamp,
925 tp->timestamp, tp->cpuid, tp->debugname, tp->debugid);
926 } else {
927 T_LOG("gap: %gs at %llu - %llu on %d: %#x",
928 (double)delta_ns / 1e9, prev_timestamp,
929 tp->timestamp, tp->cpuid, tp->debugid);
930 }
931
932 /*
933 * These gaps are ok -- they appear after CPUs are brought back
934 * up.
935 */
936 #define INTERRUPT (0x1050000)
937 #define PERF_CPU_IDLE (0x27001000)
938 #define INTC_HANDLER (0x5000004)
939 #define DECR_TRAP (0x1090000)
940 uint32_t eventid = tp->debugid & KDBG_EVENTID_MASK;
941 if (eventid != INTERRUPT && eventid != PERF_CPU_IDLE &&
942 eventid != INTC_HANDLER && eventid != DECR_TRAP) {
943 unsigned int lost_events = TRACE_LOST_EVENTS;
944 T_QUIET; T_EXPECT_EQ(tp->debugid, lost_events,
945 "gaps should end with lost events");
946 }
947 }
948
949 prev_timestamp = tp->timestamp;
950 });
951 ktrace_events_single(sread, TRACE_LOST_EVENTS, ^(struct trace_point *tp){
952 T_LOG("lost: %llu on %d (%llu)", tp->timestamp, tp->cpuid, tp->arg1);
953 });
954
955 __block uint64_t last_write = 0;
956 ktrace_events_single_paired(sread, TRACE_WRITING_EVENTS,
957 ^(struct trace_point *start, struct trace_point *end) {
958 uint64_t delta_ns;
959 int converror = ktrace_convert_timestamp_to_nanoseconds(sread,
960 start->timestamp - last_write, &delta_ns);
961 T_QUIET; T_ASSERT_POSIX_ZERO(converror, "convert timestamp to ns");
962
963 uint64_t dur_ns;
964 converror = ktrace_convert_timestamp_to_nanoseconds(sread,
965 end->timestamp - start->timestamp, &dur_ns);
966 T_QUIET; T_ASSERT_POSIX_ZERO(converror, "convert timestamp to ns");
967
968 T_LOG("write: %llu (+%gs): %gus on %d: %llu events", start->timestamp,
969 (double)delta_ns / 1e9, (double)dur_ns / 1e3, end->cpuid, end->arg1);
970 last_write = end->timestamp;
971 });
972 ktrace_set_completion_handler(sread, ^{
973 uint64_t duration_ns = 0;
974 if (last_timestamp) {
975 int converror = ktrace_convert_timestamp_to_nanoseconds(sread,
976 last_timestamp - first_timestamp, &duration_ns);
977 T_QUIET; T_ASSERT_POSIX_ZERO(converror,
978 "convert timestamp to ns");
979 T_LOG("file was %gs long, %llu events: %g events/msec/cpu",
980 (double)duration_ns / 1e9, nevents,
981 (double)nevents / ((double)duration_ns / 1e6) / ncpus);
982 }
983 (void)unlink(filepath);
984 ktrace_session_destroy(sread);
985 T_END;
986 });
987
988 int starterror = ktrace_start(sread, dispatch_get_main_queue());
989 T_QUIET; T_ASSERT_POSIX_ZERO(starterror, "ktrace_start read session");
990
991 T_SETUPEND;
992 });
993
994 /* Just kidding... for now. */
995 #if 0
996 kperror = kperf_sample_set(1);
997 T_ASSERT_POSIX_SUCCESS(kperror,
998 "started kperf timer sampling every %llu ns", TIMER_NS);
999 #endif
1000
1001 for (int i = 0; i < (ncpus - 1); i++) {
1002 int error = pthread_create(&threads[i], NULL, kdebug_abuser_thread,
1003 (void *)(uintptr_t)i);
1004 T_QUIET; T_ASSERT_POSIX_ZERO(error,
1005 "pthread_create abuser thread %d", i);
1006 }
1007
1008 int error = ktrace_start_writing_file(s, filepath,
1009 ktrace_compression_none, NULL, NULL);
1010 T_ASSERT_POSIX_ZERO(error, "started writing ktrace to %s", filepath);
1011
1012 T_SETUPEND;
1013
1014 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, ABUSE_SECS * NSEC_PER_SEC),
1015 dispatch_get_main_queue(), ^{
1016 T_LOG("ending trace");
1017 ktrace_end(s, 1);
1018
1019 continue_abuse = false;
1020 for (int i = 0; i < (ncpus - 1); i++) {
1021 int joinerror = pthread_join(threads[i], NULL);
1022 T_QUIET; T_EXPECT_POSIX_ZERO(joinerror, "pthread_join thread %d",
1023 i);
1024 }
1025 });
1026
1027 dispatch_main();
1028 }
1029
1030 #define ROUND_TRIP_PERIOD UINT64_C(10 * 1000)
1031 #define ROUND_TRIPS_THRESHOLD UINT64_C(25)
1032 #define ROUND_TRIPS_TIMEOUT_SECS (2 * 60)
1033 #define COLLECTION_INTERVAL_MS 100
1034
1035 /*
1036 * Test a sustained tracing session, involving multiple round-trips to the
1037 * kernel.
1038 *
1039 * Trace all events, and every `ROUND_TRIP_PERIOD` events, emit an event that's
1040 * unlikely to be emitted elsewhere. Look for this event, too, and make sure we
1041 * see as many of them as we emitted.
1042 *
1043 * After seeing `ROUND_TRIPS_THRESHOLD` of the unlikely events, end tracing.
1044 * In the failure mode, we won't see any of these, so set a timeout of
1045 * `ROUND_TRIPS_TIMEOUT_SECS` to prevent hanging, waiting for events that we'll
1046 * never see.
1047 */
1048 T_DECL(round_trips,
1049 "test sustained tracing with multiple round-trips through the kernel")
1050 {
1051 start_controlling_ktrace();
1052
1053 ktrace_session_t s = ktrace_session_create();
1054 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "created session");
1055
1056 /*
1057 * Set a small buffer and collection interval to increase the number of
1058 * round-trips.
1059 */
1060 ktrace_set_buffer_size(s, 50);
1061 ktrace_set_collection_interval(s, COLLECTION_INTERVAL_MS);
1062
1063 __block uint64_t events = 0;
1064 __block uint64_t emitted = 0;
1065 __block uint64_t seen = 0;
1066 ktrace_events_all(s, ^(__unused struct trace_point *tp) {
1067 events++;
1068 if (events % ROUND_TRIP_PERIOD == 0) {
1069 T_LOG("emitting round-trip event %" PRIu64, emitted);
1070 kdebug_trace(TRACE_DEBUGID, events, 0, 0, 0);
1071 emitted++;
1072 }
1073 });
1074
1075 ktrace_events_single(s, TRACE_DEBUGID, ^(__unused struct trace_point *tp) {
1076 T_LOG("saw round-trip event after %" PRIu64 " events", events);
1077 seen++;
1078 if (seen >= ROUND_TRIPS_THRESHOLD) {
1079 T_LOG("ending trace after seeing %" PRIu64 " events, "
1080 "emitting %" PRIu64, seen, emitted);
1081 ktrace_end(s, 1);
1082 }
1083 });
1084
1085 ktrace_set_completion_handler(s, ^{
1086 T_EXPECT_GE(emitted, ROUND_TRIPS_THRESHOLD,
1087 "emitted %" PRIu64 " round-trip events", emitted);
1088 T_EXPECT_GE(seen, ROUND_TRIPS_THRESHOLD,
1089 "saw %" PRIu64 " round-trip events", seen);
1090 ktrace_session_destroy(s);
1091 T_END;
1092 });
1093
1094 int error = ktrace_start(s, dispatch_get_main_queue());
1095 T_ASSERT_POSIX_ZERO(error, "started tracing");
1096
1097 dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
1098 ROUND_TRIPS_TIMEOUT_SECS * NSEC_PER_SEC), dispatch_get_main_queue(),
1099 ^{
1100 T_LOG("ending trace after %d seconds", ROUND_TRIPS_TIMEOUT_SECS);
1101 ktrace_end(s, 0);
1102 });
1103
1104 dispatch_main();
1105 }
1106
1107 #define HEARTBEAT_INTERVAL_SECS 2
1108 #define HEARTBEAT_COUNT 20
1109
1110 /*
1111 * Ensure we see events periodically, checking for recent events on a
1112 * heart-beat.
1113 */
1114 T_DECL(event_coverage, "ensure events appear up to the end of tracing")
1115 {
1116 start_controlling_ktrace();
1117
1118 ktrace_session_t s = ktrace_session_create();
1119 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "created session");
1120
1121 __block uint64_t current_timestamp = 0;
1122 __block uint64_t events = 0;
1123 ktrace_events_all(s, ^(struct trace_point *tp) {
1124 current_timestamp = tp->timestamp;
1125 events++;
1126 });
1127
1128 ktrace_set_buffer_size(s, 20);
1129 ktrace_set_collection_interval(s, COLLECTION_INTERVAL_MS);
1130
1131 __block uint64_t last_timestamp = 0;
1132 __block uint64_t last_events = 0;
1133 __block unsigned int heartbeats = 0;
1134
1135 ktrace_set_completion_handler(s, ^{
1136 ktrace_session_destroy(s);
1137 T_QUIET; T_EXPECT_GT(events, 0ULL, "should have seen some events");
1138 T_END;
1139 });
1140
1141 dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
1142 0, 0, dispatch_get_main_queue());
1143 dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW,
1144 HEARTBEAT_INTERVAL_SECS * NSEC_PER_SEC),
1145 HEARTBEAT_INTERVAL_SECS * NSEC_PER_SEC, 0);
1146 dispatch_source_set_cancel_handler(timer, ^{
1147 dispatch_release(timer);
1148 });
1149
1150 dispatch_source_set_event_handler(timer, ^{
1151 heartbeats++;
1152
1153 T_LOG("heartbeat %u at time %lld, seen %" PRIu64 " events, "
1154 "current event time %lld", heartbeats, mach_absolute_time(),
1155 events, current_timestamp);
1156
1157 if (current_timestamp > 0) {
1158 T_EXPECT_GT(current_timestamp, last_timestamp,
1159 "event timestamps should be increasing");
1160 T_QUIET; T_EXPECT_GT(events, last_events,
1161 "number of events should be increasing");
1162 }
1163
1164 last_timestamp = current_timestamp;
1165 last_events = events;
1166
1167 if (heartbeats >= HEARTBEAT_COUNT) {
1168 T_LOG("ending trace after %u heartbeats", HEARTBEAT_COUNT);
1169 ktrace_end(s, 0);
1170 }
1171 });
1172
1173 int error = ktrace_start(s, dispatch_get_main_queue());
1174 T_ASSERT_POSIX_ZERO(error, "started tracing");
1175
1176 dispatch_activate(timer);
1177
1178 dispatch_main();
1179 }
1180
1181 static unsigned int
1182 set_nevents(unsigned int nevents)
1183 {
1184 T_QUIET;
1185 T_ASSERT_POSIX_SUCCESS(sysctl(
1186 (int[]){ CTL_KERN, KERN_KDEBUG, KERN_KDSETBUF, (int)nevents }, 4,
1187 NULL, 0, NULL, 0), "set kdebug buffer size");
1188
1189 T_QUIET;
1190 T_ASSERT_POSIX_SUCCESS(sysctl(
1191 (int[]){ CTL_KERN, KERN_KDEBUG, KERN_KDSETUP, (int)nevents }, 4,
1192 NULL, 0, NULL, 0), "setup kdebug buffers");
1193
1194 kbufinfo_t bufinfo = { 0 };
1195 T_QUIET;
1196 T_ASSERT_POSIX_SUCCESS(sysctl(
1197 (int[]){ CTL_KERN, KERN_KDEBUG, KERN_KDGETBUF }, 3,
1198 &bufinfo, &(size_t){ sizeof(bufinfo) }, NULL, 0),
1199 "get kdebug buffer size");
1200
1201 T_QUIET;
1202 T_ASSERT_POSIX_SUCCESS(sysctl(
1203 (int[]){ CTL_KERN, KERN_KDEBUG, KERN_KDREMOVE }, 3,
1204 NULL, 0, NULL, 0),
1205 "remove kdebug buffers");
1206
1207 return (unsigned int)bufinfo.nkdbufs;
1208 }
1209
1210 T_DECL(set_buffer_size, "ensure large buffer sizes can be set")
1211 {
1212 start_controlling_ktrace();
1213
1214 uint64_t memsize = 0;
1215 T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("hw.memsize", &memsize,
1216 &(size_t){ sizeof(memsize) }, NULL, 0), "get memory size");
1217
1218 /*
1219 * Try to allocate up to one-eighth of available memory towards
1220 * tracing.
1221 */
1222 uint64_t maxevents_u64 = memsize / 8 / sizeof(kd_buf);
1223 if (maxevents_u64 > UINT32_MAX) {
1224 maxevents_u64 = UINT32_MAX;
1225 }
1226 unsigned int maxevents = (unsigned int)maxevents_u64;
1227
1228 unsigned int minevents = set_nevents(0);
1229 T_ASSERT_GT(minevents, 0, "saw non-zero minimum event count of %u",
1230 minevents);
1231
1232 unsigned int step = ((maxevents - minevents - 1) / 4);
1233 T_ASSERT_GT(step, 0, "stepping by %u events", step);
1234
1235 for (unsigned int i = minevents + step; i < maxevents; i += step) {
1236 unsigned int actualevents = set_nevents(i);
1237 T_ASSERT_GE(actualevents, i - minevents,
1238 "%u events in kernel when %u requested", actualevents, i);
1239 }
1240 }
1241
1242 static void *
1243 donothing(__unused void *arg)
1244 {
1245 return NULL;
1246 }
1247
1248 T_DECL(long_names, "ensure long command names are reported")
1249 {
1250 start_controlling_ktrace();
1251
1252 char longname[] = "thisisaverylongprocessname!";
1253 char *longname_ptr = longname;
1254 static_assert(sizeof(longname) > 16,
1255 "the name should be longer than MAXCOMLEN");
1256
1257 int ret = sysctlbyname("kern.procname", NULL, NULL, longname,
1258 sizeof(longname));
1259 T_ASSERT_POSIX_SUCCESS(ret,
1260 "use sysctl kern.procname to lengthen the name");
1261
1262 ktrace_session_t ktsess = ktrace_session_create();
1263
1264 /*
1265 * 32-bit kernels can only trace 16 bytes of the string in their event
1266 * arguments.
1267 */
1268 if (!ktrace_is_kernel_64_bit(ktsess)) {
1269 longname[16] = '\0';
1270 }
1271
1272 ktrace_filter_pid(ktsess, getpid());
1273
1274 __block bool saw_newthread = false;
1275 ktrace_events_single(ktsess, TRACE_STRING_NEWTHREAD,
1276 ^(struct trace_point *tp) {
1277 if (ktrace_get_pid_for_thread(ktsess, tp->threadid) ==
1278 getpid()) {
1279 saw_newthread = true;
1280
1281 char argname[32] = {};
1282 strncat(argname, (char *)&tp->arg1, sizeof(tp->arg1));
1283 strncat(argname, (char *)&tp->arg2, sizeof(tp->arg2));
1284 strncat(argname, (char *)&tp->arg3, sizeof(tp->arg3));
1285 strncat(argname, (char *)&tp->arg4, sizeof(tp->arg4));
1286
1287 T_EXPECT_EQ_STR((char *)argname, longname_ptr,
1288 "process name of new thread should be long");
1289
1290 ktrace_end(ktsess, 1);
1291 }
1292 });
1293
1294 ktrace_set_completion_handler(ktsess, ^{
1295 ktrace_session_destroy(ktsess);
1296 T_EXPECT_TRUE(saw_newthread,
1297 "should have seen the new thread");
1298 T_END;
1299 });
1300
1301 int error = ktrace_start(ktsess, dispatch_get_main_queue());
1302 T_ASSERT_POSIX_ZERO(error, "started tracing");
1303
1304 pthread_t thread = NULL;
1305 error = pthread_create(&thread, NULL, donothing, NULL);
1306 T_ASSERT_POSIX_ZERO(error, "create new thread");
1307
1308 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC),
1309 dispatch_get_main_queue(), ^{
1310 ktrace_end(ktsess, 0);
1311 });
1312
1313 error = pthread_join(thread, NULL);
1314 T_ASSERT_POSIX_ZERO(error, "join to thread");
1315
1316 dispatch_main();
1317 }
1318
1319 T_DECL(continuous_time, "make sure continuous time status can be queried",
1320 T_META_RUN_CONCURRENTLY(true))
1321 {
1322 bool cont_time = kdebug_using_continuous_time();
1323 T_ASSERT_FALSE(cont_time, "should not be using continuous time yet");
1324 }
1325
1326 static const uint32_t frame_eventid = KDBG_EVENTID(DBG_BSD,
1327 DBG_BSD_KDEBUG_TEST, 1);
1328
1329 static ktrace_session_t
1330 future_events_session(void)
1331 {
1332 ktrace_session_t ktsess = ktrace_session_create();
1333 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(ktsess, "failed to create session");
1334
1335 ktrace_events_single(ktsess, KDBG_EVENTID(DBG_BSD, DBG_BSD_KDEBUG_TEST, 0),
1336 ^(struct trace_point *tp __unused) {
1337 T_FAIL("saw future test event from IOP");
1338 });
1339 ktrace_events_single(ktsess, frame_eventid, ^(struct trace_point *tp) {
1340 if (tp->debugid & DBG_FUNC_START) {
1341 T_LOG("saw start event");
1342 } else {
1343 T_LOG("saw event traced after trying to trace future event, ending");
1344 ktrace_end(ktsess, 1);
1345 }
1346 });
1347
1348 ktrace_set_collection_interval(ktsess, 100);
1349 return ktsess;
1350 }
1351
1352 T_DECL(future_iop_events,
1353 "make sure IOPs cannot trace events in the future while live tracing")
1354 {
1355 start_controlling_ktrace();
1356 ktrace_session_t ktsess = future_events_session();
1357 ktrace_set_completion_handler(ktsess, ^{
1358 ktrace_session_destroy(ktsess);
1359 T_END;
1360 });
1361
1362 T_ASSERT_POSIX_ZERO(ktrace_start(ktsess, dispatch_get_main_queue()),
1363 "start tracing");
1364 kdebug_trace(frame_eventid | DBG_FUNC_START, 0, 0, 0, 0);
1365 assert_kdebug_test(KDBG_TEST_FUTURE_TIMES);
1366 kdebug_trace(frame_eventid | DBG_FUNC_END, 0, 0, 0, 0);
1367
1368 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC),
1369 dispatch_get_main_queue(), ^{
1370 T_FAIL("ending tracing after timeout");
1371 ktrace_end(ktsess, 0);
1372 });
1373
1374 dispatch_main();
1375 }
1376
1377 T_DECL(future_iop_events_disabled,
1378 "make sure IOPs cannot trace events in the future after disabling tracing")
1379 {
1380 start_controlling_ktrace();
1381 ktrace_session_t ktsess = future_events_session();
1382 T_ASSERT_POSIX_ZERO(ktrace_configure(ktsess), "configure tracing");
1383
1384 kdebug_trace(frame_eventid | DBG_FUNC_START, 0, 0, 0, 0);
1385 assert_kdebug_test(KDBG_TEST_FUTURE_TIMES);
1386 kdebug_trace(frame_eventid | DBG_FUNC_END, 0, 0, 0, 0);
1387
1388 T_ASSERT_POSIX_ZERO(ktrace_disable_configured(ktsess),
1389 "disable tracing");
1390 ktrace_session_destroy(ktsess);
1391
1392 ktsess = future_events_session();
1393 T_QUIET;
1394 T_ASSERT_POSIX_ZERO(ktrace_set_use_existing(ktsess), "use existing trace");
1395 ktrace_set_completion_handler(ktsess, ^{
1396 ktrace_session_destroy(ktsess);
1397 T_END;
1398 });
1399
1400 T_ASSERT_POSIX_ZERO(ktrace_start(ktsess, dispatch_get_main_queue()),
1401 "start tracing existing session");
1402
1403 dispatch_main();
1404 }
1405
1406 T_DECL(iop_events_disable,
1407 "make sure IOP events are flushed before disabling trace")
1408 {
1409 start_controlling_ktrace();
1410 ktrace_session_t ktsess = future_events_session();
1411
1412 assert_kdebug_test(KDBG_TEST_IOP_SYNC_FLUSH);
1413 T_ASSERT_POSIX_ZERO(ktrace_configure(ktsess), "configure tracing");
1414
1415 kdebug_trace(frame_eventid | DBG_FUNC_START, 0, 0, 0, 0);
1416
1417 T_ASSERT_POSIX_ZERO(ktrace_disable_configured(ktsess),
1418 "disable tracing");
1419 ktrace_session_destroy(ktsess);
1420
1421 ktsess = ktrace_session_create();
1422 T_QUIET; T_WITH_ERRNO;
1423 T_ASSERT_NOTNULL(ktsess, "create session");
1424
1425 ktrace_events_single(ktsess,
1426 KDBG_EVENTID(DBG_BSD, DBG_BSD_KDEBUG_TEST, 0xff),
1427 ^(struct trace_point *tp __unused) {
1428 T_PASS("saw IOP event from sync flush");
1429 });
1430
1431 T_QUIET;
1432 T_ASSERT_POSIX_ZERO(ktrace_set_use_existing(ktsess), "use existing trace");
1433 ktrace_set_completion_handler(ktsess, ^{
1434 ktrace_session_destroy(ktsess);
1435 T_END;
1436 });
1437
1438 T_ASSERT_POSIX_ZERO(ktrace_start(ktsess, dispatch_get_main_queue()),
1439 "start tracing existing session");
1440
1441 dispatch_main();
1442 }
1443
1444 T_DECL(lookup_long_paths,
1445 "lookup long path names")
1446 {
1447 start_controlling_ktrace();
1448
1449 int ret = chdir("/tmp");
1450 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "chdir to /tmp");
1451 const char *dir = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/";
1452 int i = 0;
1453 do {
1454 ret = mkdir(dir, S_IRUSR | S_IWUSR | S_IXUSR);
1455 if (ret >= 0 || errno != EEXIST) {
1456 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "mkdir of %d nested directory",
1457 i);
1458 }
1459 ret = chdir(dir);
1460 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "chdir to %d nested directory", i);
1461 } while (i++ < 40);
1462
1463 ktrace_session_t s = ktrace_session_create();
1464 ktrace_set_collection_interval(s, 250);
1465 ktrace_filter_pid(s, getpid());
1466 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "created session");
1467 ktrace_events_single(s, VFS_LOOKUP, ^(struct trace_point *tp __unused){});
1468 ktrace_set_vnode_paths_enabled(s, KTRACE_FEATURE_ENABLED);
1469
1470 dispatch_queue_t q = dispatch_queue_create("com.apple.kdebug-test", 0);
1471
1472 ktrace_set_completion_handler(s, ^{
1473 dispatch_release(q);
1474 T_END;
1475 });
1476
1477 int error = ktrace_start(s, q);
1478 T_ASSERT_POSIX_ZERO(error, "started tracing");
1479
1480 int fd = open("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", O_RDWR | O_CREAT);
1481 T_ASSERT_POSIX_SUCCESS(fd, "opened file at %d directories deep", i);
1482
1483 sleep(5);
1484
1485 T_LOG("ending tracing");
1486 ktrace_end(s, 0);
1487 dispatch_main();
1488 }
1489
1490 #pragma mark - boot tracing
1491
1492 static const char *expected_subsystems[] = {
1493 "tunables", "locks_early", "kprintf", "pmap_steal", "vm_kernel",
1494 "kmem", "kmem_alloc", "zalloc",
1495 /* "percpu", only has a startup phase on Intel */
1496 "locks", "codesigning", "oslog", "early_boot",
1497 };
1498 #define EXPECTED_SUBSYSTEMS_LEN \
1499 (sizeof(expected_subsystems) / sizeof(expected_subsystems[0]))
1500
1501 T_DECL(early_boot_tracing, "ensure early boot strings are present",
1502 T_META_BOOTARGS_SET("trace=100000"))
1503 {
1504 T_ATEND(reset_ktrace);
1505
1506 T_SETUPBEGIN;
1507 ktrace_session_t s = ktrace_session_create();
1508 ktrace_set_collection_interval(s, 250);
1509 int error = ktrace_set_use_existing(s);
1510 T_ASSERT_POSIX_ZERO(error, "use existing trace buffer");
1511
1512 #if defined(__x86_64__)
1513 #define FIRST_EVENT_STRING "i386_init"
1514 #else /* defined(__x86_64__) */
1515 #define FIRST_EVENT_STRING "kernel_startup_bootstrap"
1516 #endif /* !defined(__x86_64__) */
1517
1518 __block bool seen_event = false;
1519 __block unsigned int cur_subsystem = 0;
1520 ktrace_events_single(s, TRACE_INFO_STRING, ^(struct trace_point *tp) {
1521 char early_str[33] = "";
1522 size_t argsize = ktrace_is_kernel_64_bit(s) ? 8 : 4;
1523 memcpy(early_str, &tp->arg1, argsize);
1524 memcpy(early_str + argsize, &tp->arg2, argsize);
1525 memcpy(early_str + argsize * 2, &tp->arg3, argsize);
1526 memcpy(early_str + argsize * 3, &tp->arg4, argsize);
1527
1528 if (!seen_event) {
1529 T_LOG("found first string event with args: "
1530 "0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64,
1531 tp->arg1, tp->arg2, tp->arg3, tp->arg4);
1532 char expect_str[33] = FIRST_EVENT_STRING;
1533 if (!ktrace_is_kernel_64_bit(s)) {
1534 // Only the first 16 bytes of the string will be traced.
1535 expect_str[16] = '\0';
1536 }
1537
1538 T_EXPECT_EQ_STR(early_str, expect_str,
1539 "first event in boot trace should be the bootstrap message");
1540 }
1541 seen_event = true;
1542
1543 if (strcmp(early_str, expected_subsystems[cur_subsystem]) == 0) {
1544 T_LOG("found log for subsystem %s",
1545 expected_subsystems[cur_subsystem]);
1546 cur_subsystem++;
1547 }
1548
1549 if (cur_subsystem == EXPECTED_SUBSYSTEMS_LEN) {
1550 T_LOG("ending after seeing all expected logs");
1551 ktrace_end(s, 1);
1552 }
1553 });
1554
1555 ktrace_set_completion_handler(s, ^{
1556 T_EXPECT_TRUE(seen_event, "should see an early boot string event");
1557 T_EXPECT_TRUE(cur_subsystem == EXPECTED_SUBSYSTEMS_LEN,
1558 "should see logs from all subsystems");
1559 if (cur_subsystem != EXPECTED_SUBSYSTEMS_LEN) {
1560 T_LOG("missing log for %s", expected_subsystems[cur_subsystem]);
1561 }
1562 T_END;
1563 });
1564
1565 error = ktrace_start(s, dispatch_get_main_queue());
1566 T_ASSERT_POSIX_ZERO(error, "started tracing");
1567
1568 T_SETUPEND;
1569
1570 dispatch_main();
1571 }
1572
1573 T_DECL(typefilter_boot_arg, "ensure typefilter is set up correctly at boot",
1574 T_META_BOOTARGS_SET("trace=100000 trace_typefilter=S0x0c00,C0xfe"))
1575 {
1576 T_ATEND(reset_ktrace);
1577
1578 T_SETUPBEGIN;
1579 ktrace_config_t config = ktrace_config_create_current();
1580 T_QUIET; T_WITH_ERRNO;
1581 T_ASSERT_NOTNULL(config, "create config from current system");
1582 T_SETUPEND;
1583
1584 T_LOG("ktrace configuration:");
1585 ktrace_config_print_description(config, stdout);
1586
1587 uint8_t *typefilt = ktrace_config_kdebug_get_typefilter(config);
1588 T_ASSERT_NOTNULL(typefilt, "typefilter is active");
1589 T_EXPECT_TRUE(typefilt[0x0c00 / 8],
1590 "specified subclass is set in typefilter");
1591 T_MAYFAIL; // rdar://63625062 (UTD converts commas in boot-args to spaces)
1592 T_EXPECT_TRUE(typefilt[0xfeed / 8],
1593 "specified class is set in typefilter");
1594
1595 ktrace_config_destroy(config);
1596 }
1597
1598 #pragma mark - events present
1599
1600 static int recvd_sigchild = 0;
1601 static void
1602 sighandler(int sig)
1603 {
1604 if (sig != SIGCHLD) {
1605 T_ASSERT_FAIL("unexpected signal: %d", sig);
1606 }
1607 recvd_sigchild = 1;
1608 }
1609
1610 T_DECL(instrs_and_cycles_on_proc_exit,
1611 "instructions and cycles should be traced on thread exit",
1612 T_META_REQUIRES_SYSCTL_EQ("kern.monotonic.supported", 1))
1613 {
1614 T_SETUPBEGIN;
1615 start_controlling_ktrace();
1616 int error;
1617 struct rusage_info_v4 *rusage = calloc(1, sizeof(*rusage));
1618 char *args[] = { "ls", "-l", NULL, };
1619 int status;
1620 dispatch_queue_t q = dispatch_queue_create("com.apple.kdebug-test",
1621 DISPATCH_QUEUE_SERIAL);
1622 T_QUIET; T_ASSERT_POSIX_SUCCESS(signal(SIGCHLD, sighandler),
1623 "register signal handler");
1624
1625 ktrace_session_t s = ktrace_session_create();
1626 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "ktrace_session_create");
1627
1628 __block pid_t pid;
1629 __block bool seen_event = false;
1630 __block uint64_t proc_instrs = 0;
1631 __block uint64_t proc_cycles = 0;
1632 __block uint64_t proc_sys_time = 0;
1633 __block uint64_t proc_usr_time = 0;
1634 error = ktrace_events_single(s, DBG_MT_INSTRS_CYCLES_PROC_EXIT,
1635 ^(ktrace_event_t tp){
1636 if (tp->pid == pid) {
1637 seen_event = true;
1638 proc_instrs = tp->arg1;
1639 proc_cycles = tp->arg2;
1640 proc_sys_time = tp->arg3;
1641 proc_usr_time = tp->arg4;
1642 ktrace_end(s, 1);
1643 }
1644 });
1645 T_QUIET; T_WITH_ERRNO; T_ASSERT_POSIX_ZERO(error, "trace single event");
1646 ktrace_set_completion_handler(s, ^{
1647 // TODO Check for equality once rdar://61948669 is fixed.
1648 T_ASSERT_GE(proc_instrs, rusage->ri_instructions,
1649 "trace event instrs are >= to rusage instrs");
1650 T_ASSERT_GE(proc_cycles, rusage->ri_cycles,
1651 "trace event cycles are >= to rusage cycles");
1652 T_ASSERT_GE(proc_sys_time, rusage->ri_system_time,
1653 "trace event sys time is >= rusage sys time");
1654 T_ASSERT_GE(proc_usr_time, rusage->ri_user_time,
1655 "trace event usr time >= rusage usr time");
1656 T_EXPECT_TRUE(seen_event, "should see the proc exit trace event");
1657
1658 free(rusage);
1659 ktrace_session_destroy(s);
1660 dispatch_release(q);
1661 T_END;
1662 });
1663 error = ktrace_start(s, q);
1664 T_ASSERT_POSIX_ZERO(error, "start tracing");
1665 T_SETUPEND;
1666
1667 extern char **environ;
1668 status = posix_spawnp(&pid, args[0], NULL, NULL, args, environ);
1669 T_QUIET; T_ASSERT_POSIX_SUCCESS(status, "spawn process");
1670 if (status == 0) {
1671 while (!recvd_sigchild) {
1672 pause();
1673 }
1674 error = proc_pid_rusage(pid, RUSAGE_INFO_V4, (rusage_info_t)rusage);
1675 T_QUIET; T_ASSERT_POSIX_ZERO(error, "rusage");
1676 error = waitpid(pid, &status, 0);
1677 T_QUIET; T_ASSERT_POSIX_SUCCESS(error, "waitpid");
1678 }
1679 dispatch_main();
1680 }
1681
1682 #define NO_OF_THREADS 2
1683
1684 struct thread_counters_info {
1685 uint64_t counts[2]; //cycles and/or instrs
1686 uint64_t cpu_time;
1687 uint64_t thread_id;
1688 };
1689 typedef struct thread_counters_info *tc_info_t;
1690
1691 static void*
1692 get_thread_counters(void* ptr)
1693 {
1694 extern int thread_selfcounts(int type, void *buf, size_t nbytes);
1695 extern uint64_t __thread_selfusage(void);
1696 extern uint64_t __thread_selfid(void);
1697 tc_info_t tc_info = (tc_info_t) ptr;
1698 tc_info->thread_id = __thread_selfid();
1699 // Just to increase the instr, cycle count
1700 T_LOG("printing %llu\n", tc_info->thread_id);
1701 tc_info->cpu_time = __thread_selfusage();
1702 thread_selfcounts(1, tc_info->counts, sizeof(tc_info->counts));
1703 return NULL;
1704 }
1705
1706 T_DECL(instrs_and_cycles_on_thread_exit,
1707 "instructions and cycles should be traced on thread exit",
1708 T_META_REQUIRES_SYSCTL_EQ("kern.monotonic.supported", 1))
1709 {
1710 T_SETUPBEGIN;
1711 start_controlling_ktrace();
1712
1713 int error;
1714 pthread_t *threads = calloc((unsigned int)(NO_OF_THREADS),
1715 sizeof(pthread_t));
1716 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(threads, "calloc(%d threads)",
1717 NO_OF_THREADS);
1718 tc_info_t tc_infos = calloc((unsigned int) (NO_OF_THREADS),
1719 sizeof(struct thread_counters_info));
1720 T_WITH_ERRNO; T_QUIET; T_ASSERT_NOTNULL(tc_infos,
1721 "calloc(%d thread counters)", NO_OF_THREADS);
1722
1723 ktrace_session_t s = ktrace_session_create();
1724 T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "ktrace_session_create");
1725 ktrace_filter_pid(s, getpid());
1726
1727 __block int nevents = 0;
1728 error = ktrace_events_single(s, DBG_MT_INSTRS_CYCLES_THR_EXIT,
1729 ^(ktrace_event_t tp) {
1730 for (int i = 0; i < NO_OF_THREADS; i++) {
1731 if (tp->threadid == tc_infos[i].thread_id) {
1732 nevents++;
1733 uint64_t cpu_time = tp->arg3 + tp->arg4;
1734 /*
1735 * as we are getting counts before thread exit,
1736 * the counts at thread exit should be greater than
1737 * thread_selfcounts
1738 */
1739 T_ASSERT_GE(tp->arg1, tc_infos[i].counts[0],
1740 "trace event instrs are >= to thread's instrs");
1741 T_ASSERT_GE(tp->arg2, tc_infos[i].counts[1],
1742 "trace event cycles are >= to thread's cycles");
1743 T_ASSERT_GE(cpu_time, tc_infos[i].cpu_time,
1744 "trace event cpu time is >= thread's cpu time");
1745 }
1746 if (nevents == NO_OF_THREADS) {
1747 ktrace_end(s, 1);
1748 }
1749 }
1750 });
1751 T_QUIET; T_ASSERT_POSIX_ZERO(error, "trace single event");
1752 ktrace_set_completion_handler(s, ^{
1753 T_EXPECT_EQ(NO_OF_THREADS, nevents, "seen %d thread exit trace events",
1754 NO_OF_THREADS);
1755 free(tc_infos);
1756 ktrace_session_destroy(s);
1757 T_END;
1758 });
1759 error = ktrace_start(s, dispatch_get_main_queue());
1760 T_ASSERT_POSIX_ZERO(error, "start tracing");
1761
1762 for (int i = 0; i < NO_OF_THREADS; i++) {
1763 error = pthread_create(&threads[i], NULL, get_thread_counters,
1764 (void *)&tc_infos[i]);
1765 T_QUIET; T_ASSERT_POSIX_ZERO(error, "pthread_create thread %d", i);
1766 }
1767 T_SETUPEND;
1768 for (int i = 0; i < NO_OF_THREADS; i++) {
1769 error = pthread_join(threads[i], NULL);
1770 T_QUIET; T_EXPECT_POSIX_ZERO(error, "pthread_join thread %d", i);
1771 }
1772
1773 dispatch_main();
1774 }