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