1 /* Copyright (c) 2018-2019 Apple Inc. All rights reserved. */
3 #include <CoreSymbolication/CoreSymbolication.h>
4 #include <darwintest.h>
5 #include <dispatch/dispatch.h>
6 #include <kperf/kperf.h>
7 #include <ktrace/session.h>
8 #include <ktrace/private.h>
9 #include <System/sys/kdebug.h>
12 #include "kperf_helpers.h"
13 #include "ktrace_helpers.h"
15 #define PERF_STK_KHDR UINT32_C(0x25020014)
16 #define PERF_STK_UHDR UINT32_C(0x25020018)
17 #define PERF_STK_KDATA UINT32_C(0x2502000c)
18 #define PERF_STK_UDATA UINT32_C(0x25020010)
20 #define CALLSTACK_VALID 0x1
21 #define CALLSTACK_TRUNCATED 0x10
24 T_META_NAMESPACE("xnu.ktrace"),
25 T_META_CHECK_LEAKS(false));
28 expect_frame(const char **bt
, unsigned int bt_len
, CSSymbolRef symbol
,
29 uint64_t addr
, unsigned int bt_idx
, unsigned int max_frames
)
32 unsigned int frame_idx
= max_frames
- bt_idx
- 1;
35 T_LOG("frame %2u: skipping system frame '%s'", frame_idx
,
36 CSSymbolGetName(symbol
));
40 T_LOG("checking frame %d: %llx", bt_idx
, addr
);
41 T_ASSERT_FALSE(CSIsNull(symbol
), "invalid symbol for return address");
43 if (frame_idx
>= bt_len
) {
44 T_FAIL("unexpected frame '%s' (%#" PRIx64
") at index %u",
45 CSSymbolGetName(symbol
), addr
, frame_idx
);
49 name
= CSSymbolGetName(symbol
);
50 T_QUIET
; T_ASSERT_NOTNULL(name
, NULL
);
51 T_EXPECT_EQ_STR(name
, bt
[frame_idx
],
52 "frame %2u: saw '%s', expected '%s'",
53 frame_idx
, name
, bt
[frame_idx
]);
57 * Expect to see either user or kernel stacks on thread with ID `tid` with a
58 * signature of `bt` of length `bt_len`. Updates `stacks_seen` when stack
61 * Can also allow stacks to be larger than the signature -- additional frames
62 * near the current PC will be ignored. This allows stacks to potentially be
63 * in the middle of a signalling system call (which signals that it is safe to
67 expect_backtrace(ktrace_session_t s
, uint64_t tid
, unsigned int *stacks_seen
,
68 bool kern
, const char **bt
, unsigned int bt_len
, unsigned int allow_larger_by
)
70 CSSymbolicatorRef symb
;
72 uint32_t data_debugid
;
73 __block
unsigned int stacks
= 0;
74 __block
unsigned int frames
= 0;
75 __block
unsigned int hdr_frames
= 0;
76 __block
unsigned int allow_larger
= allow_larger_by
;
81 static CSSymbolicatorRef kern_symb
;
82 static dispatch_once_t kern_symb_once
;
84 hdr_debugid
= PERF_STK_KHDR
;
85 data_debugid
= PERF_STK_KDATA
;
87 dispatch_once(&kern_symb_once
, ^(void) {
88 kern_symb
= CSSymbolicatorCreateWithMachKernel();
89 T_QUIET
; T_ASSERT_FALSE(CSIsNull(kern_symb
), NULL
);
93 static CSSymbolicatorRef user_symb
;
94 static dispatch_once_t user_symb_once
;
96 hdr_debugid
= PERF_STK_UHDR
;
97 data_debugid
= PERF_STK_UDATA
;
99 dispatch_once(&user_symb_once
, ^(void) {
100 user_symb
= CSSymbolicatorCreateWithTask(mach_task_self());
101 T_QUIET
; T_ASSERT_FALSE(CSIsNull(user_symb
), NULL
);
102 T_QUIET
; T_ASSERT_TRUE(CSSymbolicatorIsTaskValid(user_symb
), NULL
);
107 ktrace_events_single(s
, hdr_debugid
, ^(struct trace_point
*tp
) {
108 if (tid
!= 0 && tid
!= tp
->threadid
) {
112 T_LOG("found %s stack from thread %#" PRIx64
, kern
? "kernel" : "user",
115 if (!(tp
->arg1
& 1)) {
116 T_FAIL("invalid %s stack on thread %#" PRIx64
,
117 kern
? "kernel" : "user", tp
->threadid
);
121 hdr_frames
= (unsigned int)tp
->arg2
;
122 /* ignore extra link register or value pointed to by stack pointer */
125 T_QUIET
; T_EXPECT_GE(hdr_frames
, bt_len
,
126 "number of frames in header");
127 T_QUIET
; T_EXPECT_LE(hdr_frames
, bt_len
+ allow_larger
,
128 "number of frames in header");
129 if (hdr_frames
> bt_len
&& allow_larger
> 0) {
130 allow_larger
= hdr_frames
- bt_len
;
134 T_LOG("%s stack seen", kern
? "kernel" : "user");
138 ktrace_events_single(s
, data_debugid
, ^(struct trace_point
*tp
) {
139 if (tid
!= 0 && tid
!= tp
->threadid
) {
145 if (frames
== 0 && hdr_frames
> bt_len
) {
146 /* skip frames near the PC */
147 i
= (int)allow_larger
;
151 for (; i
< 4 && frames
< hdr_frames
; i
++, frames
++) {
152 uint64_t addr
= (&tp
->arg1
)[i
];
153 CSSymbolRef symbol
= CSSymbolicatorGetSymbolWithAddressAtTime(
156 expect_frame(bt
, bt_len
, symbol
, addr
, frames
, hdr_frames
);
159 /* saw the end of the user stack */
160 if (hdr_frames
== frames
) {
171 #define TRIGGERING_DEBUGID (0xfeff0f00)
174 * These functions must return an int to avoid the function prologue being
175 * hoisted out of the path to the spin (breaking being able to get a good
178 static int __attribute__((noinline
, not_tail_called
))
179 recurse_a(dispatch_semaphore_t spinning
, unsigned int frames
);
180 static int __attribute__((noinline
, not_tail_called
))
181 recurse_b(dispatch_semaphore_t spinning
, unsigned int frames
);
183 static int __attribute__((noinline
, not_tail_called
))
184 recurse_a(dispatch_semaphore_t spinning
, unsigned int frames
)
188 dispatch_semaphore_signal(spinning
);
193 kdebug_trace(TRIGGERING_DEBUGID
, 0, 0, 0, 0);
198 return recurse_b(spinning
, frames
- 1) + 1;
201 static int __attribute__((noinline
, not_tail_called
))
202 recurse_b(dispatch_semaphore_t spinning
, unsigned int frames
)
206 dispatch_semaphore_signal(spinning
);
211 kdebug_trace(TRIGGERING_DEBUGID
, 0, 0, 0, 0);
216 return recurse_a(spinning
, frames
- 1) + 1;
219 #define USER_FRAMES (12)
221 #if defined(__x86_64__)
223 #define RECURSE_START_OFFSET (3)
225 #else /* defined(__x86_64__) */
227 #define RECURSE_START_OFFSET (2)
229 #endif /* !defined(__x86_64__) */
231 static const char *user_bt
[USER_FRAMES
] = {
232 #if defined(__x86_64__)
234 * x86_64 has an extra "thread_start" frame here.
237 #endif /* defined(__x86_64__) */
240 "recurse_a", "recurse_b", "recurse_a", "recurse_b",
241 "recurse_a", "recurse_b", "recurse_a", "recurse_b",
242 #if !defined(__x86_64__)
244 * Pick up the slack to make the number of frames constant.
247 #endif /* !defined(__x86_64__) */
253 #define KERNEL_FRAMES (2)
254 static const char *kernel_bt
[KERNEL_FRAMES
] = {
255 "unix_syscall", "kdebug_trace64"
258 #elif defined(__arm64__)
260 #define KERNEL_FRAMES (4)
261 static const char *kernel_bt
[KERNEL_FRAMES
] = {
262 "fleh_synchronous", "sleh_synchronous", "unix_syscall", "kdebug_trace64"
265 #elif defined(__x86_64__)
267 #define KERNEL_FRAMES (2)
268 static const char *kernel_bt
[KERNEL_FRAMES
] = {
269 "unix_syscall64", "kdebug_trace64"
273 #error "architecture unsupported"
274 #endif /* defined(__arm__) */
276 static dispatch_once_t backtrace_once
;
277 static dispatch_semaphore_t backtrace_started
;
278 static dispatch_semaphore_t backtrace_go
;
281 * Another thread to run with a known backtrace.
283 * Take a semaphore that will be signalled when the thread is spinning at the
284 * correct frame. If the semaphore is NULL, don't spin and instead make a
285 * kdebug_trace system call, which can trigger a deterministic backtrace itself.
288 backtrace_thread(void *arg
)
290 dispatch_semaphore_t notify_spinning
;
293 notify_spinning
= (dispatch_semaphore_t
)arg
;
295 dispatch_semaphore_signal(backtrace_started
);
296 if (!notify_spinning
) {
297 dispatch_semaphore_wait(backtrace_go
, DISPATCH_TIME_FOREVER
);
301 * backtrace_thread, recurse_a, recurse_b, ...[, __kdebug_trace64]
303 * Always make one less call for this frame (backtrace_thread).
305 calls
= USER_FRAMES
- RECURSE_START_OFFSET
- 1 /* backtrace_thread */;
306 if (notify_spinning
) {
308 * Spinning doesn't end up calling __kdebug_trace64.
313 T_LOG("backtrace thread calling into %d frames (already at %d frames)",
314 calls
, RECURSE_START_OFFSET
);
315 (void)recurse_a(notify_spinning
, calls
);
320 create_backtrace_thread(void *(*thread_fn
)(void *),
321 dispatch_semaphore_t notify_spinning
)
323 pthread_t thread
= NULL
;
326 dispatch_once(&backtrace_once
, ^{
327 backtrace_started
= dispatch_semaphore_create(0);
328 T_QUIET
; T_ASSERT_NOTNULL(backtrace_started
, NULL
);
330 if (!notify_spinning
) {
331 backtrace_go
= dispatch_semaphore_create(0);
332 T_QUIET
; T_ASSERT_NOTNULL(backtrace_go
, NULL
);
336 T_QUIET
; T_ASSERT_POSIX_ZERO(pthread_create(&thread
, NULL
, thread_fn
,
337 (void *)notify_spinning
), NULL
);
338 T_QUIET
; T_ASSERT_NOTNULL(thread
, "backtrace thread created");
339 dispatch_semaphore_wait(backtrace_started
, DISPATCH_TIME_FOREVER
);
341 T_QUIET
; T_ASSERT_POSIX_ZERO(pthread_threadid_np(thread
, &tid
), NULL
);
342 T_QUIET
; T_ASSERT_NE(tid
, UINT64_C(0),
343 "backtrace thread created does not have ID 0");
345 T_LOG("starting thread with ID 0x%" PRIx64
, tid
);
351 start_backtrace_thread(void)
353 T_QUIET
; T_ASSERT_NOTNULL(backtrace_go
,
354 "thread to backtrace created before starting it");
355 dispatch_semaphore_signal(backtrace_go
);
359 #define TEST_TIMEOUT_NS (30 * NSEC_PER_SEC)
360 #else /* TARGET_OS_WATCH */
361 #define TEST_TIMEOUT_NS (5 * NSEC_PER_SEC)
362 #endif /* !TARGET_OS_WATCH */
364 T_DECL(kperf_stacks_kdebug_trig
,
365 "test that backtraces from kdebug trigger are correct",
368 static unsigned int stacks_seen
= 0;
370 kperf_kdebug_filter_t filter
;
373 start_controlling_ktrace();
375 s
= ktrace_session_create();
376 T_ASSERT_NOTNULL(s
, "ktrace session was created");
378 ktrace_set_collection_interval(s
, 100);
380 T_ASSERT_POSIX_ZERO(ktrace_filter_pid(s
, getpid()), NULL
);
382 tid
= create_backtrace_thread(backtrace_thread
, NULL
);
383 expect_backtrace(s
, tid
, &stacks_seen
, false, user_bt
, USER_FRAMES
, 0);
384 expect_backtrace(s
, tid
, &stacks_seen
, true, kernel_bt
, KERNEL_FRAMES
, 0);
387 * The triggering event must be traced (and thus registered with libktrace)
390 ktrace_events_single(s
, TRIGGERING_DEBUGID
,
391 ^(__unused
struct trace_point
*tp
){ });
393 ktrace_set_completion_handler(s
, ^(void) {
394 T_EXPECT_GE(stacks_seen
, 2U, "saw both kernel and user stacks");
395 ktrace_session_destroy(s
);
400 filter
= kperf_kdebug_filter_create();
401 T_ASSERT_NOTNULL(filter
, "kperf kdebug filter was created");
403 T_QUIET
; T_ASSERT_POSIX_SUCCESS(kperf_kdebug_filter_add_debugid(filter
,
404 TRIGGERING_DEBUGID
), NULL
);
405 T_QUIET
; T_ASSERT_POSIX_SUCCESS(kperf_kdebug_filter_set(filter
), NULL
);
406 (void)kperf_action_count_set(1);
407 T_QUIET
; T_ASSERT_POSIX_SUCCESS(kperf_action_samplers_set(1,
408 KPERF_SAMPLER_USTACK
| KPERF_SAMPLER_KSTACK
), NULL
);
409 T_QUIET
; T_ASSERT_POSIX_SUCCESS(kperf_kdebug_action_set(1), NULL
);
410 kperf_kdebug_filter_destroy(filter
);
412 T_ASSERT_POSIX_SUCCESS(kperf_sample_set(1), NULL
);
414 T_ASSERT_POSIX_ZERO(ktrace_start(s
, dispatch_get_main_queue()), NULL
);
416 start_backtrace_thread();
418 dispatch_after(dispatch_time(DISPATCH_TIME_NOW
, TEST_TIMEOUT_NS
),
419 dispatch_get_main_queue(), ^(void)
421 T_LOG("ending test after timeout");
428 T_DECL(kperf_ustack_timer
,
429 "test that user backtraces on a timer are correct",
432 static unsigned int stacks_seen
= 0;
435 dispatch_semaphore_t wait_for_spinning
= dispatch_semaphore_create(0);
437 start_controlling_ktrace();
439 s
= ktrace_session_create();
440 T_QUIET
; T_ASSERT_NOTNULL(s
, "ktrace_session_create");
442 ktrace_set_collection_interval(s
, 100);
444 ktrace_filter_pid(s
, getpid());
446 configure_kperf_stacks_timer(getpid(), 10, false);
448 tid
= create_backtrace_thread(backtrace_thread
, wait_for_spinning
);
449 /* potentially calling dispatch function and system call */
450 expect_backtrace(s
, tid
, &stacks_seen
, false, user_bt
, USER_FRAMES
- 1, 2);
452 ktrace_set_completion_handler(s
, ^(void) {
453 T_EXPECT_GE(stacks_seen
, 1U, "saw at least one stack");
454 ktrace_session_destroy(s
);
459 T_QUIET
; T_ASSERT_POSIX_SUCCESS(kperf_sample_set(1), NULL
);
461 /* wait until the thread that will be backtraced is spinning */
462 dispatch_semaphore_wait(wait_for_spinning
, DISPATCH_TIME_FOREVER
);
464 T_ASSERT_POSIX_ZERO(ktrace_start(s
, dispatch_get_main_queue()), NULL
);
466 dispatch_after(dispatch_time(DISPATCH_TIME_NOW
, TEST_TIMEOUT_NS
),
467 dispatch_get_main_queue(), ^(void)
469 T_LOG("ending test after timeout");
476 static volatile bool spin
= true;
478 __attribute__((noinline
, not_tail_called
))
480 recurse_spin(dispatch_semaphore_t notify_sema
, int depth
)
483 recurse_spin(notify_sema
, depth
- 1);
485 dispatch_semaphore_signal(notify_sema
);
491 spin_thread(void *arg
)
493 dispatch_semaphore_t notify_sema
= arg
;
494 dispatch_semaphore_signal(backtrace_started
);
495 recurse_spin(notify_sema
, 257);
499 T_DECL(kperf_ustack_trunc
, "ensure stacks are marked as truncated")
501 start_controlling_ktrace();
503 ktrace_session_t s
= ktrace_session_create();
504 T_ASSERT_NOTNULL(s
, "ktrace session was created");
506 ktrace_set_collection_interval(s
, 100);
509 T_ASSERT_POSIX_ZERO(ktrace_filter_pid(s
, getpid()), NULL
);
511 configure_kperf_stacks_timer(getpid(), 10, false);
513 __block
bool saw_stack
= false;
514 ktrace_set_completion_handler(s
, ^{
515 T_EXPECT_TRUE(saw_stack
, "saw the user stack");
519 dispatch_semaphore_t notify_sema
= dispatch_semaphore_create(0);
520 uint64_t tid
= create_backtrace_thread(spin_thread
, notify_sema
);
522 ktrace_events_single(s
, PERF_STK_UHDR
, ^(struct trace_point
*tp
) {
523 if (tp
->threadid
!= tid
) {
526 T_LOG("found %llu frame stack", tp
->arg2
);
527 T_EXPECT_BITS_SET(tp
->arg1
, CALLSTACK_VALID
,
528 "found valid callstack");
529 T_EXPECT_BITS_SET(tp
->arg1
, CALLSTACK_TRUNCATED
,
530 "found truncated callstack");
535 T_QUIET
; T_ASSERT_POSIX_SUCCESS(kperf_sample_set(1), NULL
);
537 T_ASSERT_POSIX_ZERO(ktrace_start(s
, dispatch_get_main_queue()),
540 dispatch_after(dispatch_time(DISPATCH_TIME_NOW
, TEST_TIMEOUT_NS
),
541 dispatch_get_main_queue(), ^(void)
543 T_LOG("ending test after timeout");
550 T_DECL(kperf_ustack_maxlen
, "ensure stacks up to 256 frames can be captured")
552 start_controlling_ktrace();
554 ktrace_session_t s
= ktrace_session_create();
555 T_ASSERT_NOTNULL(s
, "ktrace session was created");
557 ktrace_set_collection_interval(s
, 100);
560 T_ASSERT_POSIX_ZERO(ktrace_filter_pid(s
, getpid()), NULL
);
562 configure_kperf_stacks_timer(getpid(), 10, false);
564 __block
bool saw_stack
= false;
565 __block
bool saw_stack_data
= false;
566 __block
uint64_t nevents
= 0;
567 ktrace_set_completion_handler(s
, ^{
568 T_EXPECT_TRUE(saw_stack
, "saw the user stack");
569 T_LOG("saw %" PRIu64
" stack data events", nevents
);
570 T_EXPECT_TRUE(saw_stack_data
, "saw all frames of the user stack");
574 dispatch_semaphore_t notify_sema
= dispatch_semaphore_create(0);
575 uint64_t tid
= create_backtrace_thread(spin_thread
, notify_sema
);
577 ktrace_events_single(s
, PERF_STK_UHDR
, ^(struct trace_point
*tp
) {
578 if (tp
->threadid
!= tid
) {
581 T_LOG("found %llu frame stack", tp
->arg2
);
582 T_EXPECT_BITS_SET(tp
->arg1
, CALLSTACK_VALID
,
583 "found valid callstack");
584 T_EXPECT_EQ(tp
->arg2
, UINT64_C(256),
585 "found the correct number of frames");
589 ktrace_events_single(s
, PERF_STK_UDATA
, ^(struct trace_point
*tp
) {
590 if (tp
->threadid
!= tid
&& !saw_stack
) {
594 if (nevents
== 256 / 4) {
597 saw_stack_data
= true;
600 T_QUIET
; T_ASSERT_POSIX_SUCCESS(kperf_sample_set(1), NULL
);
602 T_ASSERT_POSIX_ZERO(ktrace_start(s
, dispatch_get_main_queue()),
605 dispatch_after(dispatch_time(DISPATCH_TIME_NOW
, TEST_TIMEOUT_NS
),
606 dispatch_get_main_queue(), ^(void)
608 T_LOG("ending test after timeout");
615 /* TODO test kernel stacks in all modes */
616 /* TODO legacy PET mode backtracing */