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