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