1 #include <CoreSymbolication/CoreSymbolication.h>
2 #include <darwintest.h>
3 #include <dispatch/dispatch.h>
6 #include <sys/sysctl.h>
8 #define USER_FRAMES (12)
10 #define NON_RECURSE_FRAMES (5)
12 static const char *user_bt
[USER_FRAMES
] = {
15 "recurse_a", "recurse_b", "recurse_a", "recurse_b",
16 "recurse_a", "recurse_b", "recurse_a",
21 expect_frame(const char **bt
, unsigned int bt_len
, CSSymbolRef symbol
,
22 unsigned long addr
, unsigned int bt_idx
, unsigned int max_frames
)
25 unsigned int frame_idx
= max_frames
- bt_idx
- 1;
27 if (bt
[frame_idx
] == NULL
) {
28 T_LOG("frame %2u: skipping system frame", frame_idx
);
32 if (CSIsNull(symbol
)) {
33 T_FAIL("invalid symbol for address %#lx at frame %d", addr
, frame_idx
);
37 if (frame_idx
>= bt_len
) {
38 T_FAIL("unexpected frame '%s' (%#lx) at index %u",
39 CSSymbolGetName(symbol
), addr
, frame_idx
);
43 name
= CSSymbolGetName(symbol
);
44 T_QUIET
; T_ASSERT_NOTNULL(name
, NULL
);
45 T_EXPECT_EQ_STR(name
, bt
[frame_idx
],
46 "frame %2u: saw '%s', expected '%s'",
47 frame_idx
, name
, bt
[frame_idx
]);
50 static void __attribute__((noinline
,not_tail_called
))
53 uint64_t bt
[USER_FRAMES
] = { 0 };
54 unsigned int bt_len
= USER_FRAMES
;
58 static dispatch_once_t expect_stacks_once
;
60 static CSSymbolicatorRef user_symb
;
62 dispatch_once(&expect_stacks_once
, ^(void) {
64 int mib
[] = { CTL_KERN
, KERN_PROC
, KERN_PROC_PID
, 0 /* kernproc */ };
70 errb
= sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), &kp
, &len
, NULL
, 0);
71 T_QUIET
; T_ASSERT_POSIX_SUCCESS(errb
,
72 "sysctl({ CTL_KERN, KERN_PROC, KERN_PROC_PID, 0})");
74 k64
= kp
.kp_proc
.p_flag
& P_LP64
;
75 T_LOG("executing with a %s-bit kernel", k64
? "64" : "32");
77 user_symb
= CSSymbolicatorCreateWithTask(mach_task_self());
78 T_QUIET
; T_ASSERT_FALSE(CSIsNull(user_symb
), NULL
);
79 T_QUIET
; T_ASSERT_TRUE(CSSymbolicatorIsTaskValid(user_symb
), NULL
);
82 bt_filled
= USER_FRAMES
;
83 err
= sysctlbyname("kern.backtrace.user", bt
, &bt_filled
, NULL
, 0);
85 T_SKIP("release kernel: kern.backtrace.user sysctl returned ENOENT");
87 T_ASSERT_POSIX_SUCCESS(err
, "sysctlbyname(\"kern.backtrace.user\")");
89 bt_len
= (unsigned int)bt_filled
;
90 T_EXPECT_EQ(bt_len
, (unsigned int)USER_FRAMES
,
91 "%u frames should be present in backtrace", (unsigned int)USER_FRAMES
);
93 for (unsigned int i
= 0; i
< bt_len
; i
++) {
95 #if !defined(__LP64__)
97 * Backtrace frames come out as kernel words; convert them back to user
98 * uintptr_t for 32-bit processes.
101 addr
= (uintptr_t)(bt
[i
]);
103 addr
= (uintptr_t)(((uint32_t *)bt
)[i
]);
105 #else /* defined(__LP32__) */
106 addr
= (uintptr_t)bt
[i
];
107 #endif /* defined(__LP32__) */
109 CSSymbolRef symbol
= CSSymbolicatorGetSymbolWithAddressAtTime(
110 user_symb
, addr
, kCSNow
);
111 expect_frame(user_bt
, USER_FRAMES
, symbol
, addr
, i
, bt_len
);
115 static int __attribute__((noinline
,not_tail_called
))
116 recurse_a(unsigned int frames
);
117 static int __attribute__((noinline
,not_tail_called
))
118 recurse_b(unsigned int frames
);
120 static int __attribute__((noinline
,not_tail_called
))
121 recurse_a(unsigned int frames
)
129 return recurse_b(frames
- 1) + 1;
132 static int __attribute__((noinline
,not_tail_called
))
133 recurse_b(unsigned int frames
)
141 return recurse_a(frames
- 1) + 1;
145 backtrace_thread(void *arg
)
151 * backtrace_thread, recurse_a, recurse_b, ..., __sysctlbyname
153 * Always make one less call for this frame (backtrace_thread).
155 calls
= USER_FRAMES
- NON_RECURSE_FRAMES
;
157 T_LOG("backtrace thread calling into %d frames (already at %d frames)",
158 calls
, NON_RECURSE_FRAMES
);
159 (void)recurse_a(calls
);
163 T_DECL(backtrace_user
, "test that the kernel can backtrace user stacks",
164 T_META_CHECK_LEAKS(false), T_META_ALL_VALID_ARCHS(true))
168 T_QUIET
; T_ASSERT_POSIX_ZERO(pthread_create(&thread
, NULL
, backtrace_thread
,
169 NULL
), "create additional thread to backtrace");
171 T_QUIET
; T_ASSERT_POSIX_ZERO(pthread_join(thread
, NULL
), NULL
);