• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3  * Copyright (C) 2020, VMware, Tzvetomir Stoyanov <tz.stoyanov@gmail.com>
4  *
5  */
6 #define _LARGEFILE64_SOURCE
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include <time.h>
14 #include <dirent.h>
15 #include <ftw.h>
16 #include <ctype.h>
17 #include <libgen.h>
18 #include <kbuffer.h>
19 #include <pthread.h>
20 
21 #include <sys/mount.h>
22 #include <sys/syscall.h>
23 
24 #include <CUnit/CUnit.h>
25 #include <CUnit/Basic.h>
26 
27 #include "tracefs.h"
28 
29 #define gettid() syscall(__NR_gettid)
30 
31 #ifndef PATH_MAX
32 #define PATH_MAX 1024
33 #endif
34 
35 #define TRACEFS_SUITE		"tracefs library"
36 #define TEST_INSTANCE_NAME	"cunit_test_iter"
37 #define TEST_TRACE_DIR		"/tmp/trace_utest.XXXXXX"
38 #define TEST_ARRAY_SIZE		5000
39 
40 #define ALL_TRACERS	"available_tracers"
41 #define CUR_TRACER	"current_tracer"
42 #define PER_CPU		"per_cpu"
43 #define TRACE_ON	"tracing_on"
44 #define TRACE_CLOCK	"trace_clock"
45 
46 /* Used to insert sql types and actions, must be big enough to hold them */
47 #define SQL_REPLACE	"RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"
48 
49 #define SQL_1_EVENT	"wakeup_1"
50 #define SQL_1_SQL	"select sched_switch.next_pid as woke_pid, sched_waking.common_pid as waking_pid from sched_waking join sched_switch on sched_switch.next_pid = sched_waking.pid"
51 #define SQL_1_MATCH	"echo 's:wakeup_1 pid_t woke_pid; s32 waking_pid;' >> /sys/kernel/tracing/dynamic_events\n" \
52 			"echo 'hist:keys=pid:__arg_XXXXXXXX_1=common_pid' >> /sys/kernel/tracing/events/sched/sched_waking/trigger\n" \
53 			"echo 'hist:keys=next_pid:__woke_pid_XXXXXXXX_2=next_pid,__waking_pid_XXXXXXXX_3=$__arg_XXXXXXXX_1:" SQL_REPLACE "' >> /sys/kernel/tracing/events/sched/sched_switch/trigger\n"
54 #define SQL_1_VAR "$__waking_pid_XXXXXXXX_3"
55 #define SQL_1_ONMATCH "onmatch(sched.sched_waking)"
56 #define SQL_1_TRACE "trace(wakeup_1,$__woke_pid_XXXXXXXX_2,$__waking_pid_XXXXXXXX_3)"
57 #define SQL_1_SAVE { "prev_prio" , "prev_state", NULL }
58 
59 #define SQL_2_EVENT	"wakeup_2"
60 #define SQL_2_SQL	"select woke.next_pid as woke_pid, wake.common_pid as waking_pid from sched_waking as wake join sched_switch as woke on woke.next_pid = wake.pid"
61 #define SQL_2_MATCH	"echo 's:wakeup_2 pid_t woke_pid; s32 waking_pid;' >> /sys/kernel/tracing/dynamic_events\n" \
62 			"echo 'hist:keys=pid:__arg_XXXXXXXX_1=common_pid' >> /sys/kernel/tracing/events/sched/sched_waking/trigger\n" \
63 			"echo 'hist:keys=next_pid:__woke_pid_XXXXXXXX_2=next_pid,__waking_pid_XXXXXXXX_3=$__arg_XXXXXXXX_1:" SQL_REPLACE "' >> /sys/kernel/tracing/events/sched/sched_switch/trigger\n"
64 #define SQL_2_MATCH_EVENT "sched.sched_waking"
65 #define SQL_2_VAR "$__woke_pid_XXXXXXXX_2"
66 #define SQL_2_ONMATCH "onmatch(sched.sched_waking)"
67 #define SQL_2_TRACE "trace(wakeup_2,$__woke_pid_XXXXXXXX_2,$__waking_pid_XXXXXXXX_3)"
68 #define SQL_2_SAVE { "prev_prio" , "prev_state", NULL }
69 
70 #define SQL_3_EVENT	"wakeup_lat"
71 #define SQL_3_SQL	"select sched_switch.next_prio as prio, end.prev_prio as pprio, (sched.sched_waking.common_timestamp.usecs - end.TIMESTAMP_USECS) as lat from sched_waking as start join sched_switch as end on start.pid = end.next_pid"
72 #define SQL_3_MATCH	"echo 's:wakeup_lat s32 prio; s32 pprio; u64 lat;' >> /sys/kernel/tracing/dynamic_events\n" \
73 			"echo 'hist:keys=pid:__arg_XXXXXXXX_1=common_timestamp.usecs' >> /sys/kernel/tracing/events/sched/sched_waking/trigger\n" \
74 			"echo 'hist:keys=next_pid:__prio_XXXXXXXX_2=next_prio,__pprio_XXXXXXXX_3=prev_prio,__lat_XXXXXXXX_4=common_timestamp.usecs-$__arg_XXXXXXXX_1:" SQL_REPLACE "' >> /sys/kernel/tracing/events/sched/sched_switch/trigger\n"
75 #define SQL_3_MATCH_EVENT "sched.sched_waking"
76 #define SQL_3_VAR "$__lat_XXXXXXXX_4"
77 #define SQL_3_ONMATCH "onmatch(sched.sched_waking)"
78 #define SQL_3_TRACE "trace(wakeup_lat,$__prio_XXXXXXXX_2,$__pprio_XXXXXXXX_3,$__lat_XXXXXXXX_4)"
79 #define SQL_3_SAVE { "prev_prio" , "prev_state", NULL }
80 
81 #define SQL_4_EVENT	"wakeup_lat_2"
82 #define SQL_4_SQL	"select start.pid, end.next_prio as prio, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sched_waking as start join sched_switch as end on start.pid = end.next_pid where (start.prio >= 1 && start.prio < 100) || !(start.pid >= 0 && start.pid <= 1) && end.prev_pid != 0"
83 #define SQL_4_MATCH	"echo 's:wakeup_lat_2 pid_t pid; s32 prio; u64 lat;' >> /sys/kernel/tracing/dynamic_events\n" \
84 			"echo 'hist:keys=pid:__arg_XXXXXXXX_1=pid,__arg_XXXXXXXX_2=common_timestamp.usecs if (prio >= 1&&prio < 100)||!(pid >= 0&&pid <= 1)' >> /sys/kernel/tracing/events/sched/sched_waking/trigger\n" \
85 			"echo 'hist:keys=next_pid:__pid_XXXXXXXX_3=$__arg_XXXXXXXX_1,__prio_XXXXXXXX_4=next_prio,__lat_XXXXXXXX_5=common_timestamp.usecs-$__arg_XXXXXXXX_2:" SQL_REPLACE " if prev_pid != 0' >> /sys/kernel/tracing/events/sched/sched_switch/trigger\n"
86 #define SQL_4_MATCH_EVENT "sched.sched_waking"
87 #define SQL_4_VAR "$__lat_XXXXXXXX_5"
88 #define SQL_4_ONMATCH "onmatch(sched.sched_waking)"
89 #define SQL_4_TRACE "trace(wakeup_lat_2,$__pid_XXXXXXXX_3,$__prio_XXXXXXXX_4,$__lat_XXXXXXXX_5)"
90 #define SQL_4_SAVE { "prev_prio" , "prev_state", NULL }
91 
92 #define SQL_5_EVENT	"irq_lat"
93 #define SQL_5_SQL	"select end.common_pid as pid, (end.common_timestamp.usecs - start.common_timestamp.usecs) as irq_lat from irq_disable as start join irq_enable as end on start.common_pid = end.common_pid, start.parent_offs == end.parent_offs where start.common_pid != 0"
94 #define SQL_5_START	"irq_disable"
95 #define SQL_5_MATCH	"echo 's:irq_lat s32 pid; u64 irq_lat;' >> /sys/kernel/tracing/dynamic_events\n" \
96 			"echo 'hist:keys=common_pid,parent_offs:__arg_XXXXXXXX_1=common_timestamp.usecs if common_pid != 0' >> /sys/kernel/tracing/events/preemptirq/irq_disable/trigger\n" \
97 			"echo 'hist:keys=common_pid,parent_offs:__pid_XXXXXXXX_2=common_pid,__irq_lat_XXXXXXXX_3=common_timestamp.usecs-$__arg_XXXXXXXX_1:" SQL_REPLACE "' >> /sys/kernel/tracing/events/preemptirq/irq_enable/trigger\n"
98 #define SQL_5_MATCH_EVENT "preemptirq.irq_disable"
99 #define SQL_5_VAR "$__irq_lat_XXXXXXXX_3"
100 #define SQL_5_ONMATCH "onmatch(preemptirq.irq_disable)"
101 #define SQL_5_TRACE "trace(irq_lat,$__pid_XXXXXXXX_2,$__irq_lat_XXXXXXXX_3)"
102 #define SQL_5_SAVE { "caller_offs", NULL }
103 
104 #define SQL_6_EVENT	"wakeup_lat_3"
105 #define SQL_6_SQL	"select start.pid, end.next_prio as prio, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sched_waking as start join sched_switch as end on start.pid = end.next_pid where (start.prio >= 1 && start.prio < 100) || !(start.pid >= 0 && start.pid <= 1) && end.prev_pid != 0"
106 #define SQL_6_MATCH	"echo 's:wakeup_lat_3 pid_t pid; s32 prio; u64 lat;' >> /sys/kernel/tracing/dynamic_events\n" \
107 			"echo 'hist:keys=pid:__arg_XXXXXXXX_1=pid,__arg_XXXXXXXX_2=common_timestamp.usecs if (prio >= 1&&prio < 100)||!(pid >= 0&&pid <= 1)' >> /sys/kernel/tracing/events/sched/sched_waking/trigger\n" \
108 			"echo 'hist:keys=next_pid:__pid_XXXXXXXX_3=$__arg_XXXXXXXX_1,__prio_XXXXXXXX_4=next_prio,__lat_XXXXXXXX_5=common_timestamp.usecs-$__arg_XXXXXXXX_2:" SQL_REPLACE " if prev_pid != 0' >> /sys/kernel/tracing/events/sched/sched_switch/trigger\n"
109 #define SQL_6_MATCH_EVENT "sched.sched_waking"
110 #define SQL_6_VAR "$__lat_XXXXXXXX_5"
111 #define SQL_6_ONMATCH "onmatch(sched.sched_waking)"
112 #define SQL_6_TRACE "trace(wakeup_lat_3,$__pid_XXXXXXXX_3,$__prio_XXXXXXXX_4,$__lat_XXXXXXXX_5)"
113 #define SQL_6_SAVE { "prev_prio" , "prev_state", NULL }
114 
115 #define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug"
116 #define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing"
117 #define TRACEFS_DEFAULT2_PATH "/sys/kernel/debug/tracing"
118 
119 static pthread_barrier_t trace_barrier;
120 
121 static struct tracefs_instance *test_instance;
122 static struct tep_handle *test_tep;
123 struct test_sample {
124 	int cpu;
125 	int value;
126 };
127 static struct test_sample test_array[TEST_ARRAY_SIZE];
128 static int test_found;
129 static unsigned long long last_ts;
130 
131 static bool mapping_is_supported;
132 
msleep(int ms)133 static void msleep(int ms)
134 {
135 	struct timespec tspec;
136 
137 	/* Sleep for 1ms */
138 	tspec.tv_sec = 0;
139 	tspec.tv_nsec = 1000000 * ms;
140 	nanosleep(&tspec, NULL);
141 }
142 
test_callback(struct tep_event * event,struct tep_record * record,int cpu,void * context)143 static int test_callback(struct tep_event *event, struct tep_record *record,
144 			  int cpu, void *context)
145 {
146 	struct tep_format_field *field;
147 	struct test_sample *sample;
148 	int *cpu_test = (int *)context;
149 	int i;
150 
151 	CU_TEST(last_ts <= record->ts);
152 	last_ts = record->ts;
153 
154 	if (cpu_test && *cpu_test >= 0) {
155 		CU_TEST(*cpu_test == cpu);
156 	}
157 	CU_TEST(cpu == record->cpu);
158 
159 	field = tep_find_field(event, "buf");
160 	if (field) {
161 		sample = ((struct test_sample *)(record->data + field->offset));
162 		for (i = 0; i < TEST_ARRAY_SIZE; i++) {
163 			if (test_array[i].value == sample->value &&
164 			    test_array[i].cpu == cpu) {
165 				test_array[i].value = 0;
166 				test_found++;
167 				break;
168 			}
169 		}
170 	}
171 
172 	return 0;
173 }
174 
175 static cpu_set_t *cpuset_save;
176 static cpu_set_t *cpuset;
177 static int cpu_size;
178 
save_affinity(void)179 static void save_affinity(void)
180 {
181 	int cpus;
182 
183 	cpus = sysconf(_SC_NPROCESSORS_CONF);
184 	cpuset_save = CPU_ALLOC(cpus);
185 	cpuset = CPU_ALLOC(cpus);
186 	cpu_size = CPU_ALLOC_SIZE(cpus);
187 	CU_TEST(cpuset_save != NULL && cpuset != NULL);
188 	CU_TEST(sched_getaffinity(0, cpu_size, cpuset_save) == 0);
189 }
190 
thread_affinity(void)191 static void thread_affinity(void)
192 {
193 	sched_setaffinity(0, cpu_size, cpuset_save);
194 }
195 
reset_affinity(void)196 static void reset_affinity(void)
197 {
198 	sched_setaffinity(0, cpu_size, cpuset_save);
199 	CPU_FREE(cpuset_save);
200 	CPU_FREE(cpuset);
201 }
202 
set_affinity(int cpu)203 static void set_affinity(int cpu)
204 {
205 	CPU_ZERO_S(cpu_size, cpuset);
206 	CPU_SET_S(cpu, cpu_size, cpuset);
207 	CU_TEST(sched_setaffinity(0, cpu_size, cpuset) == 0);
208 	sched_yield(); /* Force schedule */
209 }
210 
test_iter_write(struct tracefs_instance * instance)211 static void test_iter_write(struct tracefs_instance *instance)
212 {
213 	char *path;
214 	int i, fd;
215 	int cpus;
216 	int ret;
217 
218 	cpus = sysconf(_SC_NPROCESSORS_CONF);
219 	save_affinity();
220 
221 	path = tracefs_instance_get_file(instance, "trace_marker");
222 	CU_TEST(path != NULL);
223 	fd = open(path, O_WRONLY);
224 	tracefs_put_tracing_file(path);
225 	CU_TEST(fd >= 0);
226 
227 	for (i = 0; i < TEST_ARRAY_SIZE; i++) {
228 		test_array[i].cpu = rand() % cpus;
229 		test_array[i].value = random();
230 		if (!test_array[i].value)
231 			test_array[i].value++;
232 		CU_TEST(test_array[i].cpu < cpus);
233 		set_affinity(test_array[i].cpu);
234 		ret = write(fd, test_array + i, sizeof(struct test_sample));
235 		CU_TEST(ret == sizeof(struct test_sample));
236 	}
237 
238 	reset_affinity();
239 	close(fd);
240 }
241 
242 
iter_raw_events_on_cpu(struct tracefs_instance * instance,int cpu,bool snapshot)243 static void iter_raw_events_on_cpu(struct tracefs_instance *instance, int cpu, bool snapshot)
244 {
245 	int cpus = sysconf(_SC_NPROCESSORS_CONF);
246 	cpu_set_t *cpuset = NULL;
247 	int cpu_size = 0;
248 	int check = 0;
249 	int ret;
250 	int i;
251 
252 	if (snapshot)
253 		tracefs_instance_clear(instance);
254 
255 	if (cpu >= 0) {
256 		cpuset = CPU_ALLOC(cpus);
257 		cpu_size = CPU_ALLOC_SIZE(cpus);
258 		CPU_ZERO_S(cpu_size, cpuset);
259 		CPU_SET(cpu, cpuset);
260 	}
261 	test_found = 0;
262 	last_ts = 0;
263 	test_iter_write(instance);
264 
265 	if (snapshot) {
266 		tracefs_snapshot_snap(instance);
267 		ret = tracefs_iterate_snapshot_events(test_tep, instance, cpuset, cpu_size,
268 						      test_callback, &cpu);
269 	} else {
270 		ret = tracefs_iterate_raw_events(test_tep, instance, cpuset, cpu_size,
271 						 test_callback, &cpu);
272 	}
273 	CU_TEST(ret == 0);
274 	if (cpu < 0) {
275 		CU_TEST(test_found == TEST_ARRAY_SIZE);
276 	} else {
277 		for (i = 0; i < TEST_ARRAY_SIZE; i++) {
278 			if (test_array[i].cpu == cpu) {
279 				check++;
280 				CU_TEST(test_array[i].value == 0)
281 			} else {
282 				CU_TEST(test_array[i].value != 0)
283 			}
284 		}
285 		CU_TEST(test_found == check);
286 	}
287 
288 	if (cpuset)
289 		CPU_FREE(cpuset);
290 }
291 
test_instance_iter_raw_events(struct tracefs_instance * instance)292 static void test_instance_iter_raw_events(struct tracefs_instance *instance)
293 {
294 	int cpus = sysconf(_SC_NPROCESSORS_CONF);
295 	int ret;
296 	int i;
297 
298 	ret = tracefs_iterate_raw_events(NULL, instance, NULL, 0, test_callback, NULL);
299 	CU_TEST(ret < 0);
300 	last_ts = 0;
301 	ret = tracefs_iterate_raw_events(test_tep, NULL, NULL, 0, test_callback, NULL);
302 	CU_TEST(ret == 0);
303 	ret = tracefs_iterate_raw_events(test_tep, instance, NULL, 0, NULL, NULL);
304 	CU_TEST(ret < 0);
305 
306 	iter_raw_events_on_cpu(instance, -1, false);
307 	for (i = 0; i < cpus; i++)
308 		iter_raw_events_on_cpu(instance, i, false);
309 }
310 
test_iter_raw_events(void)311 static void test_iter_raw_events(void)
312 {
313 	test_instance_iter_raw_events(NULL);
314 	test_instance_iter_raw_events(test_instance);
315 }
316 
test_instance_iter_snapshot_events(struct tracefs_instance * instance)317 static void test_instance_iter_snapshot_events(struct tracefs_instance *instance)
318 {
319 	int cpus = sysconf(_SC_NPROCESSORS_CONF);
320 	int i;
321 
322 	iter_raw_events_on_cpu(instance, -1, true);
323 	for (i = 0; i < cpus; i++)
324 		iter_raw_events_on_cpu(instance, i, true);
325 	tracefs_snapshot_free(instance);
326 }
327 
test_iter_snapshot_events(void)328 static void test_iter_snapshot_events(void)
329 {
330 	test_instance_iter_snapshot_events(NULL);
331 	test_instance_iter_snapshot_events(test_instance);
332 }
333 
334 
335 #define RAND_STR_SIZE 20
336 #define RAND_ASCII "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
get_rand_str(void)337 static const char *get_rand_str(void)
338 {
339 	static char str[RAND_STR_SIZE];
340 	static char sym[] = RAND_ASCII;
341 	struct timespec clk;
342 	int i;
343 
344 	clock_gettime(CLOCK_REALTIME, &clk);
345 	srand(clk.tv_nsec);
346 	for (i = 0; i < RAND_STR_SIZE; i++)
347 		str[i] = sym[rand() % (sizeof(sym) - 1)];
348 
349 	str[RAND_STR_SIZE - 1] = 0;
350 	return str;
351 }
352 
353 struct marker_find {
354 	int data_offset;
355 	int event_id;
356 	int count;
357 	int len;
358 	void *data;
359 };
360 
test_marker_callback(struct tep_event * event,struct tep_record * record,int cpu,void * context)361 static int test_marker_callback(struct tep_event *event, struct tep_record *record,
362 				int cpu, void *context)
363 {
364 	struct marker_find *walk = context;
365 
366 	if (!walk)
367 		return -1;
368 	if (event->id != walk->event_id)
369 		return 0;
370 	if (record->size < (walk->data_offset + walk->len))
371 		return 0;
372 
373 	if (memcmp(walk->data, record->data + walk->data_offset, walk->len) == 0)
374 		walk->count++;
375 
376 	return 0;
377 }
378 
find_test_marker(struct tracefs_instance * instance,void * data,int len,int expected,bool raw)379 static bool find_test_marker(struct tracefs_instance *instance,
380 			     void *data, int len, int expected, bool raw)
381 {
382 	struct tep_format_field *field;
383 	struct tep_event *event;
384 	struct marker_find walk;
385 	int ret;
386 
387 	if (raw) {
388 		event = tep_find_event_by_name(test_tep, "ftrace", "raw_data");
389 		if (event)
390 			field = tep_find_field(event, "id");
391 
392 	} else {
393 		event = tep_find_event_by_name(test_tep, "ftrace", "print");
394 		if (event)
395 			field = tep_find_field(event, "buf");
396 	}
397 
398 	if (!event || !field)
399 		return false;
400 
401 	walk.data = data;
402 	walk.len = len;
403 	walk.count = 0;
404 	walk.event_id = event->id;
405 	walk.data_offset = field->offset;
406 	ret = tracefs_iterate_raw_events(test_tep, instance, NULL, 0,
407 					 test_marker_callback, &walk);
408 	CU_TEST(ret == 0);
409 
410 	return walk.count == expected;
411 }
412 
marker_vprint(struct tracefs_instance * instance,char * fmt,...)413 static int marker_vprint(struct tracefs_instance *instance, char *fmt, ...)
414 {
415 	va_list ap;
416 	int ret;
417 
418 	va_start(ap, fmt);
419 	ret = tracefs_vprintf(instance, fmt, ap);
420 	va_end(ap);
421 
422 	return ret;
423 }
424 
425 #define MARKERS_WRITE_COUNT	100
test_instance_ftrace_marker(struct tracefs_instance * instance)426 static void test_instance_ftrace_marker(struct tracefs_instance *instance)
427 {
428 	const char *string = get_rand_str();
429 	unsigned int data = 0xdeadbeef;
430 	char *str;
431 	int i;
432 
433 	CU_TEST(tracefs_print_init(instance) == 0);
434 	tracefs_print_close(instance);
435 
436 	CU_TEST(tracefs_binary_init(instance) == 0);
437 	tracefs_binary_close(instance);
438 
439 	for (i = 0; i < MARKERS_WRITE_COUNT; i++) {
440 		CU_TEST(tracefs_binary_write(instance, &data, sizeof(data)) == 0);
441 	}
442 	CU_TEST(find_test_marker(instance, &data, sizeof(data), MARKERS_WRITE_COUNT, true));
443 
444 	for (i = 0; i < MARKERS_WRITE_COUNT; i++) {
445 		CU_TEST(tracefs_printf(instance, "Test marker: %s 0x%X", string, data) == 0);
446 	}
447 	asprintf(&str, "Test marker: %s 0x%X", string, data);
448 	CU_TEST(find_test_marker(instance, str, strlen(str), MARKERS_WRITE_COUNT, false));
449 	free(str);
450 
451 	for (i = 0; i < MARKERS_WRITE_COUNT; i++) {
452 		CU_TEST(marker_vprint(instance, "Test marker V: %s 0x%X", string, data) == 0);
453 	}
454 	asprintf(&str, "Test marker V: %s 0x%X", string, data);
455 	CU_TEST(find_test_marker(instance, str, strlen(str), MARKERS_WRITE_COUNT, false));
456 	free(str);
457 
458 	tracefs_print_close(instance);
459 	tracefs_binary_close(instance);
460 }
461 
test_ftrace_marker(void)462 static void test_ftrace_marker(void)
463 {
464 	test_instance_ftrace_marker(test_instance);
465 }
466 
replace_str(char * str,char * rep,char * with,int rep_len,int with_len)467 static void replace_str(char *str, char *rep, char *with, int rep_len, int with_len)
468 {
469 	char find[rep_len + 1];
470 	char *s = str;
471 	int delta = rep_len - with_len;
472 
473 	CU_TEST(delta >= 0);
474 	if (delta < 0) {
475 		printf("rep_len:%d with_len:%d\n", rep_len, with_len);
476 		return;
477 	}
478 
479 	strncpy(find, rep, rep_len + 1);
480 	find[rep_len] = '\0';
481 
482 	while ((s = strstr(s, find))) {
483 		strncpy(s, with, with_len);
484 		s += with_len;
485 		if (delta) {
486 			int new_len = strlen(s) - delta;
487 			memmove(s, s + delta, new_len);
488 			s[new_len] = '\0';
489 		}
490 	}
491 }
492 
493 enum sql_type {
494 	SQL_ONMATCH,
495 	SQL_ONMAX,
496 	SQL_ONCHANGE,
497 };
498 
499 enum sql_action {
500 	SQL_TRACE,
501 	SQL_SNAPSHOT,
502 	SQL_SAVE,
503 	SQL_TRACE_SNAPSHOT,
504 };
505 
506 struct trace_sql_strings {
507 	const char		*match;
508 	const char		*onmatch;
509 	const char		*var;
510 	const char		*trace;
511 	char			*save[4];
512 };
513 
514 #define SQL_VAR_REPLACE		"_XXXXXXXX_"
515 
test_sql(struct trace_seq * seq,struct trace_sql_strings * strings,enum sql_type stype,enum sql_action atype)516 static bool test_sql(struct trace_seq *seq, struct trace_sql_strings *strings,
517 		     enum sql_type stype, enum sql_action atype)
518 {
519 	char string[strlen(strings->match) + 256]; /* add a bunch for replacement */
520 	char replace[1024];
521 	char type[256];
522 	char *p, *s, *e, *c = seq->buffer;
523 	bool ret;
524 
525 	strcpy(string, strings->match);
526 	s = string;
527 
528 	switch (stype) {
529 	case SQL_ONMATCH:
530 		sprintf(type, "%s", strings->onmatch);
531 		break;
532 	case SQL_ONMAX:
533 		sprintf(type, "onmax(%s)", strings->var);
534 		break;
535 	case SQL_ONCHANGE:
536 		sprintf(type, "onchange(%s)", strings->var);
537 		break;
538 	}
539 
540 	switch (atype) {
541 	case SQL_TRACE:
542 		sprintf(replace, "%s.%s", type, strings->trace);
543 		break;
544 	case SQL_SNAPSHOT:
545 		sprintf(replace, "%s.snapshot()", type);
546 		break;
547 	case SQL_SAVE:
548 		sprintf(replace, "%s.save(", type);
549 
550 		for (int i = 0; strings->save[i]; i++) {
551 			if (i)
552 				strcat(replace, ",");
553 			strcat(replace, strings->save[i]);
554 		}
555 		strcat(replace, ")");
556 		break;
557 	case SQL_TRACE_SNAPSHOT:
558 		sprintf(replace, "%s.%s:%s.snapshot()", type, strings->trace, type);
559 		break;
560 	}
561 
562 	replace_str(string, SQL_REPLACE, replace, strlen(SQL_REPLACE), strlen(replace));
563 
564 	while ((p = strstr(s, SQL_VAR_REPLACE))) {
565 		CU_TEST(ret = strncmp(c, s, p - s) == 0);
566 		if (!ret) {
567 			printf("\n\t'%*.s'\nDOES NOT MATCH\n\t%*.s\n",
568 			       (int)(p - s), c, (int)(p - s), s);
569 			return ret;
570 		}
571 
572 		/* Move c passed what was matched */
573 		c += p - s;
574 
575 		/* Set e to the next value */
576 		e = c + 1;
577 		while (isdigit(*e))
578 			e++;
579 		/* Skip the next '_' */
580 		e++;
581 		/* Skip the next numbers */
582 		while (isdigit(*e))
583 			e++;
584 
585 		/* Skip the "_XXXXXXXX_" */
586 		s = p + strlen(SQL_VAR_REPLACE);
587 		/* Skip the next numbers */
588 		while (isdigit(*s))
589 			s++;
590 
591 		/* Now replace all of these */
592 		replace_str(s, p, c, s - p, e - c);
593 
594 		c = e;
595 	}
596 
597 	ret = strcmp(s, c) == 0;
598 	if (!ret)
599 		printf("\n\t'%s'\nDOES NOT MATCH\n\t%s\n", s, c);
600 
601 	return ret;
602 }
603 
unhash_var(char * var,const char * hash_var)604 static void unhash_var(char *var, const char *hash_var)
605 {
606 	const char *p = hash_var + strlen(hash_var) - 1;
607 	int len;
608 
609 	/* Skip $__ */
610 	hash_var += 3;
611 
612 	/* Find the _XXXXXXXXX_ */
613 	p = strstr(hash_var, SQL_VAR_REPLACE);
614 	CU_TEST(p != NULL);
615 
616 	len = p - hash_var;
617 
618 	strncpy(var, hash_var, len);
619 	var[len] = '\0';
620 }
621 
set_sql_type(struct tracefs_synth * synth,struct trace_sql_strings * strings,enum sql_type stype,enum sql_action atype)622 static bool set_sql_type(struct tracefs_synth *synth, struct trace_sql_strings *strings,
623 			 enum sql_type stype, enum sql_action atype)
624 {
625 	enum tracefs_synth_handler handler = 0;
626 	char var[256];
627 	int ret = 0;
628 
629 	switch (stype) {
630 	case SQL_ONMATCH:
631 		break;
632 	case SQL_ONMAX:
633 		handler = TRACEFS_SYNTH_HANDLE_MAX;
634 		break;
635 	case SQL_ONCHANGE:
636 		handler = TRACEFS_SYNTH_HANDLE_CHANGE;
637 		break;
638 	}
639 
640 	unhash_var(var, strings->var);
641 
642 	switch (atype) {
643 	case SQL_TRACE:
644 		if (handler)
645 			ret = tracefs_synth_trace(synth, handler, var);
646 		break;
647 	case SQL_SNAPSHOT:
648 		ret = tracefs_synth_snapshot(synth, handler, var);
649 		break;
650 	case SQL_SAVE:
651 		ret = tracefs_synth_save(synth, handler, var, strings->save);
652 		break;
653 	case SQL_TRACE_SNAPSHOT:
654 		ret = tracefs_synth_trace(synth, handler, var);
655 		ret |= tracefs_synth_snapshot(synth, handler, var);
656 		break;
657 	}
658 
659 	return ret == 0;
660 }
661 
662 #define sql_assign_save(str, arr)			\
663 	do {						\
664 		char *__array__[] = arr;		\
665 		int i;					\
666 							\
667 		for (i = 0; __array__[i]; i++) {	\
668 			(str)[i] = __array__[i];	\
669 		}					\
670 		(str)[i] = NULL;			\
671 	} while (0)
672 
test_instance_trace_sql(struct tracefs_instance * instance,enum sql_type stype,enum sql_action atype)673 static void test_instance_trace_sql(struct tracefs_instance *instance,
674 				    enum sql_type stype, enum sql_action atype)
675 {
676 	struct tracefs_synth *synth;
677 	struct trace_seq seq;
678 	struct tep_handle *tep;
679 	struct tep_event *event;
680 	struct trace_sql_strings strings;
681 	int ret;
682 
683 	tep = test_tep;
684 
685 	trace_seq_init(&seq);
686 
687 	strings.match = SQL_1_MATCH;
688 	strings.var = SQL_1_VAR;
689 	strings.onmatch = SQL_1_ONMATCH;
690 	strings.trace = SQL_1_TRACE;
691 	sql_assign_save(strings.save, SQL_1_SAVE);
692 
693 	synth = tracefs_sql(tep, SQL_1_EVENT, SQL_1_SQL, NULL);
694 	CU_TEST(synth != NULL);
695 	CU_TEST(set_sql_type(synth, &strings, stype, atype));
696 	ret = tracefs_synth_echo_cmd(&seq, synth);
697 	CU_TEST(ret == 0);
698 	CU_TEST(test_sql(&seq, &strings, stype, atype));
699 	tracefs_synth_free(synth);
700 	trace_seq_reset(&seq);
701 
702 	strings.match = SQL_2_MATCH;
703 	strings.var = SQL_2_VAR;
704 	strings.onmatch = SQL_2_ONMATCH;
705 	strings.trace = SQL_2_TRACE;
706 	sql_assign_save(strings.save, SQL_2_SAVE);
707 
708 	synth = tracefs_sql(tep, SQL_2_EVENT, SQL_2_SQL, NULL);
709 	CU_TEST(synth != NULL);
710 	CU_TEST(set_sql_type(synth, &strings, stype, atype));
711 	ret = tracefs_synth_echo_cmd(&seq, synth);
712 	CU_TEST(ret == 0);
713 	CU_TEST(test_sql(&seq, &strings, stype, atype));
714 	tracefs_synth_free(synth);
715 	trace_seq_reset(&seq);
716 
717 	strings.match = SQL_3_MATCH;
718 	strings.var = SQL_3_VAR;
719 	strings.onmatch = SQL_3_ONMATCH;
720 	strings.trace = SQL_3_TRACE;
721 	sql_assign_save(strings.save, SQL_3_SAVE);
722 
723 	synth = tracefs_sql(tep, SQL_3_EVENT, SQL_3_SQL, NULL);
724 	CU_TEST(synth != NULL);
725 	CU_TEST(set_sql_type(synth, &strings, stype, atype));
726 	ret = tracefs_synth_echo_cmd(&seq, synth);
727 	CU_TEST(ret == 0);
728 	CU_TEST(test_sql(&seq, &strings, stype, atype));
729 	tracefs_synth_free(synth);
730 	trace_seq_reset(&seq);
731 
732 	strings.match = SQL_4_MATCH;
733 	strings.var = SQL_4_VAR;
734 	strings.onmatch = SQL_4_ONMATCH;
735 	strings.trace = SQL_4_TRACE;
736 	sql_assign_save(strings.save, SQL_4_SAVE);
737 
738 	synth = tracefs_sql(tep, SQL_4_EVENT, SQL_4_SQL, NULL);
739 	CU_TEST(synth != NULL);
740 	CU_TEST(set_sql_type(synth, &strings, stype, atype));
741 	ret = tracefs_synth_echo_cmd(&seq, synth);
742 	CU_TEST(ret == 0);
743 	CU_TEST(test_sql(&seq, &strings, stype, atype));
744 	tracefs_synth_free(synth);
745 	trace_seq_reset(&seq);
746 
747 	event = tep_find_event_by_name(tep, NULL, SQL_5_START);
748 	if (event) {
749 
750 		strings.match = SQL_5_MATCH;
751 		strings.var = SQL_5_VAR;
752 		strings.onmatch = SQL_5_ONMATCH;
753 		strings.trace = SQL_5_TRACE;
754 		sql_assign_save(strings.save, SQL_5_SAVE);
755 
756 		synth = tracefs_sql(tep, SQL_5_EVENT, SQL_5_SQL, NULL);
757 		CU_TEST(synth != NULL);
758 		CU_TEST(set_sql_type(synth, &strings, stype, atype));
759 		ret = tracefs_synth_echo_cmd(&seq, synth);
760 		CU_TEST(ret == 0);
761 		CU_TEST(test_sql(&seq, &strings, stype, atype));
762 		tracefs_synth_free(synth);
763 		trace_seq_reset(&seq);
764 	}
765 
766 	strings.match = SQL_6_MATCH;
767 	strings.var = SQL_6_VAR;
768 	strings.onmatch = SQL_6_ONMATCH;
769 	strings.trace = SQL_6_TRACE;
770 	sql_assign_save(strings.save, SQL_6_SAVE);
771 
772 	synth = tracefs_sql(tep, SQL_6_EVENT, SQL_6_SQL, NULL);
773 	CU_TEST(synth != NULL);
774 	CU_TEST(set_sql_type(synth, &strings, stype, atype));
775 	ret = tracefs_synth_echo_cmd(&seq, synth);
776 	CU_TEST(ret == 0);
777 	CU_TEST(test_sql(&seq, &strings, stype, atype));
778 	tracefs_synth_free(synth);
779 	trace_seq_reset(&seq);
780 
781 	trace_seq_destroy(&seq);
782 }
783 
test_trace_sql(void)784 static void test_trace_sql(void)
785 {
786 	test_instance_trace_sql(test_instance, SQL_ONMATCH, SQL_TRACE);
787 }
788 
test_trace_sql_trace_onmax(void)789 static void test_trace_sql_trace_onmax(void)
790 {
791 	test_instance_trace_sql(test_instance, SQL_ONMAX, SQL_TRACE);
792 }
793 
test_trace_sql_trace_onchange(void)794 static void test_trace_sql_trace_onchange(void)
795 {
796 	test_instance_trace_sql(test_instance, SQL_ONCHANGE, SQL_TRACE);
797 }
798 
test_trace_sql_snapshot_onmax(void)799 static void test_trace_sql_snapshot_onmax(void)
800 {
801 	test_instance_trace_sql(test_instance, SQL_ONMAX, SQL_SNAPSHOT);
802 }
803 
test_trace_sql_snapshot_onchange(void)804 static void test_trace_sql_snapshot_onchange(void)
805 {
806 	test_instance_trace_sql(test_instance, SQL_ONCHANGE, SQL_SNAPSHOT);
807 }
808 
test_trace_sql_save_onmax(void)809 static void test_trace_sql_save_onmax(void)
810 {
811 	test_instance_trace_sql(test_instance, SQL_ONMAX, SQL_SAVE);
812 }
813 
test_trace_sql_save_onchange(void)814 static void test_trace_sql_save_onchange(void)
815 {
816 	test_instance_trace_sql(test_instance, SQL_ONCHANGE, SQL_SAVE);
817 }
818 
test_trace_sql_trace_snapshot_onmax(void)819 static void test_trace_sql_trace_snapshot_onmax(void)
820 {
821 	test_instance_trace_sql(test_instance, SQL_ONMAX, SQL_TRACE_SNAPSHOT);
822 }
823 
test_trace_sql_trace_snapshot_onchange(void)824 static void test_trace_sql_trace_snapshot_onchange(void)
825 {
826 	test_instance_trace_sql(test_instance, SQL_ONCHANGE, SQL_TRACE_SNAPSHOT);
827 }
828 
829 
call_getppid(int cnt)830 static void call_getppid(int cnt)
831 {
832 	int i;
833 
834 	for (i = 0; i < cnt; i++)
835 		getppid();
836 }
837 
838 struct check_data {
839 	int	this_pid;
840 	int	other_pid;
841 	bool	trace_this;
842 	bool	trace_other;
843 	bool	trace_all;
844 	bool	hit;
845 	int (*filter_clear)(struct tracefs_instance *instance, bool notrace);
846 };
847 
check_callback(struct tep_event * event,struct tep_record * record,int cpu,void * data)848 static int check_callback(struct tep_event *event, struct tep_record *record,
849 			  int cpu, void *data)
850 {
851 	struct check_data *cdata = data;
852 	int pid;
853 
854 	cdata->hit = true;
855 
856 	pid = tep_data_pid(event->tep, record);
857 
858 	if (pid == cdata->this_pid) {
859 		CU_TEST(cdata->trace_this);
860 		return cdata->trace_this ? 0 : -1;
861 	}
862 
863 	if (pid == cdata->other_pid) {
864 		CU_TEST(cdata->trace_other);
865 		return cdata->trace_other ? 0 : -1;
866 	}
867 
868 	CU_TEST(cdata->trace_all);
869 	if (!cdata->trace_all) {
870 		printf(" (Traced %d but should not have", pid);
871 		if (cdata->trace_this)
872 			printf(", this_pid:%d", cdata->this_pid);
873 		if (cdata->trace_other)
874 			printf(", other_pid:%d", cdata->other_pid);
875 		printf(") ");
876 	}
877 
878 	return cdata->trace_all ? 0 : -1;
879 }
880 
check_filtered_pid(struct tep_handle * tep,struct tracefs_instance * instance,struct check_data * cdata)881 static int check_filtered_pid(struct tep_handle *tep, struct tracefs_instance *instance,
882 			      struct check_data *cdata)
883 {
884 	int ret;
885 
886 	cdata->hit = false;
887 	ret = tracefs_iterate_raw_events(tep, instance, NULL, 0, check_callback, cdata);
888 
889 	tracefs_instance_clear(instance);
890 
891 	cdata->filter_clear(instance, false);
892 	cdata->filter_clear(instance, true);
893 
894 	return ret;
895 }
896 
897 struct spin_data {
898 	bool	stop;
899 	bool	done;
900 	int	tid;
901 };
902 
trace_spin_thread(void * arg)903 static void *trace_spin_thread(void *arg)
904 {
905 	struct spin_data *data = arg;
906 
907 	data->tid = gettid();
908 	pthread_barrier_wait(&trace_barrier);
909 
910 	while (!data->done) {
911 		pthread_barrier_wait(&trace_barrier);
912 		while (!data->stop && !data->done)
913 			getppid();
914 		pthread_barrier_wait(&trace_barrier);
915 	}
916 
917 	return NULL;
918 }
919 
run_test(struct tracefs_instance * instance,struct tep_handle * tep,struct spin_data * data,struct check_data * cdata)920 static void run_test(struct tracefs_instance *instance, struct tep_handle *tep,
921 		     struct spin_data *data, struct check_data *cdata)
922 {
923 	tracefs_trace_on(instance);
924 
925 	/* Run a little */
926 	call_getppid(1000);
927 
928 	/* Start the spinner */
929 	data->stop = false;
930 	pthread_barrier_wait(&trace_barrier);
931 
932 	/* Allow the other threads run */
933 	msleep(100);
934 
935 	/* Stop the spinners */
936 	data->stop = true;
937 	pthread_barrier_wait(&trace_barrier);
938 	/* Run a little more  */
939 	call_getppid(10);
940 	tracefs_trace_off(instance);
941 
942 	check_filtered_pid(tep, instance, cdata);
943 }
944 
945 
test_instance_pid_filter(struct tracefs_instance * instance,int (* filter_pid)(struct tracefs_instance * instance,int pid,bool reset,bool notrace),int (* filter_clear)(struct tracefs_instance * instance,bool notrace))946 static void test_instance_pid_filter(struct tracefs_instance *instance,
947 				     int (*filter_pid)(struct tracefs_instance *instance,
948 						       int pid, bool reset, bool notrace),
949 				     int (*filter_clear)(struct tracefs_instance *instance,
950 							 bool notrace))
951 {
952 	struct tep_handle *tep = test_tep;
953 	struct check_data cdata;
954 	struct spin_data data = { };
955 	pthread_t thread1;
956 	pthread_t thread2;
957 	int this_pid = getpid();
958 
959 	pthread_barrier_init(&trace_barrier, NULL, 3);
960 
961 	/* create two spinners, one will be used for tracing */
962 	pthread_create(&thread1, NULL, trace_spin_thread, &data);
963 	pthread_create(&thread2, NULL, trace_spin_thread, &data);
964 
965 	pthread_barrier_wait(&trace_barrier);
966 
967 	cdata.this_pid = this_pid;
968 	cdata.other_pid = data.tid;
969 	cdata.filter_clear = filter_clear;
970 
971 	/* Test 1 */
972 	cdata.trace_this = true;
973 	cdata.trace_other = false;
974 	cdata.trace_all = false;
975 
976 	/* Add the thread, but then reset it out */
977 	filter_pid(instance, data.tid, true, false);
978 	filter_pid(instance, this_pid, true, false);
979 
980 	/* Only this thread should be traced */
981 	run_test(instance, tep, &data, &cdata);
982 	CU_TEST(cdata.hit);
983 
984 
985 	/* Test 2 */
986 	cdata.trace_this = true;
987 	cdata.trace_other = true;
988 	cdata.trace_all = false;
989 
990 	/* Add the thread, but then reset it out */
991 	filter_pid(instance, data.tid, true, false);
992 	filter_pid(instance, this_pid, false, false);
993 
994 	/* Only this thread should be traced */
995 	run_test(instance, tep, &data, &cdata);
996 	CU_TEST(cdata.hit);
997 
998 
999 	/* Test 3 */
1000 	cdata.trace_this = false;
1001 	cdata.trace_other = true;
1002 	cdata.trace_all = true;
1003 
1004 	/* Add the thread, but then reset it out */
1005 	filter_pid(instance, data.tid, true, true);
1006 	filter_pid(instance, this_pid, true, true);
1007 
1008 	/* Only this thread should be traced */
1009 	run_test(instance, tep, &data, &cdata);
1010 	CU_TEST(cdata.hit);
1011 
1012 
1013 	/* Test 4 */
1014 	cdata.trace_this = false;
1015 	cdata.trace_other = false;
1016 	cdata.trace_all = true;
1017 
1018 	/* Add the thread, but then reset it out */
1019 	filter_pid(instance, data.tid, true, true);
1020 	filter_pid(instance, this_pid, false, true);
1021 
1022 	/* Only this thread should be traced */
1023 	run_test(instance, tep, &data, &cdata);
1024 	CU_TEST(cdata.hit);
1025 
1026 	/* exit out */
1027 	data.done = true;
1028 	pthread_barrier_wait(&trace_barrier);
1029 	pthread_barrier_wait(&trace_barrier);
1030 
1031 	pthread_join(thread1, NULL);
1032 	pthread_join(thread2, NULL);
1033 }
1034 
test_function_pid_filter(struct tracefs_instance * instance)1035 static void test_function_pid_filter(struct tracefs_instance *instance)
1036 {
1037 	tracefs_trace_off(instance);
1038 	tracefs_instance_clear(instance);
1039 	tracefs_tracer_set(instance, TRACEFS_TRACER_FUNCTION);
1040 	test_instance_pid_filter(instance,
1041 				 tracefs_filter_pid_function,
1042 				 tracefs_filter_pid_function_clear);
1043 	tracefs_tracer_clear(instance);
1044 	tracefs_trace_on(instance);
1045 }
1046 
test_trace_function_pid_filter(void)1047 static void test_trace_function_pid_filter(void)
1048 {
1049 	test_function_pid_filter(NULL);
1050 	test_function_pid_filter(test_instance);
1051 }
1052 
test_events_pid_filter(struct tracefs_instance * instance)1053 static void test_events_pid_filter(struct tracefs_instance *instance)
1054 {
1055 	tracefs_trace_off(instance);
1056 	tracefs_instance_clear(instance);
1057 	tracefs_event_enable(instance, "syscalls", NULL);
1058 	tracefs_event_enable(instance, "raw_syscalls", NULL);
1059 	test_instance_pid_filter(instance,
1060 				 tracefs_filter_pid_events,
1061 				 tracefs_filter_pid_events_clear);
1062 	tracefs_event_disable(instance, NULL, NULL);
1063 	tracefs_trace_on(instance);
1064 }
1065 
test_trace_events_pid_filter(void)1066 static void test_trace_events_pid_filter(void)
1067 {
1068 	test_events_pid_filter(NULL);
1069 	test_events_pid_filter(test_instance);
1070 }
1071 
1072 struct test_cpu_data {
1073 	struct tracefs_instance		*instance;
1074 	struct tracefs_cpu		*tcpu;
1075 	struct kbuffer			*kbuf;
1076 	struct tep_handle		*tep;
1077 	unsigned long long		missed_events;
1078 	void				*buf;
1079 	int				events_per_buf;
1080 	int				bufsize;
1081 	int				nr_subbufs;
1082 	int				data_size;
1083 	int				this_pid;
1084 	int				fd;
1085 	bool				done;
1086 };
1087 
cleanup_trace_cpu(struct test_cpu_data * data)1088 static void cleanup_trace_cpu(struct test_cpu_data *data)
1089 {
1090 	close(data->fd);
1091 	tracefs_cpu_close(data->tcpu);
1092 	free(data->buf);
1093 	kbuffer_free(data->kbuf);
1094 }
1095 
1096 #define EVENT_SYSTEM "syscalls"
1097 #define EVENT_NAME  "sys_enter_getppid"
1098 
make_trace_temp_file(void)1099 static int make_trace_temp_file(void)
1100 {
1101 	char tmpfile[] = "/tmp/utest-libtracefsXXXXXX";
1102 	int fd;
1103 
1104 	fd = mkstemp(tmpfile);
1105 	unlink(tmpfile);
1106 	return fd;
1107 }
1108 
setup_trace_cpu(struct tracefs_instance * instance,struct test_cpu_data * data,bool nonblock,bool map)1109 static int setup_trace_cpu(struct tracefs_instance *instance, struct test_cpu_data *data, bool nonblock, bool map)
1110 {
1111 	struct tep_format_field **fields;
1112 	struct tep_event *event;
1113 	ssize_t buffer_size;
1114 	int max = 0;
1115 	int ret;
1116 	int i;
1117 
1118 	/* Make sure tracing is on */
1119 	tracefs_trace_on(instance);
1120 
1121 	memset (data, 0, sizeof(*data));
1122 
1123 	data->instance = instance;
1124 
1125 	data->fd = make_trace_temp_file();
1126 	CU_TEST(data->fd >= 0);
1127 	if (data->fd < 0)
1128 		return -1;
1129 
1130 	data->tep = test_tep;
1131 
1132 	if (map)
1133 		data->tcpu = tracefs_cpu_open_mapped(instance, 0, nonblock);
1134 	else
1135 		data->tcpu = tracefs_cpu_open(instance, 0, nonblock);
1136 
1137 	CU_TEST(data->tcpu != NULL);
1138 	if (!data->tcpu)
1139 		goto fail;
1140 
1141 	data->bufsize = tracefs_cpu_read_size(data->tcpu);
1142 	CU_TEST(data->bufsize > 0);
1143 
1144 	data->data_size = tep_get_sub_buffer_data_size(data->tep);
1145 	CU_TEST(data->data_size > 0);
1146 
1147 	buffer_size = tracefs_instance_get_buffer_size(instance, 0) * 1024;
1148 	data->nr_subbufs = buffer_size/ data->data_size;
1149 
1150 	data->buf = calloc(1, data->bufsize);
1151 	CU_TEST(data->buf != NULL);
1152 	if (!data->buf)
1153 		goto fail;
1154 
1155 	data->kbuf = tep_kbuffer(data->tep);
1156 	CU_TEST(data->kbuf != NULL);
1157 	if (!data->kbuf)
1158 		goto fail;
1159 
1160 	tracefs_instance_file_clear(instance, "trace");
1161 
1162 	event = tep_find_event_by_name(data->tep, EVENT_SYSTEM, EVENT_NAME);
1163 	CU_TEST(event != NULL);
1164 	if (!event)
1165 		goto fail;
1166 
1167 	fields = tep_event_fields(event);
1168 	CU_TEST(fields != NULL);
1169 	if (!fields)
1170 		goto fail;
1171 
1172 	for (i = 0; fields[i]; i++) {
1173 		int end = fields[i]->offset + fields[i]->size;
1174 		if (end > max)
1175 			max = end;
1176 	}
1177 	free(fields);
1178 
1179 	CU_TEST(max != 0);
1180 	if (!max)
1181 		goto fail;
1182 
1183 	/* round up to long size alignment */
1184 	max = ((max + sizeof(long) - 1)) & ~(sizeof(long) - 1);
1185 
1186 	/* Add meta header */
1187 	max += 4;
1188 
1189 	data->events_per_buf = data->data_size / max;
1190 
1191 	data->this_pid = getpid();
1192 	ret = tracefs_event_enable(instance, EVENT_SYSTEM, EVENT_NAME);
1193 	CU_TEST(ret == 0);
1194 	if (ret)
1195 		goto fail;
1196 
1197 
1198 	save_affinity();
1199 	set_affinity(0);
1200 
1201 	return 0;
1202  fail:
1203 	cleanup_trace_cpu(data);
1204 	return -1;
1205 }
1206 
shutdown_trace_cpu(struct test_cpu_data * data)1207 static void shutdown_trace_cpu(struct test_cpu_data *data)
1208 {
1209 	struct tracefs_instance *instance = data->instance;
1210 	int ret;
1211 
1212 	reset_affinity();
1213 
1214 	ret = tracefs_event_disable(instance, EVENT_SYSTEM, EVENT_NAME);
1215 	CU_TEST(ret == 0);
1216 
1217 	cleanup_trace_cpu(data);
1218 }
1219 
reset_trace_cpu(struct test_cpu_data * data,bool nonblock,bool map)1220 static void reset_trace_cpu(struct test_cpu_data *data, bool nonblock, bool map)
1221 {
1222 	close(data->fd);
1223 	tracefs_cpu_close(data->tcpu);
1224 
1225 	data->fd = make_trace_temp_file();
1226 	CU_TEST(data->fd >= 0);
1227 	if (map)
1228 		data->tcpu = tracefs_cpu_open_mapped(data->instance, 0, nonblock);
1229 	else
1230 		data->tcpu = tracefs_cpu_open(data->instance, 0, nonblock);
1231 	CU_TEST(data->tcpu != NULL);
1232 }
1233 
test_cpu_read(struct test_cpu_data * data,int expect)1234 static void test_cpu_read(struct test_cpu_data *data, int expect)
1235 {
1236 	struct tracefs_cpu *tcpu = data->tcpu;
1237 	struct kbuffer *kbuf = data->kbuf;
1238 	struct tep_record record;
1239 	void *buf = data->buf;
1240 	unsigned long long ts;
1241 	bool first = true;
1242 	int pid;
1243 	int ret;
1244 	int cnt = 0;
1245 
1246 	call_getppid(expect);
1247 
1248 	for (;;) {
1249 		ret = tracefs_cpu_read(tcpu, buf, false);
1250 		CU_TEST(ret > 0 || !first);
1251 		if (ret <= 0)
1252 			break;
1253 		first = false;
1254 		ret = kbuffer_load_subbuffer(kbuf, buf);
1255 		CU_TEST(ret == 0);
1256 		for (;;) {
1257 			record.data = kbuffer_read_event(kbuf, &ts);
1258 			if (!record.data)
1259 				break;
1260 			record.ts = ts;
1261 			pid = tep_data_pid(data->tep, &record);
1262 			if (pid == data->this_pid)
1263 				cnt++;
1264 			kbuffer_next_event(kbuf, NULL);
1265 		}
1266 	}
1267 	CU_TEST(cnt == expect);
1268 }
1269 
test_instance_trace_cpu_read(struct tracefs_instance * instance,bool map)1270 static void test_instance_trace_cpu_read(struct tracefs_instance *instance, bool map)
1271 {
1272 	struct test_cpu_data data;
1273 
1274 	if (setup_trace_cpu(instance, &data, true, map))
1275 		return;
1276 
1277 	test_cpu_read(&data, 1);
1278 	test_cpu_read(&data, data.events_per_buf / 2);
1279 	test_cpu_read(&data, data.events_per_buf);
1280 	test_cpu_read(&data, data.events_per_buf + 1);
1281 	test_cpu_read(&data, data.events_per_buf * 50);
1282 
1283 	shutdown_trace_cpu(&data);
1284 }
1285 
test_trace_cpu_read(void)1286 static void test_trace_cpu_read(void)
1287 {
1288 	test_instance_trace_cpu_read(NULL, false);
1289 	if (mapping_is_supported)
1290 		test_instance_trace_cpu_read(NULL, true);
1291 
1292 	test_instance_trace_cpu_read(test_instance, false);
1293 	if (mapping_is_supported)
1294 		test_instance_trace_cpu_read(test_instance, true);
1295 }
1296 
trace_cpu_read_thread(void * arg)1297 static void *trace_cpu_read_thread(void *arg)
1298 {
1299 	struct test_cpu_data *data = arg;
1300 	struct tracefs_cpu *tcpu = data->tcpu;
1301 	struct kbuffer *kbuf;
1302 	long ret = 0;
1303 
1304 	pthread_barrier_wait(&trace_barrier);
1305 
1306 	kbuf = tracefs_cpu_read_buf(tcpu, false);
1307 	CU_TEST(kbuf != NULL);
1308 	data->done = true;
1309 
1310 	return (void *)ret;
1311 }
1312 
test_cpu_read_buf_percent(struct test_cpu_data * data,int percent)1313 static void test_cpu_read_buf_percent(struct test_cpu_data *data, int percent)
1314 {
1315 	char buffer[tracefs_cpu_read_size(data->tcpu)];
1316 	pthread_t thread;
1317 	int save_percent;
1318 	ssize_t expect;
1319 	int ret;
1320 
1321 	tracefs_instance_clear(data->instance);
1322 
1323 	save_percent = tracefs_instance_get_buffer_percent(data->instance);
1324 	CU_TEST(save_percent >= 0);
1325 
1326 	ret = tracefs_instance_set_buffer_percent(data->instance, percent);
1327 	CU_TEST(ret == 0);
1328 
1329 	data->done = false;
1330 
1331 	pthread_barrier_init(&trace_barrier, NULL, 2);
1332 
1333 	pthread_create(&thread, NULL, trace_cpu_read_thread, data);
1334 
1335 	pthread_barrier_wait(&trace_barrier);
1336 
1337 	msleep(100);
1338 
1339 	CU_TEST(data->done == false);
1340 
1341 	/* For percent == 0, just test for any data */
1342 	if (percent) {
1343 		expect = data->nr_subbufs * data->events_per_buf * percent / 100;
1344 
1345 		/* Add just under the percent */
1346 		expect -= data->events_per_buf;
1347 		CU_TEST(expect > 0);
1348 
1349 		call_getppid(expect);
1350 
1351 		msleep(100);
1352 
1353 		CU_TEST(data->done == false);
1354 
1355 		/* Add just over the percent */
1356 		expect = data->events_per_buf * 2;
1357 	} else {
1358 		expect = data->events_per_buf;
1359 	}
1360 
1361 	call_getppid(expect);
1362 
1363 	msleep(100);
1364 
1365 	CU_TEST(data->done == true);
1366 
1367 	while (tracefs_cpu_flush(data->tcpu, buffer))
1368 		;
1369 
1370 	tracefs_cpu_stop(data->tcpu);
1371 	pthread_join(thread, NULL);
1372 
1373 	ret = tracefs_instance_set_buffer_percent(data->instance, save_percent);
1374 	CU_TEST(ret == 0);
1375 }
1376 
test_instance_trace_cpu_read_buf_percent(struct tracefs_instance * instance,bool map)1377 static void test_instance_trace_cpu_read_buf_percent(struct tracefs_instance *instance, bool map)
1378 {
1379 	struct test_cpu_data data;
1380 
1381 	if (setup_trace_cpu(instance, &data, false, map))
1382 		return;
1383 
1384 	test_cpu_read_buf_percent(&data, 0);
1385 
1386 	reset_trace_cpu(&data, false, map);
1387 
1388 	test_cpu_read_buf_percent(&data, 1);
1389 
1390 	reset_trace_cpu(&data, false, map);
1391 
1392 	test_cpu_read_buf_percent(&data, 50);
1393 
1394 	reset_trace_cpu(&data, false, map);
1395 
1396 	test_cpu_read_buf_percent(&data, 100);
1397 
1398 	shutdown_trace_cpu(&data);
1399 }
1400 
test_trace_cpu_read_buf_percent(void)1401 static void test_trace_cpu_read_buf_percent(void)
1402 {
1403 	test_instance_trace_cpu_read_buf_percent(NULL, false);
1404 	if (mapping_is_supported)
1405 		test_instance_trace_cpu_read_buf_percent(NULL, true);
1406 	test_instance_trace_cpu_read_buf_percent(test_instance, false);
1407 	if (mapping_is_supported)
1408 		test_instance_trace_cpu_read_buf_percent(test_instance, true);
1409 }
1410 
1411 struct follow_data {
1412 	struct tep_event *sched_switch;
1413 	struct tep_event *sched_waking;
1414 	struct tep_event *getppid;
1415 	struct tep_event *function;
1416 	int missed;
1417 	int switch_hit;
1418 	int waking_hit;
1419 	int getppid_hit;
1420 	int missed_hit;
1421 };
1422 
clear_hits(struct follow_data * fdata)1423 static void clear_hits(struct follow_data *fdata)
1424 {
1425 	fdata->switch_hit = 0;
1426 	fdata->waking_hit = 0;
1427 	fdata->getppid_hit = 0;
1428 	fdata->missed_hit = 0;
1429 }
1430 
switch_callback(struct tep_event * event,struct tep_record * record,int cpu,void * data)1431 static int switch_callback(struct tep_event *event, struct tep_record *record,
1432 			   int cpu, void *data)
1433 {
1434 	struct follow_data *fdata = data;
1435 
1436 	CU_TEST(cpu == record->cpu);
1437 	CU_TEST(event->id == fdata->sched_switch->id);
1438 	fdata->switch_hit++;
1439 	return 0;
1440 }
1441 
waking_callback(struct tep_event * event,struct tep_record * record,int cpu,void * data)1442 static int waking_callback(struct tep_event *event, struct tep_record *record,
1443 			   int cpu, void *data)
1444 {
1445 	struct follow_data *fdata = data;
1446 
1447 	CU_TEST(cpu == record->cpu);
1448 	CU_TEST(event->id == fdata->sched_waking->id);
1449 	fdata->waking_hit++;
1450 	return 0;
1451 }
1452 
getppid_callback(struct tep_event * event,struct tep_record * record,int cpu,void * data)1453 static int getppid_callback(struct tep_event *event, struct tep_record *record,
1454 			    int cpu, void *data)
1455 {
1456 	struct follow_data *fdata = data;
1457 
1458 	CU_TEST(cpu == record->cpu);
1459 	CU_TEST(event->id == fdata->getppid->id);
1460 	fdata->getppid_hit++;
1461 	return 0;
1462 }
1463 
function_callback(struct tep_event * event,struct tep_record * record,int cpu,void * data)1464 static int function_callback(struct tep_event *event, struct tep_record *record,
1465 			     int cpu, void *data)
1466 {
1467 	struct follow_data *fdata = data;
1468 
1469 	CU_TEST(cpu == record->cpu);
1470 	CU_TEST(event->id == fdata->function->id);
1471 	return 0;
1472 }
1473 
missed_callback(struct tep_event * event,struct tep_record * record,int cpu,void * data)1474 static int missed_callback(struct tep_event *event, struct tep_record *record,
1475 			     int cpu, void *data)
1476 {
1477 	struct follow_data *fdata = data;
1478 
1479 	fdata->missed = record->missed_events;
1480 	fdata->missed_hit++;
1481 	return 0;
1482 }
1483 
all_callback(struct tep_event * event,struct tep_record * record,int cpu,void * data)1484 static int all_callback(struct tep_event *event, struct tep_record *record,
1485 			int cpu, void *data)
1486 {
1487 	struct follow_data *fdata = data;
1488 
1489 	CU_TEST(fdata->missed == record->missed_events);
1490 	fdata->missed = 0;
1491 	return 0;
1492 }
1493 
stop_thread(void * arg)1494 static void *stop_thread(void *arg)
1495 {
1496 	struct tracefs_instance *instance = arg;
1497 
1498 	sleep(1);
1499 	tracefs_iterate_stop(instance);
1500 	return NULL;
1501 }
1502 
test_instance_follow_events(struct tracefs_instance * instance)1503 static void test_instance_follow_events(struct tracefs_instance *instance)
1504 {
1505 	struct follow_data fdata;
1506 	struct tep_handle *tep;
1507 	pthread_t thread;
1508 	int ret;
1509 
1510 	memset(&fdata, 0, sizeof(fdata));
1511 
1512 	tep = test_tep;
1513 
1514 	fdata.sched_switch = tep_find_event_by_name(tep, "sched", "sched_switch");
1515 	CU_TEST(fdata.sched_switch != NULL);
1516 	if (!fdata.sched_switch)
1517 		return;
1518 
1519 	fdata.sched_waking = tep_find_event_by_name(tep, "sched", "sched_waking");
1520 	CU_TEST(fdata.sched_waking != NULL);
1521 	if (!fdata.sched_waking)
1522 		return;
1523 
1524 	fdata.function = tep_find_event_by_name(tep, "ftrace", "function");
1525 	CU_TEST(fdata.function != NULL);
1526 	if (!fdata.function)
1527 		return;
1528 
1529 	ret = tracefs_follow_event(tep, instance, "sched", "sched_switch",
1530 				   switch_callback, &fdata);
1531 	CU_TEST(ret == 0);
1532 
1533 	ret = tracefs_follow_event(tep, instance, "sched", "sched_waking",
1534 				   waking_callback, &fdata);
1535 	CU_TEST(ret == 0);
1536 
1537 	ret = tracefs_follow_event(tep, instance, "ftrace", "function",
1538 				   function_callback, &fdata);
1539 	CU_TEST(ret == 0);
1540 
1541 	ret = tracefs_follow_missed_events(instance, missed_callback, &fdata);
1542 	CU_TEST(ret == 0);
1543 
1544 	ret = tracefs_event_enable(instance, "sched", "sched_switch");
1545 	CU_TEST(ret == 0);
1546 
1547 	ret = tracefs_event_enable(instance, "sched", "sched_waking");
1548 	CU_TEST(ret == 0);
1549 
1550 	ret = tracefs_tracer_set(instance, TRACEFS_TRACER_FUNCTION);
1551 	CU_TEST(ret == 0);
1552 
1553 	pthread_create(&thread, NULL, stop_thread, instance);
1554 
1555 	ret = tracefs_iterate_raw_events(tep, instance, NULL, 0, all_callback, &fdata);
1556 	CU_TEST(ret == 0);
1557 
1558 	ret = tracefs_follow_event_clear(instance, NULL, NULL);
1559 	CU_TEST(ret == 0);
1560 	ret = tracefs_follow_missed_events_clear(instance);
1561 	CU_TEST(ret == 0);
1562 
1563 	pthread_join(thread, NULL);
1564 
1565 	tracefs_tracer_clear(instance);
1566 	tracefs_event_disable(instance, NULL, NULL);
1567 }
1568 
test_follow_events(void)1569 static void test_follow_events(void)
1570 {
1571 	test_instance_follow_events(NULL);
1572 	test_instance_follow_events(test_instance);
1573 }
1574 
test_instance_follow_events_clear(struct tracefs_instance * instance)1575 static void test_instance_follow_events_clear(struct tracefs_instance *instance)
1576 {
1577 	struct follow_data fdata;
1578 	struct tep_handle *tep;
1579 	unsigned long page_size;
1580 	size_t save_size;
1581 	char **list;
1582 	int ret;
1583 
1584 	memset(&fdata, 0, sizeof(fdata));
1585 
1586 	tep = test_tep;
1587 
1588 	fdata.sched_switch = tep_find_event_by_name(tep, "sched", "sched_switch");
1589 	CU_TEST(fdata.sched_switch != NULL);
1590 	if (!fdata.sched_switch)
1591 		return;
1592 
1593 	fdata.sched_waking = tep_find_event_by_name(tep, "sched", "sched_waking");
1594 	CU_TEST(fdata.sched_waking != NULL);
1595 	if (!fdata.sched_waking)
1596 		return;
1597 
1598 	fdata.getppid = tep_find_event_by_name(tep, EVENT_SYSTEM, EVENT_NAME);
1599 	CU_TEST(fdata.getppid != NULL);
1600 	if (!fdata.getppid)
1601 		return;
1602 
1603 	ret = tracefs_follow_event(tep, instance, "sched", "sched_switch",
1604 				   switch_callback, &fdata);
1605 	CU_TEST(ret == 0);
1606 
1607 	ret = tracefs_follow_event(tep, instance, "sched", "sched_waking",
1608 				   waking_callback, &fdata);
1609 	CU_TEST(ret == 0);
1610 
1611 	ret = tracefs_follow_event(tep, instance, EVENT_SYSTEM, EVENT_NAME,
1612 				   getppid_callback, &fdata);
1613 	CU_TEST(ret == 0);
1614 
1615 	ret = tracefs_follow_missed_events(instance, missed_callback, &fdata);
1616 	CU_TEST(ret == 0);
1617 
1618 	ret = tracefs_event_enable(instance, "sched", "sched_switch");
1619 	CU_TEST(ret == 0);
1620 
1621 	ret = tracefs_event_enable(instance, "sched", "sched_waking");
1622 	CU_TEST(ret == 0);
1623 
1624 	ret = tracefs_event_enable(instance, EVENT_SYSTEM, EVENT_NAME);
1625 	CU_TEST(ret == 0);
1626 
1627 	tracefs_trace_on(instance);
1628 	call_getppid(100);
1629 	msleep(100);
1630 	tracefs_trace_off(instance);
1631 
1632 	ret = tracefs_iterate_raw_events(tep, instance, NULL, 0, NULL, &fdata);
1633 	CU_TEST(ret == 0);
1634 
1635 	/* Make sure all are hit */
1636 	CU_TEST(fdata.switch_hit > 0);
1637 	CU_TEST(fdata.waking_hit > 0);
1638 	CU_TEST(fdata.getppid_hit == 100);
1639 	/* No missed events */
1640 	CU_TEST(fdata.missed_hit == 0);
1641 	clear_hits(&fdata);
1642 
1643 
1644 
1645 	/* Disable getppid and do the same thing */
1646 	ret = tracefs_follow_event_clear(instance, EVENT_SYSTEM, EVENT_NAME);
1647 	CU_TEST(ret == 0);
1648 
1649 	tracefs_trace_on(instance);
1650 	call_getppid(100);
1651 	msleep(100);
1652 	tracefs_trace_off(instance);
1653 
1654 	ret = tracefs_iterate_raw_events(tep, instance, NULL, 0, NULL, &fdata);
1655 	CU_TEST(ret == 0);
1656 
1657 	/* All but getppid should be hit */
1658 	CU_TEST(fdata.switch_hit > 0);
1659 	CU_TEST(fdata.waking_hit > 0);
1660 	CU_TEST(fdata.getppid_hit == 0);
1661 	/* No missed events */
1662 	CU_TEST(fdata.missed_hit == 0);
1663 	clear_hits(&fdata);
1664 
1665 
1666 
1667 	/* Add function and remove sched */
1668 	ret = tracefs_follow_event(tep, instance, "ftrace", "function",
1669 				   function_callback, &fdata);
1670 	CU_TEST(ret == 0);
1671 	ret = tracefs_follow_event_clear(instance, "sched", NULL);
1672 	CU_TEST(ret == 0);
1673 
1674 	tracefs_trace_on(instance);
1675 	call_getppid(100);
1676 	system("ls -l /usr/bin > /dev/null");
1677 	tracefs_trace_off(instance);
1678 
1679 	ret = tracefs_iterate_raw_events(tep, instance, NULL, 0, NULL, &fdata);
1680 	CU_TEST(ret == 0);
1681 
1682 	/* Nothing should have been hit */
1683 	CU_TEST(fdata.switch_hit == 0);
1684 	CU_TEST(fdata.waking_hit == 0);
1685 	CU_TEST(fdata.getppid_hit == 0);
1686 	/* No missed events */
1687 	CU_TEST(fdata.missed_hit == 0);
1688 	clear_hits(&fdata);
1689 
1690 
1691 	/* Enable function tracing and see if we missed hits */
1692 	ret = tracefs_tracer_set(instance, TRACEFS_TRACER_FUNCTION);
1693 	CU_TEST(ret == 0);
1694 
1695 	fdata.function = tep_find_event_by_name(tep, "ftrace", "function");
1696 	CU_TEST(fdata.function != NULL);
1697 	if (!fdata.function)
1698 		return;
1699 
1700 	/* Shrink the buffer to make sure we have missed events */
1701 	page_size = getpagesize();
1702 	save_size = tracefs_instance_get_buffer_size(instance, 0);
1703 	ret = tracefs_instance_set_buffer_size(instance, page_size * 4, 0);
1704 	CU_TEST(ret == 0);
1705 
1706 	tracefs_trace_on(instance);
1707 	call_getppid(100);
1708 	/* Stir the kernel a bit */
1709 	list = tracefs_event_systems(NULL);
1710 	tracefs_list_free(list);
1711 	system("ls -l /usr/bin > /dev/null");
1712 	tracefs_trace_off(instance);
1713 
1714 	ret = tracefs_iterate_raw_events(tep, instance, NULL, 0, NULL, &fdata);
1715 	CU_TEST(ret == 0);
1716 
1717 	ret = tracefs_instance_set_buffer_size(instance, save_size, 0);
1718 	CU_TEST(ret == 0);
1719 
1720 	/* Nothing should have been hit */
1721 	CU_TEST(fdata.switch_hit == 0);
1722 	CU_TEST(fdata.waking_hit == 0);
1723 	CU_TEST(fdata.getppid_hit == 0);
1724 	/* We should have missed events! */
1725 	CU_TEST(fdata.missed_hit > 0);
1726 	clear_hits(&fdata);
1727 
1728 
1729 	/* Now remove missed events follower */
1730 	ret = tracefs_follow_missed_events_clear(instance);
1731 	CU_TEST(ret == 0);
1732 
1733 	tracefs_trace_on(instance);
1734 	call_getppid(100);
1735 	sleep(1);
1736 	tracefs_trace_off(instance);
1737 
1738 	ret = tracefs_iterate_raw_events(tep, instance, NULL, 0, NULL, &fdata);
1739 	CU_TEST(ret == 0);
1740 
1741 	/* Nothing should have been hit */
1742 	CU_TEST(fdata.switch_hit == 0);
1743 	CU_TEST(fdata.waking_hit == 0);
1744 	CU_TEST(fdata.getppid_hit == 0);
1745 	/* No missed events either */
1746 	CU_TEST(fdata.missed_hit == 0);
1747 	clear_hits(&fdata);
1748 
1749 	/* Turn everything off */
1750 	tracefs_tracer_clear(instance);
1751 	tracefs_event_disable(instance, NULL, NULL);
1752 
1753 	tracefs_trace_on(instance);
1754 
1755 	/* Clear the function follower */
1756 	ret = tracefs_follow_event_clear(instance, NULL, "function");
1757 
1758 	/* Should not have any more followers */
1759 	ret = tracefs_follow_event_clear(instance, NULL, NULL);
1760 	CU_TEST(ret != 0);
1761 
1762 	/* Nor missed event followers */
1763 	ret = tracefs_follow_missed_events_clear(instance);
1764 	CU_TEST(ret != 0);
1765 }
1766 
test_follow_events_clear(void)1767 static void test_follow_events_clear(void)
1768 {
1769 	test_instance_follow_events_clear(NULL);
1770 	test_instance_follow_events_clear(test_instance);
1771 }
1772 
1773 extern char *find_tracing_dir(bool debugfs, bool mount);
test_mounting(void)1774 static void test_mounting(void)
1775 {
1776 	const char *tracing_dir;
1777 	const char *debug_dir;
1778 	struct stat st;
1779 	char *save_tracing = NULL;
1780 	char *save_debug = NULL;
1781 	char *path;
1782 	char *dir;
1783 	int ret;
1784 
1785 	/* First, unmount all instances of debugfs */
1786 	do {
1787 		dir = find_tracing_dir(true, false);
1788 		if (dir) {
1789 			ret = umount(dir);
1790 			CU_TEST(ret == 0);
1791 			if (ret < 0)
1792 				return;
1793 			/* Save the first instance that's not /sys/kernel/debug */
1794 			if (!save_debug && strcmp(dir, DEBUGFS_DEFAULT_PATH) != 0)
1795 				save_debug = dir;
1796 			else
1797 				free(dir);
1798 		}
1799 	} while (dir);
1800 
1801 	/* Next, unmount all instances of tracefs */
1802 	do {
1803 		dir = find_tracing_dir(false, false);
1804 		if (dir) {
1805 			ret = umount(dir);
1806 			CU_TEST(ret == 0);
1807 			if (ret < 0)
1808 				return;
1809 			/* Save the first instance that's not in /sys/kernel/ */
1810 			if (!save_tracing && strncmp(dir, "/sys/kernel/", 12) != 0)
1811 				save_tracing = dir;
1812 			else
1813 				free(dir);
1814 		}
1815 	} while (dir);
1816 
1817 	/* Mount first the tracing dir (which should mount at /sys/kernel/tracing */
1818 	tracing_dir = tracefs_tracing_dir();
1819 	CU_TEST(tracing_dir != NULL);
1820 	if (tracing_dir != NULL) {
1821 		CU_TEST(strcmp(tracing_dir, TRACEFS_DEFAULT_PATH) == 0 ||
1822 			strcmp(tracing_dir, TRACEFS_DEFAULT2_PATH) == 0);
1823 		if (strncmp(tracing_dir, "/sys/kernel/", 12) != 0)
1824 			printf("Tracing directory mounted at '%s'\n",
1825 			       tracing_dir);
1826 
1827 		/* Make sure the directory has content.*/
1828 		asprintf(&path, "%s/trace", tracing_dir);
1829 		CU_TEST(stat(path, &st) == 0);
1830 		free(path);
1831 	}
1832 
1833 	/* Now mount debugfs dir, which should mount at /sys/kernel/debug */
1834 	debug_dir = tracefs_debug_dir();
1835 	CU_TEST(debug_dir != NULL);
1836 	if (debug_dir != NULL) {
1837 		CU_TEST(strcmp(debug_dir, DEBUGFS_DEFAULT_PATH) == 0);
1838 		if (strcmp(debug_dir, DEBUGFS_DEFAULT_PATH) != 0)
1839 			printf("debug directory mounted at '%s'\n",
1840 			       debug_dir);
1841 
1842 		/* Make sure the directory has content.*/
1843 		asprintf(&path, "%s/tracing", debug_dir);
1844 		CU_TEST(stat(path, &st) == 0);
1845 		free(path);
1846 	}
1847 
1848 	if (save_debug)
1849 		mount("debugfs", save_debug, "debugfs", 0, NULL);
1850 
1851 	if (save_tracing &&
1852 	    (!save_debug || strncmp(save_debug, save_tracing, strlen(save_debug)) != 0))
1853 		mount("tracefs", save_tracing, "tracefs", 0, NULL);
1854 
1855 	free(save_debug);
1856 	free(save_tracing);
1857 }
1858 
read_trace_cpu_file(struct test_cpu_data * data)1859 static int read_trace_cpu_file(struct test_cpu_data *data)
1860 {
1861 	unsigned long long ts;
1862 	struct tep_record record;
1863 	struct kbuffer *kbuf = data->kbuf;
1864 	void *buf = data->buf;
1865 	bool first = true;
1866 	int bufsize = data->bufsize;
1867 	int fd = data->fd;
1868 	int missed;
1869 	int pid;
1870 	int ret;
1871 	int cnt = 0;
1872 
1873 	ret = lseek64(fd, 0, SEEK_SET);
1874 	CU_TEST(ret == 0);
1875 	if (ret)
1876 		return -1;
1877 
1878 	for (;;) {
1879 		ret = read(fd, buf, bufsize);
1880 		CU_TEST(ret > 0 || !first);
1881 		if (ret <= 0)
1882 			break;
1883 		first = false;
1884 
1885 		ret = kbuffer_load_subbuffer(kbuf, buf);
1886 		CU_TEST(ret == 0);
1887 		missed = kbuffer_missed_events(kbuf);
1888 		if (missed)
1889 			printf("missed events %d\n", missed);
1890 		for (;;) {
1891 			record.data = kbuffer_read_event(kbuf, &ts);
1892 			if (!record.data)
1893 				break;
1894 			record.ts = ts;
1895 			pid = tep_data_pid(data->tep, &record);
1896 			if (pid == data->this_pid)
1897 				cnt++;
1898 			kbuffer_next_event(kbuf, NULL);
1899 		}
1900 	}
1901 	return ret == 0 ? cnt : ret;
1902 }
1903 
trace_cpu_thread(void * arg)1904 static void *trace_cpu_thread(void *arg)
1905 {
1906 	struct test_cpu_data *data = arg;
1907 	struct tracefs_cpu *tcpu = data->tcpu;
1908 	int fd = data->fd;
1909 	long ret = 0;
1910 
1911 	thread_affinity();
1912 
1913 	while (!data->done && ret >= 0) {
1914 		ret = tracefs_cpu_write(tcpu, fd, false);
1915 		if (ret < 0 && errno == EAGAIN)
1916 			ret = 0;
1917 	}
1918 	if (ret >= 0 || errno == EAGAIN) {
1919 		do {
1920 			ret = tracefs_cpu_flush_write(tcpu, fd);
1921 		} while (ret > 0);
1922 	}
1923 
1924 	return (void *)ret;
1925 }
1926 
test_cpu_pipe(struct test_cpu_data * data,int expect)1927 static void test_cpu_pipe(struct test_cpu_data *data, int expect)
1928 {
1929 	pthread_t thread;
1930 	void *retval;
1931 	long ret;
1932 	int cnt;
1933 
1934 	tracefs_instance_file_clear(data->instance, "trace");
1935 	ftruncate(data->fd, 0);
1936 
1937 	data->done = false;
1938 
1939 	pthread_create(&thread, NULL, trace_cpu_thread, data);
1940 	sleep(1);
1941 
1942 	call_getppid(expect);
1943 
1944 	data->done = true;
1945 	tracefs_cpu_stop(data->tcpu);
1946 	pthread_join(thread, &retval);
1947 	ret = (long)retval;
1948 	CU_TEST(ret >= 0);
1949 
1950 	cnt = read_trace_cpu_file(data);
1951 
1952 	CU_TEST(cnt == expect);
1953 }
1954 
test_instance_trace_cpu_pipe(struct tracefs_instance * instance,bool map)1955 static void test_instance_trace_cpu_pipe(struct tracefs_instance *instance, bool map)
1956 {
1957 	struct test_cpu_data data;
1958 
1959 	if (setup_trace_cpu(instance, &data, true, map))
1960 		return;
1961 
1962 	test_cpu_pipe(&data, 1);
1963 	test_cpu_pipe(&data, data.events_per_buf / 2);
1964 	test_cpu_pipe(&data, data.events_per_buf);
1965 	test_cpu_pipe(&data, data.events_per_buf + 1);
1966 	test_cpu_pipe(&data, data.events_per_buf * 1000);
1967 
1968 	shutdown_trace_cpu(&data);
1969 }
1970 
test_trace_cpu_pipe(void)1971 static void test_trace_cpu_pipe(void)
1972 {
1973 	test_instance_trace_cpu_pipe(NULL, false);
1974 	if (mapping_is_supported)
1975 		test_instance_trace_cpu_pipe(NULL, true);
1976 	test_instance_trace_cpu_pipe(test_instance, false);
1977 	if (mapping_is_supported)
1978 		test_instance_trace_cpu_pipe(test_instance, true);
1979 }
1980 
get_dynevents_check(enum tracefs_dynevent_type types,int count)1981 static struct tracefs_dynevent **get_dynevents_check(enum tracefs_dynevent_type types, int count)
1982 {
1983 	struct tracefs_dynevent **devents;
1984 	int i;
1985 
1986 	devents = tracefs_dynevent_get_all(types, NULL);
1987 	if (count) {
1988 		CU_TEST(devents != NULL);
1989 		if (!devents)
1990 			return NULL;
1991 		i = 0;
1992 		while (devents[i])
1993 			i++;
1994 		CU_TEST(i == count);
1995 	} else {
1996 		CU_TEST(devents == NULL);
1997 	}
1998 
1999 	return devents;
2000 }
2001 
2002 
2003 struct test_synth {
2004 	char *name;
2005 	char *start_system;
2006 	char *start_event;
2007 	char *end_system;
2008 	char *end_event;
2009 	char *start_match_field;
2010 	char *end_match_field;
2011 	char *match_name;
2012 };
2013 
test_synth_compare(struct test_synth * sevents,struct tracefs_dynevent ** devents)2014 static void test_synth_compare(struct test_synth *sevents, struct tracefs_dynevent **devents)
2015 {
2016 	enum tracefs_dynevent_type stype;
2017 	char *format;
2018 	char *event;
2019 	int i;
2020 
2021 	for (i = 0; devents && devents[i]; i++) {
2022 		stype = tracefs_dynevent_info(devents[i], NULL,
2023 					      &event, NULL, NULL, &format);
2024 		CU_TEST(stype == TRACEFS_DYNEVENT_SYNTH);
2025 		if (stype != TRACEFS_DYNEVENT_SYNTH)
2026 			continue;
2027 		CU_TEST(event && sevents[i].name && strcmp(event, sevents[i].name) == 0);
2028 		if (sevents[i].match_name) {
2029 			CU_TEST(strstr(format, sevents[i].match_name) != NULL);
2030 		}
2031 		free(event);
2032 		free(format);
2033 	}
2034 	CU_TEST(devents == NULL || devents[i] == NULL);
2035 }
2036 
destroy_dynevents(unsigned int type)2037 static void destroy_dynevents(unsigned int type)
2038 {
2039 	int ret;
2040 
2041 	ret = tracefs_dynevent_destroy_all(type, true);
2042 	CU_TEST(ret == 0);
2043 	get_dynevents_check(type, 0);
2044 }
2045 
test_instance_synthetic(struct tracefs_instance * instance)2046 static void test_instance_synthetic(struct tracefs_instance *instance)
2047 {
2048 	struct test_synth sevents[] = {
2049 		{"synth_1", "sched", "sched_waking", "sched", "sched_switch", "pid", "next_pid", "pid_match"},
2050 		{"synth_2", "syscalls", "sys_enter_openat2", "syscalls", "sys_exit_openat2", "__syscall_nr", "__syscall_nr", "nr_match"},
2051 	};
2052 	int sevents_count = sizeof(sevents) / sizeof((sevents)[0]);
2053 	struct tracefs_dynevent **devents;
2054 	struct tracefs_synth **synth;
2055 	struct tep_handle *tep;
2056 	int ret;
2057 	int i;
2058 
2059 	synth = calloc(sevents_count + 1, sizeof(*synth));
2060 
2061 	tep = tracefs_local_events(NULL);
2062 	CU_TEST(tep != NULL);
2063 
2064 	/* kprobes APIs */
2065 	destroy_dynevents(TRACEFS_DYNEVENT_SYNTH);
2066 
2067 	for (i = 0; i < sevents_count; i++) {
2068 		synth[i] = tracefs_synth_alloc(tep,  sevents[i].name,
2069 					       sevents[i].start_system, sevents[i].start_event,
2070 					       sevents[i].end_system, sevents[i].end_event,
2071 					       sevents[i].start_match_field, sevents[i].end_match_field,
2072 					       sevents[i].match_name);
2073 		CU_TEST(synth[i] != NULL);
2074 	}
2075 
2076 	get_dynevents_check(TRACEFS_DYNEVENT_SYNTH, 0);
2077 
2078 	for (i = 0; i < sevents_count; i++) {
2079 		ret = tracefs_synth_create(synth[i]);
2080 		CU_TEST(ret == 0);
2081 	}
2082 
2083 	devents = get_dynevents_check(TRACEFS_DYNEVENT_SYNTH, sevents_count);
2084 	CU_TEST(devents != NULL);
2085 	if (!devents)
2086 		goto out;
2087 	CU_TEST(devents[sevents_count] == NULL);
2088 	if (devents[sevents_count])
2089 		goto out;
2090 
2091 	test_synth_compare(sevents, devents);
2092 	tracefs_dynevent_list_free(devents);
2093 
2094 	for (i = 0; i < sevents_count; i++) {
2095 		ret = tracefs_synth_destroy(synth[i]);
2096 		CU_TEST(ret == 0);
2097 	}
2098 
2099 	get_dynevents_check(TRACEFS_DYNEVENT_SYNTH, 0);
2100 
2101  out:
2102 	for (i = 0; i < sevents_count; i++)
2103 		tracefs_synth_free(synth[i]);
2104 
2105 	tep_free(tep);
2106 	free(synth);
2107 }
2108 
test_synthetic(void)2109 static void test_synthetic(void)
2110 {
2111 	test_instance_synthetic(test_instance);
2112 }
2113 
test_trace_file(void)2114 static void test_trace_file(void)
2115 {
2116 	const char *tmp = get_rand_str();
2117 	const char *tdir;
2118 	struct stat st;
2119 	char *file;
2120 
2121 	tdir  = tracefs_tracing_dir();
2122 	CU_TEST(tdir != NULL);
2123 	CU_TEST(stat(tdir, &st) == 0);
2124 	CU_TEST(S_ISDIR(st.st_mode));
2125 
2126 	file = tracefs_get_tracing_file(NULL);
2127 	CU_TEST(file == NULL);
2128 	file = tracefs_get_tracing_file(tmp);
2129 	CU_TEST(file != NULL);
2130 	CU_TEST(stat(file, &st) != 0);
2131 	tracefs_put_tracing_file(file);
2132 
2133 	file = tracefs_get_tracing_file("trace");
2134 	CU_TEST(file != NULL);
2135 	CU_TEST(stat(file, &st) == 0);
2136 	tracefs_put_tracing_file(file);
2137 }
2138 
test_instance_file_read(struct tracefs_instance * inst,const char * fname)2139 static void test_instance_file_read(struct tracefs_instance *inst, const char *fname)
2140 {
2141 	const char *tdir  = tracefs_tracing_dir();
2142 	char buf[BUFSIZ];
2143 	char *fpath;
2144 	char *file;
2145 	size_t fsize = 0;
2146 	int size = 0;
2147 	int fd;
2148 
2149 	if (inst) {
2150 		CU_TEST(asprintf(&fpath, "%s/instances/%s/%s",
2151 			tdir, tracefs_instance_get_name(inst), fname) > 0);
2152 	} else {
2153 		CU_TEST(asprintf(&fpath, "%s/%s", tdir, fname) > 0);
2154 	}
2155 
2156 	memset(buf, 0, BUFSIZ);
2157 	fd = open(fpath, O_RDONLY);
2158 	CU_TEST(fd >= 0);
2159 	fsize = read(fd, buf, BUFSIZ);
2160 	CU_TEST(fsize >= 0);
2161 	close(fd);
2162 	buf[BUFSIZ - 1] = 0;
2163 
2164 	file = tracefs_instance_file_read(inst, fname, &size);
2165 	CU_TEST(file != NULL);
2166 	CU_TEST(size == fsize);
2167 	CU_TEST(strcmp(file, buf) == 0);
2168 
2169 	free(fpath);
2170 	free(file);
2171 }
2172 
2173 struct probe_test {
2174 	enum tracefs_dynevent_type type;
2175 	char *prefix;
2176 	char *system;
2177 	char *event;
2178 	char *address;
2179 	char *format;
2180 };
2181 
check_probes(struct probe_test * probes,int count,struct tracefs_dynevent ** devents,bool in_system,struct tracefs_instance * instance,struct tep_handle * tep)2182 static bool check_probes(struct probe_test *probes, int count,
2183 			 struct tracefs_dynevent **devents, bool in_system,
2184 			 struct tracefs_instance *instance, struct tep_handle *tep)
2185 {
2186 	enum tracefs_dynevent_type type;
2187 	struct tep_event *tevent;
2188 	char *ename;
2189 	char *address;
2190 	char *event;
2191 	char *system;
2192 	char *format;
2193 	char *prefix;
2194 	int found = 0;
2195 	int ret;
2196 	int i, j;
2197 
2198 	for (i = 0; devents && devents[i]; i++) {
2199 		type = tracefs_dynevent_info(devents[i], &system,
2200 					     &event, &prefix, &address, &format);
2201 		for (j = 0; j < count; j++) {
2202 			if (type != probes[j].type)
2203 				continue;
2204 			if (probes[j].event)
2205 				ename = probes[j].event;
2206 			else
2207 				ename = probes[j].address;
2208 			if (strcmp(ename, event))
2209 				continue;
2210 			if (probes[j].system) {
2211 				CU_TEST(strcmp(probes[j].system, system) == 0);
2212 			}
2213 			CU_TEST(strcmp(probes[j].address, address) == 0);
2214 			if (probes[j].format) {
2215 				CU_TEST(strcmp(probes[j].format, format) == 0);
2216 			}
2217 			if (probes[j].prefix) {
2218 				CU_TEST(strcmp(probes[j].prefix, prefix) == 0);
2219 			}
2220 			ret = tracefs_event_enable(instance, system, event);
2221 			if (in_system) {
2222 				CU_TEST(ret == 0);
2223 			} else {
2224 				CU_TEST(ret != 0);
2225 			}
2226 			ret = tracefs_event_disable(instance, system, event);
2227 			if (in_system) {
2228 				CU_TEST(ret == 0);
2229 			} else {
2230 				CU_TEST(ret != 0);
2231 			}
2232 
2233 			tevent =  tracefs_dynevent_get_event(tep, devents[i]);
2234 			if (in_system) {
2235 				CU_TEST(tevent != NULL);
2236 				if (tevent) {
2237 					CU_TEST(strcmp(tevent->name, event) == 0);
2238 					CU_TEST(strcmp(tevent->system, system) == 0);
2239 				}
2240 			} else {
2241 				CU_TEST(tevent == NULL);
2242 			}
2243 
2244 			found++;
2245 			break;
2246 		}
2247 		free(system);
2248 		free(event);
2249 		free(prefix);
2250 		free(address);
2251 		free(format);
2252 	}
2253 
2254 	CU_TEST(found == count);
2255 	if (found != count)
2256 		return false;
2257 
2258 	return true;
2259 }
2260 
test_kprobes_instance(struct tracefs_instance * instance)2261 static void test_kprobes_instance(struct tracefs_instance *instance)
2262 {
2263 	struct probe_test ktests[] = {
2264 		{ TRACEFS_DYNEVENT_KPROBE, "p", NULL, "mkdir", "do_mkdirat", "path=+u0($arg2):ustring" },
2265 		{ TRACEFS_DYNEVENT_KPROBE, "p", NULL, "close", "close_fd", NULL },
2266 		{ TRACEFS_DYNEVENT_KPROBE, "p", "ptest", "open2", "do_sys_openat2",
2267 				  "file=+u0($arg2):ustring flags=+0($arg3):x64" },
2268 	};
2269 	struct probe_test kretests[] = {
2270 		{ TRACEFS_DYNEVENT_KRETPROBE, NULL, NULL, "retopen", "do_sys_openat2", "ret=$retval" },
2271 		{ TRACEFS_DYNEVENT_KRETPROBE, NULL, NULL, NULL, "do_sys_open", "ret=$retval" },
2272 	};
2273 	int kretprobe_count = sizeof(kretests) / sizeof((kretests)[0]);
2274 	int kprobe_count = sizeof(ktests) / sizeof((ktests)[0]);
2275 	struct tracefs_dynevent **dkretprobe;
2276 	struct tracefs_dynevent **dkprobe;
2277 	struct tracefs_dynevent **devents;
2278 	struct tep_handle *tep;
2279 	char *tmp;
2280 	int ret;
2281 	int i;
2282 
2283 	tep = tep_alloc();
2284 	CU_TEST(tep != NULL);
2285 
2286 	dkprobe = calloc(kprobe_count + 1, sizeof(*dkprobe));
2287 	dkretprobe = calloc(kretprobe_count + 1, sizeof(*dkretprobe));
2288 
2289 	/* Invalid parameters */
2290 	CU_TEST(tracefs_kprobe_alloc("test", NULL, NULL, "test") == NULL);
2291 	CU_TEST(tracefs_kretprobe_alloc("test", NULL, NULL, "test", 0) == NULL);
2292 	CU_TEST(tracefs_dynevent_create(NULL) != 0);
2293 	CU_TEST(tracefs_dynevent_info(NULL, &tmp, &tmp, &tmp, &tmp, &tmp) == TRACEFS_DYNEVENT_UNKNOWN);
2294 	CU_TEST(tracefs_kprobe_raw("test", "test", NULL, "test") != 0);
2295 	CU_TEST(tracefs_kretprobe_raw("test", "test", NULL, "test") != 0);
2296 
2297 	/* kprobes APIs */
2298 	destroy_dynevents(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE);
2299 
2300 	for (i = 0; i < kprobe_count; i++) {
2301 		dkprobe[i] = tracefs_kprobe_alloc(ktests[i].system, ktests[i].event,
2302 						  ktests[i].address, ktests[i].format);
2303 		CU_TEST(dkprobe[i] != NULL);
2304 	}
2305 	dkprobe[i] = NULL;
2306 	get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, 0);
2307 	CU_TEST(check_probes(ktests, kprobe_count, dkprobe, false, instance, tep));
2308 
2309 	for (i = 0; i < kretprobe_count; i++) {
2310 		dkretprobe[i] = tracefs_kretprobe_alloc(kretests[i].system, kretests[i].event,
2311 							kretests[i].address, kretests[i].format, 0);
2312 		CU_TEST(dkretprobe[i] != NULL);
2313 	}
2314 	dkretprobe[i] = NULL;
2315 	get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, 0);
2316 	CU_TEST(check_probes(kretests, kretprobe_count, dkretprobe, false, instance, tep));
2317 
2318 	for (i = 0; i < kprobe_count; i++) {
2319 		CU_TEST(tracefs_dynevent_create(dkprobe[i]) == 0);
2320 	}
2321 	devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE,
2322 				    kprobe_count);
2323 	CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance, tep));
2324 	CU_TEST(check_probes(kretests, kretprobe_count, dkretprobe, false, instance, tep));
2325 	tracefs_dynevent_list_free(devents);
2326 	devents = NULL;
2327 
2328 	for (i = 0; i < kretprobe_count; i++) {
2329 		CU_TEST(tracefs_dynevent_create(dkretprobe[i]) == 0);
2330 	}
2331 	devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE,
2332 				    kprobe_count + kretprobe_count);
2333 	CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance, tep));
2334 	CU_TEST(check_probes(kretests, kretprobe_count, devents, true, instance, tep));
2335 	tracefs_dynevent_list_free(devents);
2336 	devents = NULL;
2337 
2338 	for (i = 0; i < kretprobe_count; i++) {
2339 		CU_TEST(tracefs_dynevent_destroy(dkretprobe[i], false) == 0);
2340 	}
2341 	devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE,
2342 				    kprobe_count);
2343 	CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance, tep));
2344 	CU_TEST(check_probes(kretests, kretprobe_count, dkretprobe, false, instance, tep));
2345 	tracefs_dynevent_list_free(devents);
2346 	devents = NULL;
2347 
2348 	for (i = 0; i < kprobe_count; i++) {
2349 		CU_TEST(tracefs_dynevent_destroy(dkprobe[i], false) == 0);
2350 	}
2351 	get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, 0);
2352 	CU_TEST(check_probes(ktests, kprobe_count, dkprobe, false, instance, tep));
2353 	CU_TEST(check_probes(kretests, kretprobe_count, dkretprobe, false, instance, tep));
2354 	tracefs_dynevent_list_free(devents);
2355 	devents = NULL;
2356 
2357 	for (i = 0; i < kprobe_count; i++)
2358 		tracefs_dynevent_free(dkprobe[i]);
2359 	for (i = 0; i < kretprobe_count; i++)
2360 		tracefs_dynevent_free(dkretprobe[i]);
2361 
2362 	/* kprobes raw APIs */
2363 	destroy_dynevents(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE);
2364 
2365 	for (i = 0; i < kprobe_count; i++) {
2366 		ret = tracefs_kprobe_raw(ktests[i].system, ktests[i].event,
2367 					 ktests[i].address, ktests[i].format);
2368 		CU_TEST(ret == 0);
2369 	}
2370 
2371 	devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, kprobe_count);
2372 	CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance, tep));
2373 	tracefs_dynevent_list_free(devents);
2374 	devents = NULL;
2375 
2376 	for (i = 0; i < kretprobe_count; i++) {
2377 		ret = tracefs_kretprobe_raw(kretests[i].system, kretests[i].event,
2378 					    kretests[i].address, kretests[i].format);
2379 		CU_TEST(ret == 0);
2380 	}
2381 
2382 	devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE, kprobe_count);
2383 	CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance, tep));
2384 	tracefs_dynevent_list_free(devents);
2385 	devents = NULL;
2386 
2387 	devents = get_dynevents_check(TRACEFS_DYNEVENT_KRETPROBE, kretprobe_count);
2388 	CU_TEST(check_probes(kretests, kretprobe_count, devents, true, instance, tep));
2389 	tracefs_dynevent_list_free(devents);
2390 	devents = NULL;
2391 
2392 	devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE,
2393 				    kprobe_count + kretprobe_count);
2394 	CU_TEST(check_probes(ktests, kprobe_count, devents, true, instance, tep));
2395 	CU_TEST(check_probes(kretests, kretprobe_count, devents, true, instance, tep));
2396 	tracefs_dynevent_list_free(devents);
2397 	devents = NULL;
2398 
2399 	/* Try destroying all the events using tracefs_kprobe_destroy */
2400 	for (i = 0; i < kprobe_count; i++) {
2401 		ret = tracefs_kprobe_destroy(ktests[i].system, ktests[i].event,
2402 					     ktests[i].address, ktests[i].format, true);
2403 		CU_TEST(ret == 0);
2404 		devents = get_dynevents_check(TRACEFS_DYNEVENT_KPROBE,
2405 					      kprobe_count - (i + 1));
2406 		tracefs_dynevent_list_free(devents);
2407 	}
2408 	get_dynevents_check(TRACEFS_DYNEVENT_KPROBE, 0);
2409 
2410 	for (i = 0; i < kretprobe_count; i++) {
2411 		ret = tracefs_kprobe_destroy(kretests[i].system, kretests[i].event,
2412 					     kretests[i].address, kretests[i].format, true);
2413 		CU_TEST(ret == 0);
2414 		devents = get_dynevents_check(TRACEFS_DYNEVENT_KRETPROBE,
2415 					      kretprobe_count - (i + 1));
2416 		tracefs_dynevent_list_free(devents);
2417 	}
2418 	get_dynevents_check(TRACEFS_DYNEVENT_KRETPROBE, 0);
2419 
2420 	free(dkretprobe);
2421 	free(dkprobe);
2422 	tep_free(tep);
2423 }
2424 
test_kprobes(void)2425 static void test_kprobes(void)
2426 {
2427 	test_kprobes_instance(test_instance);
2428 }
2429 
test_eprobes_instance(struct tracefs_instance * instance)2430 static void test_eprobes_instance(struct tracefs_instance *instance)
2431 {
2432 	struct probe_test etests[] = {
2433 		{ TRACEFS_DYNEVENT_EPROBE, "e", NULL, "sopen_in", "syscalls.sys_enter_openat",
2434 					   "file=+0($filename):ustring" },
2435 		{ TRACEFS_DYNEVENT_EPROBE, "e", "etest", "sopen_out", "syscalls.sys_exit_openat",
2436 					   "res=$ret:u64" },
2437 	};
2438 	int count = sizeof(etests) / sizeof((etests)[0]);
2439 	struct tracefs_dynevent **deprobes;
2440 	struct tracefs_dynevent **devents;
2441 	struct tep_handle *tep;
2442 	char *tsys, *tevent;
2443 	char *tmp, *sav;
2444 	int i;
2445 
2446 	tep = tep_alloc();
2447 	CU_TEST(tep != NULL);
2448 
2449 	deprobes = calloc(count + 1, sizeof(*deprobes));
2450 
2451 	/* Invalid parameters */
2452 	CU_TEST(tracefs_eprobe_alloc("test", NULL, "test", "test", "test") == NULL);
2453 	CU_TEST(tracefs_eprobe_alloc("test", "test", NULL, "test", "test") == NULL);
2454 	CU_TEST(tracefs_eprobe_alloc("test", "test", "test", NULL, "test") == NULL);
2455 
2456 	destroy_dynevents(TRACEFS_DYNEVENT_EPROBE);
2457 
2458 	for (i = 0; i < count; i++) {
2459 		tmp = strdup(etests[i].address);
2460 		tsys = strtok_r(tmp, "./", &sav);
2461 		tevent = strtok_r(NULL, "", &sav);
2462 		deprobes[i] = tracefs_eprobe_alloc(etests[i].system, etests[i].event,
2463 						   tsys, tevent, etests[i].format);
2464 		free(tmp);
2465 		CU_TEST(deprobes[i] != NULL);
2466 	}
2467 	deprobes[i] = NULL;
2468 
2469 	get_dynevents_check(TRACEFS_DYNEVENT_EPROBE, 0);
2470 	CU_TEST(check_probes(etests, count, deprobes, false, instance, tep));
2471 
2472 	for (i = 0; i < count; i++) {
2473 		CU_TEST(tracefs_dynevent_create(deprobes[i]) == 0);
2474 	}
2475 
2476 	devents = get_dynevents_check(TRACEFS_DYNEVENT_EPROBE, count);
2477 	CU_TEST(check_probes(etests, count, devents, true, instance, tep));
2478 	tracefs_dynevent_list_free(devents);
2479 	devents = NULL;
2480 
2481 	for (i = 0; i < count; i++) {
2482 		CU_TEST(tracefs_dynevent_destroy(deprobes[i], false) == 0);
2483 	}
2484 	get_dynevents_check(TRACEFS_DYNEVENT_EPROBE, 0);
2485 	CU_TEST(check_probes(etests, count, deprobes, false, instance, tep));
2486 
2487 	for (i = 0; i < count; i++)
2488 		tracefs_dynevent_free(deprobes[i]);
2489 
2490 	free(deprobes);
2491 	tep_free(tep);
2492 }
2493 
test_eprobes(void)2494 static void test_eprobes(void)
2495 {
2496 	test_eprobes_instance(test_instance);
2497 }
2498 
2499 #define FOFFSET 1000ll
test_uprobes_instance(struct tracefs_instance * instance)2500 static void test_uprobes_instance(struct tracefs_instance *instance)
2501 {
2502 	struct probe_test utests[] = {
2503 		{ TRACEFS_DYNEVENT_UPROBE, "p", "utest", "utest_u", NULL, "arg1=$stack2" },
2504 		{ TRACEFS_DYNEVENT_URETPROBE, "r", "utest", "utest_r", NULL, "arg1=$retval" },
2505 	};
2506 	int count = sizeof(utests) / sizeof((utests)[0]);
2507 	struct tracefs_dynevent **duprobes;
2508 	struct tracefs_dynevent **duvents;
2509 	char self[PATH_MAX] = { 0 };
2510 	struct tep_handle *tep;
2511 	char *target = NULL;
2512 	int i;
2513 
2514 	tep = tep_alloc();
2515 	CU_TEST(tep != NULL);
2516 
2517 	duprobes = calloc(count + 1, sizeof(*duvents));
2518 	CU_TEST(duprobes != NULL);
2519 	CU_TEST(readlink("/proc/self/exe", self, sizeof(self)) > 0);
2520 	CU_TEST(asprintf(&target, "%s:0x%0*llx", self, (int)(sizeof(void *) * 2), FOFFSET) > 0);
2521 
2522 	for (i = 0; i < count; i++)
2523 		utests[i].address = target;
2524 
2525 	/* Invalid parameters */
2526 	CU_TEST(tracefs_uprobe_alloc(NULL, NULL, self, 0, NULL) == NULL);
2527 	CU_TEST(tracefs_uprobe_alloc(NULL, "test", NULL, 0, NULL) == NULL);
2528 	CU_TEST(tracefs_uretprobe_alloc(NULL, NULL, self, 0, NULL) == NULL);
2529 	CU_TEST(tracefs_uretprobe_alloc(NULL, "test", NULL, 0, NULL) == NULL);
2530 
2531 	for (i = 0; i < count; i++) {
2532 		if (utests[i].type == TRACEFS_DYNEVENT_UPROBE)
2533 			duprobes[i] = tracefs_uprobe_alloc(utests[i].system, utests[i].event,
2534 							   self, FOFFSET, utests[i].format);
2535 		else
2536 			duprobes[i] = tracefs_uretprobe_alloc(utests[i].system, utests[i].event,
2537 							      self, FOFFSET, utests[i].format);
2538 		CU_TEST(duprobes[i] != NULL);
2539 	}
2540 	duprobes[i] = NULL;
2541 
2542 	get_dynevents_check(TRACEFS_DYNEVENT_UPROBE | TRACEFS_DYNEVENT_URETPROBE, 0);
2543 	CU_TEST(check_probes(utests, count, duprobes, false, instance, tep));
2544 
2545 	for (i = 0; i < count; i++) {
2546 		CU_TEST(tracefs_dynevent_create(duprobes[i]) == 0);
2547 	}
2548 
2549 	duvents = get_dynevents_check(TRACEFS_DYNEVENT_UPROBE | TRACEFS_DYNEVENT_URETPROBE, count);
2550 	CU_TEST(check_probes(utests, count, duvents, true, instance, tep));
2551 	tracefs_dynevent_list_free(duvents);
2552 
2553 	for (i = 0; i < count; i++) {
2554 		CU_TEST(tracefs_dynevent_destroy(duprobes[i], false) == 0);
2555 	}
2556 	get_dynevents_check(TRACEFS_DYNEVENT_UPROBE | TRACEFS_DYNEVENT_URETPROBE, 0);
2557 	CU_TEST(check_probes(utests, count, duprobes, false, instance, tep));
2558 
2559 	for (i = 0; i < count; i++)
2560 		tracefs_dynevent_free(duprobes[i]);
2561 
2562 	free(duprobes);
2563 	free(target);
2564 	tep_free(tep);
2565 }
2566 
test_uprobes(void)2567 static void test_uprobes(void)
2568 {
2569 	test_uprobes_instance(test_instance);
2570 }
2571 
test_instance_file(void)2572 static void test_instance_file(void)
2573 {
2574 	struct tracefs_instance *instance = NULL;
2575 	struct tracefs_instance *second = NULL;
2576 	const char *name = get_rand_str();
2577 	const char *inst_name = NULL;
2578 	const char *tdir;
2579 	char *inst_file;
2580 	char *inst_dir;
2581 	struct stat st;
2582 	char *file1;
2583 	char *file2;
2584 	char *tracer;
2585 	char *fname;
2586 	int size;
2587 	int ret;
2588 
2589 	tdir  = tracefs_tracing_dir();
2590 	CU_TEST(tdir != NULL);
2591 	CU_TEST(asprintf(&inst_dir, "%s/instances/%s", tdir, name) > 0);
2592 	CU_TEST(stat(inst_dir, &st) != 0);
2593 
2594 	CU_TEST(tracefs_instance_exists(name) == false);
2595 	instance = tracefs_instance_create(name);
2596 	CU_TEST(instance != NULL);
2597 	CU_TEST(tracefs_instance_is_new(instance));
2598 	second = tracefs_instance_create(name);
2599 	CU_TEST(second != NULL);
2600 	CU_TEST(!tracefs_instance_is_new(second));
2601 	tracefs_instance_free(second);
2602 	CU_TEST(tracefs_instance_exists(name) == true);
2603 	CU_TEST(stat(inst_dir, &st) == 0);
2604 	CU_TEST(S_ISDIR(st.st_mode));
2605 	inst_name = tracefs_instance_get_name(instance);
2606 	CU_TEST(inst_name != NULL);
2607 	CU_TEST(strcmp(inst_name, name) == 0);
2608 
2609 	fname = tracefs_instance_get_dir(NULL);
2610 	CU_TEST(fname != NULL);
2611 	CU_TEST(strcmp(fname, tdir) == 0);
2612 	free(fname);
2613 
2614 	fname = tracefs_instance_get_dir(instance);
2615 	CU_TEST(fname != NULL);
2616 	CU_TEST(strcmp(fname, inst_dir) == 0);
2617 	free(fname);
2618 
2619 	CU_TEST(asprintf(&fname, "%s/"ALL_TRACERS, tdir) > 0);
2620 	CU_TEST(fname != NULL);
2621 	inst_file = tracefs_instance_get_file(NULL, ALL_TRACERS);
2622 	CU_TEST(inst_file != NULL);
2623 	CU_TEST(strcmp(fname, inst_file) == 0);
2624 	tracefs_put_tracing_file(inst_file);
2625 	free(fname);
2626 
2627 	CU_TEST(asprintf(&fname, "%s/instances/%s/"ALL_TRACERS, tdir, name) > 0);
2628 	CU_TEST(fname != NULL);
2629 	CU_TEST(stat(fname, &st) == 0);
2630 	inst_file = tracefs_instance_get_file(instance, ALL_TRACERS);
2631 	CU_TEST(inst_file != NULL);
2632 	CU_TEST(strcmp(fname, inst_file) == 0);
2633 
2634 	test_instance_file_read(NULL, ALL_TRACERS);
2635 	test_instance_file_read(instance, ALL_TRACERS);
2636 
2637 	file1 = tracefs_instance_file_read(instance, ALL_TRACERS, NULL);
2638 	CU_TEST(file1 != NULL);
2639 	tracer = strtok(file1, " ");
2640 	CU_TEST(tracer != NULL);
2641 	ret = tracefs_instance_file_write(instance, CUR_TRACER, tracer);
2642 	CU_TEST(ret == strlen(tracer));
2643 	file2 = tracefs_instance_file_read(instance, CUR_TRACER, &size);
2644 	CU_TEST(file2 != NULL);
2645 	CU_TEST(size >= strlen(tracer));
2646 	CU_TEST(strncmp(file2, tracer, strlen(tracer)) == 0);
2647 	free(file1);
2648 	free(file2);
2649 
2650 	tracefs_put_tracing_file(inst_file);
2651 	free(fname);
2652 
2653 	CU_TEST(tracefs_file_exists(NULL, (char *)name) == false);
2654 	CU_TEST(tracefs_dir_exists(NULL, (char *)name) == false);
2655 	CU_TEST(tracefs_file_exists(instance, (char *)name) == false);
2656 	CU_TEST(tracefs_dir_exists(instance, (char *)name) == false);
2657 
2658 	CU_TEST(tracefs_file_exists(NULL, CUR_TRACER) == true);
2659 	CU_TEST(tracefs_dir_exists(NULL, CUR_TRACER) == false);
2660 	CU_TEST(tracefs_file_exists(instance, CUR_TRACER) == true);
2661 	CU_TEST(tracefs_dir_exists(instance, CUR_TRACER) == false);
2662 
2663 	CU_TEST(tracefs_file_exists(NULL, PER_CPU) == false);
2664 	CU_TEST(tracefs_dir_exists(NULL, PER_CPU) == true);
2665 	CU_TEST(tracefs_file_exists(instance, PER_CPU) == false);
2666 	CU_TEST(tracefs_dir_exists(instance, PER_CPU) == true);
2667 
2668 	CU_TEST(tracefs_instance_destroy(NULL) != 0);
2669 	CU_TEST(tracefs_instance_destroy(instance) == 0);
2670 	CU_TEST(tracefs_instance_destroy(instance) != 0);
2671 	tracefs_instance_free(instance);
2672 	CU_TEST(stat(inst_dir, &st) != 0);
2673 	free(inst_dir);
2674 }
2675 
test_check_file_content(struct tracefs_instance * instance,char * file,char * content,bool full_match,bool ignore_comments)2676 static bool test_check_file_content(struct tracefs_instance *instance, char *file,
2677 				    char *content, bool full_match, bool ignore_comments)
2678 {
2679 	char *save = NULL;
2680 	char *buf, *line;
2681 	bool ret = false;
2682 	int len;
2683 
2684 	if (!tracefs_file_exists(instance, file))
2685 		return false;
2686 
2687 	buf = tracefs_instance_file_read(instance, file, NULL);
2688 	if (strlen(content) == 0) {
2689 		/* check for empty file */
2690 		if (!buf)
2691 			return true;
2692 		if (!ignore_comments) {
2693 			if (strlen(buf) > 0)
2694 				goto out;
2695 		} else {
2696 			line = strtok_r(buf, "\n", &save);
2697 			while (line) {
2698 				if (line[0] != '#')
2699 					goto out;
2700 				line = strtok_r(NULL, "\n", &save);
2701 			}
2702 		}
2703 	} else {
2704 		if (!buf || strlen(buf) < 1)
2705 			return false;
2706 		if (full_match) {
2707 			/* strip the newline */
2708 			len = strlen(buf) - 1;
2709 			while (buf[len] == '\n' || buf[len] == '\r') {
2710 				buf[len] = '\0';
2711 				len = strlen(buf) - 1;
2712 				if (len < 0)
2713 					goto out;
2714 			}
2715 			if (strcmp(buf, content))
2716 				goto out;
2717 		} else {
2718 			if (!strstr(buf, content))
2719 				goto out;
2720 		}
2721 	}
2722 
2723 	ret = true;
2724 out:
2725 	free(buf);
2726 	return ret;
2727 }
2728 
test_check_event_file_content(struct tracefs_instance * instance,char * system,char * event,char * file,char * content,bool full_match,bool ignore_comments)2729 static bool test_check_event_file_content(struct tracefs_instance *instance,
2730 					  char *system, char *event, char *file,
2731 					  char *content, bool full_match, bool ignore_comments)
2732 {
2733 	char *efile;
2734 	int ret;
2735 
2736 	ret = asprintf(&efile, "events/%s/%s/%s", system, event, file);
2737 	if (ret <= 0)
2738 		return false;
2739 	ret = test_check_file_content(instance, efile, content, full_match, ignore_comments);
2740 	free(efile);
2741 	return ret;
2742 }
2743 
check_cpu_mask(struct tracefs_instance * instance)2744 static bool check_cpu_mask(struct tracefs_instance *instance)
2745 {
2746 	int cpus = sysconf(_SC_NPROCESSORS_CONF);
2747 	int fullwords = (cpus - 1) / 32;
2748 	int bits = (cpus - 1) % 32 + 1;
2749 	int len = (fullwords + 1) * 9;
2750 	char buf[len + 1];
2751 
2752 	buf[0] = '\0';
2753 	sprintf(buf, "%x", (unsigned int)((1ULL << bits) - 1));
2754 	while (fullwords-- > 0)
2755 		strcat(buf, ",ffffffff");
2756 
2757 	return test_check_file_content(instance, "tracing_cpumask", buf, true, false);
2758 }
2759 
test_instance_check_default_state(struct tracefs_instance * instance)2760 static bool test_instance_check_default_state(struct tracefs_instance *instance)
2761 {
2762 	char **systems;
2763 	char **events;
2764 	int i, j;
2765 	int ok;
2766 
2767 	if (tracefs_trace_is_on(instance) != 1)
2768 		return false;
2769 	if (!test_check_file_content(instance, "current_tracer", "nop", true, false))
2770 		return false;
2771 	if (!test_check_file_content(instance, "events/enable", "0", true, false))
2772 		return false;
2773 	if (!test_check_file_content(instance, "set_ftrace_pid", "no pid", true, false))
2774 		return false;
2775 	if (!test_check_file_content(instance, "trace", "", true, true))
2776 		return false;
2777 	if (!test_check_file_content(instance, "error_log", "", true, false))
2778 		return false;
2779 	if (!test_check_file_content(instance, "trace_clock", "[local]", false, false))
2780 		return false;
2781 	if (!test_check_file_content(instance, "set_event_pid", "", true, false))
2782 		return false;
2783 	if (!test_check_file_content(instance, "tracing_max_latency", "0", true, false))
2784 		return false;
2785 	if (!test_check_file_content(instance, "set_ftrace_filter", "", true, true))
2786 		return false;
2787 	if (!test_check_file_content(instance, "set_ftrace_notrace", "", true, true))
2788 		return false;
2789 	if (!check_cpu_mask(instance))
2790 		return false;
2791 
2792 	ok = 1;
2793 	systems = tracefs_event_systems(NULL);
2794 	if (systems) {
2795 		for (i = 0; systems[i]; i++) {
2796 			events = tracefs_system_events(NULL, systems[i]);
2797 			if (!events)
2798 				continue;
2799 			for (j = 0; events[j]; j++) {
2800 				if (!test_check_event_file_content(instance, systems[i], events[j],
2801 								    "enable", "0", true, false))
2802 					break;
2803 				if (!test_check_event_file_content(instance, systems[i], events[j],
2804 								    "filter", "none", true, false))
2805 					break;
2806 				if (!test_check_event_file_content(instance, systems[i], events[j],
2807 								    "trigger", "", true, true))
2808 					break;
2809 			}
2810 			if (events[j])
2811 				ok = 0;
2812 			tracefs_list_free(events);
2813 			if (!ok)
2814 				return false;
2815 		}
2816 		tracefs_list_free(systems);
2817 	}
2818 
2819 	return true;
2820 }
2821 
test_instance_reset(void)2822 static void test_instance_reset(void)
2823 {
2824 	struct tracefs_instance *instance = NULL;
2825 	const char *name = get_rand_str();
2826 	char **tracers;
2827 
2828 	CU_TEST(tracefs_instance_exists(name) == false);
2829 	instance = tracefs_instance_create(name);
2830 	CU_TEST(instance != NULL);
2831 
2832 	CU_TEST(test_instance_check_default_state(instance) == true);
2833 
2834 	tracers = tracefs_instance_tracers(instance);
2835 	CU_TEST(tracers != NULL);
2836 	if (tracers) {
2837 		CU_TEST(tracefs_tracer_set(instance, TRACEFS_TRACER_CUSTOM, tracers[0]) == 0);
2838 		tracefs_list_free(tracers);
2839 	}
2840 	CU_TEST(tracefs_event_enable(instance, "sched", "sched_switch") == 0);
2841 	CU_TEST(tracefs_instance_file_write(instance, "set_ftrace_pid", "5") > 0);
2842 	CU_TEST(tracefs_instance_file_write(instance, "trace_clock", "global") > 0);
2843 	CU_TEST(tracefs_instance_file_write(instance, "set_event_pid", "5") > 0);
2844 	CU_TEST(tracefs_instance_file_write(instance, "set_ftrace_filter",
2845 						      "schedule:stacktrace") > 0);
2846 	CU_TEST(tracefs_instance_file_write(instance, "set_ftrace_notrace",
2847 						      "schedule:stacktrace") > 0);
2848 	CU_TEST(tracefs_instance_file_write(instance, "tracing_cpumask", "0f") > 0);
2849 	CU_TEST(tracefs_event_file_write(instance, "syscalls", "sys_exit_read", "trigger",
2850 						      "enable_event:kmem:kmalloc:1") > 0);
2851 	CU_TEST(tracefs_event_file_write(instance, "sched", "sched_switch", "filter",
2852 						      "common_pid == 5") > 0);
2853 
2854 	CU_TEST(test_instance_check_default_state(instance) == false);
2855 
2856 	tracefs_instance_reset(instance);
2857 	CU_TEST(test_instance_check_default_state(instance) == true);
2858 
2859 	CU_TEST(tracefs_instance_destroy(instance) == 0);
2860 	tracefs_instance_free(instance);
2861 }
2862 
check_fd_name(int fd,const char * dir,const char * name)2863 static bool check_fd_name(int fd, const char *dir, const char *name)
2864 {
2865 	char link[PATH_MAX + 1];
2866 	char path[PATH_MAX + 1];
2867 	struct stat st;
2868 	char *file;
2869 	int ret;
2870 
2871 	snprintf(link, PATH_MAX, "/proc/self/fd/%d", fd);
2872 	ret = lstat(link, &st);
2873 	CU_TEST(ret == 0);
2874 	if (ret < 0)
2875 		return false;
2876 	CU_TEST(S_ISLNK(st.st_mode));
2877 	if (!S_ISLNK(st.st_mode))
2878 		return false;
2879 	ret = readlink(link, path, PATH_MAX);
2880 	CU_TEST(ret > 0);
2881 	if (ret > PATH_MAX || ret < 0)
2882 		return false;
2883 	path[ret] = 0;
2884 	ret = strncmp(dir, path, strlen(dir));
2885 	CU_TEST(ret == 0);
2886 	if (ret)
2887 		return false;
2888 	file = basename(path);
2889 	CU_TEST(file != NULL);
2890 	if (!file)
2891 		return false;
2892 	ret = strcmp(file, name);
2893 	CU_TEST(ret == 0);
2894 	if (ret)
2895 		return false;
2896 	return true;
2897 }
2898 
2899 #define FLAGS_STR	"flags:"
check_fd_mode(int fd,int mode)2900 static bool check_fd_mode(int fd, int mode)
2901 {
2902 	char path[PATH_MAX + 1];
2903 	long fmode = -1;
2904 	char *line = NULL;
2905 	struct stat st;
2906 	size_t len = 0;
2907 	ssize_t size;
2908 	FILE *file;
2909 	int ret;
2910 
2911 	snprintf(path, PATH_MAX, "/proc/self/fdinfo/%d", fd);
2912 	ret = stat(path, &st);
2913 	CU_TEST(ret == 0);
2914 	if (ret < 0)
2915 		return false;
2916 	file = fopen(path, "r");
2917 	if (!file)
2918 		return false;
2919 	while ((size = getline(&line, &len, file)) > 0) {
2920 		if (strncmp(line, FLAGS_STR, strlen(FLAGS_STR)))
2921 			continue;
2922 		fmode = strtol(line + strlen(FLAGS_STR), NULL, 8);
2923 		break;
2924 	}
2925 	free(line);
2926 	fclose(file);
2927 	if (fmode < 0 ||
2928 	    (O_ACCMODE & fmode) != (O_ACCMODE & mode))
2929 		return false;
2930 	return true;
2931 }
2932 
test_instance_file_fd(struct tracefs_instance * instance)2933 static void test_instance_file_fd(struct tracefs_instance *instance)
2934 {
2935 	const char *name = get_rand_str();
2936 	const char *tdir = tracefs_instance_get_trace_dir(instance);
2937 	long long res = -1;
2938 	long long res2;
2939 	char rd[2];
2940 	int fd;
2941 
2942 	CU_TEST(tdir != NULL);
2943 	fd = tracefs_instance_file_open(instance, name, -1);
2944 	CU_TEST(fd == -1);
2945 	fd = tracefs_instance_file_open(instance, TRACE_ON, O_RDONLY);
2946 	CU_TEST(fd >= 0);
2947 
2948 	CU_TEST(check_fd_name(fd, tdir, TRACE_ON));
2949 	CU_TEST(check_fd_mode(fd, O_RDONLY));
2950 
2951 	CU_TEST(tracefs_instance_file_read_number(instance, ALL_TRACERS, &res) != 0);
2952 	CU_TEST(tracefs_instance_file_read_number(instance, name, &res) != 0);
2953 	CU_TEST(tracefs_instance_file_read_number(instance, TRACE_ON, &res) == 0);
2954 	CU_TEST((res == 0 || res == 1));
2955 	CU_TEST(read(fd, &rd, 1) == 1);
2956 	rd[1] = 0;
2957 	CU_TEST(res == atoi(rd));
2958 	close(fd);
2959 
2960 	/* Inverse tracing_on and test changing it with write_number */
2961 	res ^= 1;
2962 
2963 	CU_TEST(tracefs_instance_file_write_number(instance, TRACE_ON, (size_t)res) == 0);
2964 
2965 	CU_TEST(tracefs_instance_file_read_number(instance, TRACE_ON, &res2) == 0);
2966 	CU_TEST(res2 == res);
2967 	fd = tracefs_instance_file_open(instance, TRACE_ON, O_RDONLY);
2968 	CU_TEST(fd >= 0);
2969 	CU_TEST(read(fd, &rd, 1) == 1);
2970 	rd[1] = 0;
2971 	CU_TEST(res2 == atoi(rd));
2972 	close(fd);
2973 
2974 	/* Put back the result of tracing_on */
2975 	res ^= 1;
2976 
2977 	CU_TEST(tracefs_instance_file_write_number(instance, TRACE_ON, (size_t)res) == 0);
2978 
2979 	CU_TEST(tracefs_instance_file_read_number(instance, TRACE_ON, &res2) == 0);
2980 	CU_TEST(res2 == res);
2981 	fd = tracefs_instance_file_open(instance, TRACE_ON, O_RDONLY);
2982 	CU_TEST(fd >= 0);
2983 	CU_TEST(read(fd, &rd, 1) == 1);
2984 	rd[1] = 0;
2985 	CU_TEST(res2 == atoi(rd));
2986 	close(fd);
2987 }
2988 
test_file_fd(void)2989 static void test_file_fd(void)
2990 {
2991 	test_instance_file_fd(test_instance);
2992 }
2993 
test_instance_tracing_onoff(struct tracefs_instance * instance)2994 static void test_instance_tracing_onoff(struct tracefs_instance *instance)
2995 {
2996 	const char *tdir = tracefs_instance_get_trace_dir(instance);
2997 	long long res = -1;
2998 	int fd;
2999 
3000 	CU_TEST(tdir != NULL);
3001 	fd = tracefs_trace_on_get_fd(instance);
3002 	CU_TEST(fd >= 0);
3003 	CU_TEST(check_fd_name(fd, tdir, TRACE_ON));
3004 	CU_TEST(check_fd_mode(fd, O_RDWR));
3005 	CU_TEST(tracefs_instance_file_read_number(instance, TRACE_ON, &res) == 0);
3006 	if (res == 1) {
3007 		CU_TEST(tracefs_trace_is_on(instance) == 1);
3008 		CU_TEST(tracefs_trace_off(instance) == 0);
3009 		CU_TEST(tracefs_trace_is_on(instance) == 0);
3010 		CU_TEST(tracefs_trace_on(instance) == 0);
3011 		CU_TEST(tracefs_trace_is_on(instance) == 1);
3012 
3013 		CU_TEST(tracefs_trace_off_fd(fd) == 0);
3014 		CU_TEST(tracefs_trace_is_on(instance) == 0);
3015 		CU_TEST(tracefs_trace_on_fd(fd) == 0);
3016 		CU_TEST(tracefs_trace_is_on(instance) == 1);
3017 	} else {
3018 		CU_TEST(tracefs_trace_is_on(instance) == 0);
3019 		CU_TEST(tracefs_trace_on(instance) == 0);
3020 		CU_TEST(tracefs_trace_is_on(instance) == 1);
3021 		CU_TEST(tracefs_trace_off(instance) == 0);
3022 		CU_TEST(tracefs_trace_is_on(instance) == 0);
3023 
3024 		CU_TEST(tracefs_trace_on_fd(fd) == 0);
3025 		CU_TEST(tracefs_trace_is_on(instance) == 1);
3026 		CU_TEST(tracefs_trace_off_fd(fd) == 0);
3027 		CU_TEST(tracefs_trace_is_on(instance) == 0);
3028 	}
3029 
3030 	if (fd >= 0)
3031 		close(fd);
3032 }
3033 
test_tracing_onoff(void)3034 static void test_tracing_onoff(void)
3035 {
3036 	test_instance_tracing_onoff(test_instance);
3037 }
3038 
check_option(struct tracefs_instance * instance,enum tracefs_option_id id,bool exist,int enabled)3039 static bool check_option(struct tracefs_instance *instance,
3040 			 enum tracefs_option_id id, bool exist, int enabled)
3041 {
3042 	const char *name = tracefs_option_name(id);
3043 	char file[PATH_MAX];
3044 	char *path = NULL;
3045 	bool ret = false;
3046 	bool supported;
3047 	struct stat st;
3048 	char buf[10];
3049 	int fd = 0;
3050 	int r;
3051 	int rstat;
3052 
3053 	CU_TEST(name != NULL);
3054 	supported = tracefs_option_is_supported(instance, id);
3055 	CU_TEST(supported == exist);
3056 	if (supported != exist)
3057 		goto out;
3058 	snprintf(file, PATH_MAX, "options/%s", name);
3059 	path = tracefs_instance_get_file(instance, file);
3060 	CU_TEST(path != NULL);
3061 	rstat = stat(path, &st);
3062 	if (exist) {
3063 		CU_TEST(rstat == 0);
3064 		if (rstat != 0)
3065 			goto out;
3066 	} else {
3067 		CU_TEST(stat(path, &st) == -1);
3068 		if (rstat != -1)
3069 			goto out;
3070 	}
3071 
3072 	fd = open(path, O_RDONLY);
3073 	if (exist) {
3074 		CU_TEST(fd >= 0);
3075 		if (fd < 0)
3076 			goto out;
3077 	} else {
3078 		CU_TEST(fd < 0);
3079 		if (fd >= 0)
3080 			goto out;
3081 	}
3082 
3083 	if (exist && enabled >= 0) {
3084 		int val = enabled ? '1' : '0';
3085 
3086 		r = read(fd, buf, 10);
3087 		CU_TEST(r >= 1);
3088 		CU_TEST(buf[0] == val);
3089 		if (buf[0] != val)
3090 			goto out;
3091 	}
3092 
3093 	ret = true;
3094 out:
3095 	tracefs_put_tracing_file(path);
3096 	if (fd >= 0)
3097 		close(fd);
3098 	return ret;
3099 }
3100 
test_instance_tracing_options(struct tracefs_instance * instance)3101 static void test_instance_tracing_options(struct tracefs_instance *instance)
3102 {
3103 	const struct tracefs_options_mask *enabled;
3104 	const struct tracefs_options_mask *all_copy;
3105 	const struct tracefs_options_mask *all;
3106 	enum tracefs_option_id i = 1;
3107 	char file[PATH_MAX];
3108 	const char *name;
3109 
3110 	all = tracefs_options_get_supported(instance);
3111 	all_copy = tracefs_options_get_supported(instance);
3112 	enabled = tracefs_options_get_enabled(instance);
3113 	CU_TEST(all != NULL);
3114 
3115 	/* Invalid parameters test */
3116 	CU_TEST(!tracefs_option_is_supported(instance, TRACEFS_OPTION_INVALID));
3117 	CU_TEST(!tracefs_option_is_enabled(instance, TRACEFS_OPTION_INVALID));
3118 	CU_TEST(tracefs_option_enable(instance, TRACEFS_OPTION_INVALID) == -1);
3119 	CU_TEST(tracefs_option_disable(instance, TRACEFS_OPTION_INVALID) == -1);
3120 	name = tracefs_option_name(TRACEFS_OPTION_INVALID);
3121 	CU_TEST(!strcmp(name, "unknown"));
3122 	/* Test all valid options */
3123 	for (i = 1; i < TRACEFS_OPTION_MAX; i++) {
3124 		name = tracefs_option_name(i);
3125 		CU_TEST(name != NULL);
3126 		CU_TEST(strcmp(name, "unknown"));
3127 		snprintf(file, PATH_MAX, "options/%s", name);
3128 
3129 		if (tracefs_option_mask_is_set(all, i)) {
3130 			CU_TEST(check_option(instance, i, true, -1));
3131 			CU_TEST(tracefs_option_is_supported(instance, i));
3132 		} else {
3133 			CU_TEST(check_option(instance, i, false, -1));
3134 			CU_TEST(!tracefs_option_is_supported(instance, i));
3135 		}
3136 
3137 		if (tracefs_option_mask_is_set(enabled, i)) {
3138 			CU_TEST(check_option(instance, i, true, 1));
3139 			CU_TEST(tracefs_option_is_supported(instance, i));
3140 			CU_TEST(tracefs_option_is_enabled(instance, i));
3141 			CU_TEST(tracefs_option_disable(instance, i) == 0);
3142 			CU_TEST(check_option(instance, i, true, 0));
3143 			CU_TEST(tracefs_option_enable(instance, i) == 0);
3144 			CU_TEST(check_option(instance, i, true, 1));
3145 		} else if (tracefs_option_mask_is_set(all_copy, i)) {
3146 			CU_TEST(check_option(instance, i, true, 0));
3147 			CU_TEST(tracefs_option_is_supported(instance, i));
3148 			CU_TEST(!tracefs_option_is_enabled(instance, i));
3149 			CU_TEST(tracefs_option_enable(instance, i) == 0);
3150 			CU_TEST(check_option(instance, i, true, 1));
3151 			CU_TEST(tracefs_option_disable(instance, i) == 0);
3152 			CU_TEST(check_option(instance, i, true, 0));
3153 		}
3154 	}
3155 }
3156 
test_tracing_options(void)3157 static void test_tracing_options(void)
3158 {
3159 	test_instance_tracing_options(test_instance);
3160 }
3161 
exclude_string(char ** strings,char * name)3162 static void exclude_string(char **strings, char *name)
3163 {
3164 	int i;
3165 
3166 	for (i = 0; strings[i]; i++) {
3167 		if (strcmp(strings[i], name) == 0) {
3168 			free(strings[i]);
3169 			strings[i] = strdup("/");
3170 			return;
3171 		}
3172 	}
3173 }
3174 
test_check_files(const char * fdir,char ** files)3175 static void test_check_files(const char *fdir, char **files)
3176 {
3177 	struct dirent *dent;
3178 	DIR *dir;
3179 	int i;
3180 
3181 	dir = opendir(fdir);
3182 	CU_TEST(dir != NULL);
3183 
3184 	while ((dent = readdir(dir)))
3185 		exclude_string(files, dent->d_name);
3186 
3187 	closedir(dir);
3188 
3189 	for (i = 0; files[i]; i++)
3190 		CU_TEST(files[i][0] == '/');
3191 }
3192 
system_event(const char * tdir)3193 static void system_event(const char *tdir)
3194 {
3195 
3196 	char **systems;
3197 	char **events;
3198 	char *sdir = NULL;
3199 
3200 	systems = tracefs_event_systems(tdir);
3201 	CU_TEST(systems != NULL);
3202 
3203 	events = tracefs_system_events(tdir, systems[0]);
3204 	CU_TEST(events != NULL);
3205 
3206 	asprintf(&sdir, "%s/events/%s", tdir, systems[0]);
3207 	CU_TEST(sdir != NULL);
3208 	test_check_files(sdir, events);
3209 	free(sdir);
3210 	sdir = NULL;
3211 
3212 	asprintf(&sdir, "%s/events", tdir);
3213 	CU_TEST(sdir != NULL);
3214 	test_check_files(sdir, systems);
3215 
3216 	tracefs_list_free(systems);
3217 	tracefs_list_free(events);
3218 
3219 	free(sdir);
3220 }
3221 
test_system_event(void)3222 static void test_system_event(void)
3223 {
3224 	const char *tdir;
3225 
3226 	tdir  = tracefs_tracing_dir();
3227 	CU_TEST(tdir != NULL);
3228 	system_event(tdir);
3229 }
3230 
test_instance_tracers(struct tracefs_instance * instance)3231 static void test_instance_tracers(struct tracefs_instance *instance)
3232 {
3233 	const char *tdir;
3234 	char **tracers;
3235 	char *tfile;
3236 	char *tracer;
3237 	int i;
3238 
3239 	tdir  = tracefs_instance_get_trace_dir(instance);
3240 	CU_TEST(tdir != NULL);
3241 
3242 	tracers = tracefs_tracers(tdir);
3243 	CU_TEST(tracers != NULL);
3244 
3245 	for (i = 0; tracers[i]; i++)
3246 		CU_TEST(tracefs_tracer_available(tdir, tracers[i]));
3247 
3248 	tfile = tracefs_instance_file_read(NULL, ALL_TRACERS, NULL);
3249 
3250 	tracer = strtok(tfile, " ");
3251 	while (tracer) {
3252 		exclude_string(tracers, tracer);
3253 		tracer = strtok(NULL, " ");
3254 	}
3255 
3256 	for (i = 0; tracers[i]; i++)
3257 		CU_TEST(tracers[i][0] == '/');
3258 
3259 	tracefs_list_free(tracers);
3260 	free(tfile);
3261 }
3262 
test_tracers(void)3263 static void test_tracers(void)
3264 {
3265 	test_instance_tracers(test_instance);
3266 }
3267 
test_check_events(struct tep_handle * tep,char * system,bool exist)3268 static void test_check_events(struct tep_handle *tep, char *system, bool exist)
3269 {
3270 	struct dirent *dent;
3271 	char file[PATH_MAX];
3272 	char buf[1024];
3273 	char *edir = NULL;
3274 	const char *tdir;
3275 	DIR *dir;
3276 	int fd;
3277 
3278 	tdir  = tracefs_tracing_dir();
3279 	CU_TEST(tdir != NULL);
3280 
3281 	asprintf(&edir, "%s/events/%s", tdir, system);
3282 	dir = opendir(edir);
3283 	CU_TEST(dir != NULL);
3284 
3285 	while ((dent = readdir(dir))) {
3286 		if (dent->d_name[0] == '.')
3287 			continue;
3288 		sprintf(file, "%s/%s/id", edir, dent->d_name);
3289 		fd = open(file, O_RDONLY);
3290 		if (fd < 0)
3291 			continue;
3292 		CU_TEST(read(fd, buf, 1024) > 0);
3293 		if (exist) {
3294 			CU_TEST(tep_find_event(tep, atoi(buf)) != NULL);
3295 		} else {
3296 			CU_TEST(tep_find_event(tep, atoi(buf)) == NULL);
3297 		}
3298 
3299 		close(fd);
3300 	}
3301 
3302 	closedir(dir);
3303 	free(edir);
3304 
3305 }
3306 
local_events(const char * tdir)3307 static void local_events(const char *tdir)
3308 {
3309 	struct tep_handle *tep;
3310 	char **systems;
3311 	char *lsystems[3];
3312 	int i;
3313 
3314 	tep = tracefs_local_events(tdir);
3315 	CU_TEST(tep != NULL);
3316 
3317 	systems = tracefs_event_systems(tdir);
3318 	CU_TEST(systems != NULL);
3319 
3320 	for (i = 0; systems[i]; i++)
3321 		test_check_events(tep, systems[i], true);
3322 	tep_free(tep);
3323 
3324 	memset(lsystems, 0, sizeof(lsystems));
3325 	for (i = 0; systems[i]; i++) {
3326 		if (!lsystems[0])
3327 			lsystems[0] = systems[i];
3328 		else if (!lsystems[2])
3329 			lsystems[2] = systems[i];
3330 		else
3331 			break;
3332 	}
3333 
3334 	if (lsystems[0] && lsystems[2]) {
3335 		tep = tracefs_local_events_system(tdir,
3336 						  (const char * const *)lsystems);
3337 		CU_TEST(tep != NULL);
3338 		test_check_events(tep, lsystems[0], true);
3339 		test_check_events(tep, lsystems[2], false);
3340 	}
3341 	tep_free(tep);
3342 
3343 	tep = tep_alloc();
3344 	CU_TEST(tep != NULL);
3345 	CU_TEST(tracefs_fill_local_events(tdir, tep, NULL) == 0);
3346 	for (i = 0; systems[i]; i++)
3347 		test_check_events(tep, systems[i], true);
3348 
3349 	tep_free(tep);
3350 
3351 	tracefs_list_free(systems);
3352 }
3353 
test_local_events(void)3354 static void test_local_events(void)
3355 {
3356 	const char *tdir;
3357 
3358 	tdir  = tracefs_tracing_dir();
3359 	CU_TEST(tdir != NULL);
3360 	local_events(tdir);
3361 }
3362 
3363 struct test_walk_instance {
3364 	struct tracefs_instance *instance;
3365 	bool found;
3366 };
3367 #define WALK_COUNT 10
test_instances_walk_cb(const char * name,void * data)3368 int test_instances_walk_cb(const char *name, void *data)
3369 {
3370 	struct test_walk_instance *instances  = (struct test_walk_instance *)data;
3371 	int i;
3372 
3373 	CU_TEST(instances != NULL);
3374 	CU_TEST(name != NULL);
3375 
3376 	for (i = 0; i < WALK_COUNT; i++) {
3377 		if (!strcmp(name,
3378 			    tracefs_instance_get_name(instances[i].instance))) {
3379 			instances[i].found = true;
3380 			break;
3381 		}
3382 	}
3383 
3384 	return 0;
3385 }
3386 
test_instances_walk(void)3387 static void test_instances_walk(void)
3388 {
3389 	struct test_walk_instance instances[WALK_COUNT];
3390 	int i;
3391 
3392 	memset(instances, 0, WALK_COUNT * sizeof(struct test_walk_instance));
3393 	for (i = 0; i < WALK_COUNT; i++) {
3394 		instances[i].instance = tracefs_instance_create(get_rand_str());
3395 		CU_TEST(instances[i].instance != NULL);
3396 	}
3397 
3398 	CU_TEST(tracefs_instances_walk(test_instances_walk_cb, instances) == 0);
3399 	for (i = 0; i < WALK_COUNT; i++) {
3400 		CU_TEST(instances[i].found);
3401 		tracefs_instance_destroy(instances[i].instance);
3402 		instances[i].found = false;
3403 	}
3404 
3405 	CU_TEST(tracefs_instances_walk(test_instances_walk_cb, instances) == 0);
3406 	for (i = 0; i < WALK_COUNT; i++) {
3407 		CU_TEST(!instances[i].found);
3408 		tracefs_instance_free(instances[i].instance);
3409 	}
3410 }
3411 
current_clock_check(struct tracefs_instance * instance,const char * clock)3412 static void current_clock_check(struct tracefs_instance *instance, const char *clock)
3413 {
3414 	int size = 0;
3415 	char *clocks;
3416 	char *str;
3417 
3418 	clocks = tracefs_instance_file_read(instance, TRACE_CLOCK, &size);
3419 	CU_TEST_FATAL(clocks != NULL);
3420 	CU_TEST(size > strlen(clock));
3421 	str = strstr(clocks, clock);
3422 	CU_TEST(str != NULL);
3423 	CU_TEST(str != clocks);
3424 	CU_TEST(*(str - 1) == '[');
3425 	CU_TEST(*(str + strlen(clock)) == ']');
3426 	free(clocks);
3427 }
3428 
test_instance_get_clock(struct tracefs_instance * instance)3429 static void test_instance_get_clock(struct tracefs_instance *instance)
3430 {
3431 	const char *clock;
3432 
3433 	clock = tracefs_get_clock(instance);
3434 	CU_TEST_FATAL(clock != NULL);
3435 	current_clock_check(instance, clock);
3436 	free((char *)clock);
3437 }
3438 
test_get_clock(void)3439 static void test_get_clock(void)
3440 {
3441 	test_instance_get_clock(test_instance);
3442 }
3443 
copy_trace_file(const char * from,char * to)3444 static void copy_trace_file(const char *from, char *to)
3445 {
3446 	int fd_from = -1;
3447 	int fd_to = -1;
3448 	char buf[512];
3449 	int ret;
3450 
3451 	fd_from = open(from, O_RDONLY);
3452 	if (fd_from < 0)
3453 		goto out;
3454 	fd_to = open(to, O_WRONLY | O_TRUNC | O_CREAT, S_IRWXU | S_IRWXG);
3455 	if (fd_to < 0)
3456 		goto out;
3457 
3458 	while ((ret = read(fd_from, buf, 512)) > 0) {
3459 		if (write(fd_to, buf, ret) == -1)
3460 			break;
3461 	}
3462 
3463 out:
3464 	if (fd_to >= 0)
3465 		close(fd_to);
3466 	if (fd_from >= 0)
3467 		close(fd_from);
3468 }
3469 
3470 static int trace_dir_base;
3471 static char *trace_tmp_dir;
copy_trace_walk(const char * fpath,const struct stat * sb,int typeflag,struct FTW * ftwbuf)3472 static int copy_trace_walk(const char *fpath, const struct stat *sb,
3473 			   int typeflag, struct FTW *ftwbuf)
3474 {
3475 	char path[PATH_MAX];
3476 
3477 	sprintf(path, "%s%s", trace_tmp_dir, fpath + trace_dir_base);
3478 
3479 	switch (typeflag) {
3480 	case FTW_D:
3481 		mkdir(path, 0750);
3482 		break;
3483 	case FTW_F:
3484 		copy_trace_file(fpath, path);
3485 		break;
3486 	default:
3487 		break;
3488 	}
3489 	return 0;
3490 }
3491 
dup_trace_dir(char * to,char * dir)3492 static void dup_trace_dir(char *to, char *dir)
3493 {
3494 	const char *trace_dir = tracefs_tracing_dir();
3495 	char file_from[PATH_MAX];
3496 	char file_to[PATH_MAX];
3497 
3498 	sprintf(file_from, "%s/%s", trace_dir, dir);
3499 	sprintf(file_to, "%s/%s", to, dir);
3500 	trace_tmp_dir = file_to;
3501 	trace_dir_base = strlen(file_from);
3502 	nftw(file_from, copy_trace_walk, 20, 0);
3503 }
3504 
dup_trace_file(char * to,char * file)3505 static void dup_trace_file(char *to, char *file)
3506 {
3507 	const char *trace_dir = tracefs_tracing_dir();
3508 	char file_from[PATH_MAX];
3509 	char file_to[PATH_MAX];
3510 
3511 	sprintf(file_from, "%s/%s", trace_dir, file);
3512 	sprintf(file_to, "%s/%s", to, file);
3513 	copy_trace_file(file_from, file_to);
3514 }
3515 
copy_trace_dir(void)3516 static char *copy_trace_dir(void)
3517 {
3518 	char template[] = TEST_TRACE_DIR;
3519 	char *dname = mkdtemp(template);
3520 
3521 	dup_trace_dir(dname, "events");
3522 	dup_trace_dir(dname, "options");
3523 	dup_trace_file(dname, TRACE_ON);
3524 	dup_trace_file(dname, CUR_TRACER);
3525 	dup_trace_file(dname, TRACE_CLOCK);
3526 	dup_trace_file(dname, ALL_TRACERS);
3527 
3528 	return strdup(dname);
3529 }
3530 
del_trace_walk(const char * fpath,const struct stat * sb,int typeflag,struct FTW * ftwbuf)3531 static int del_trace_walk(const char *fpath, const struct stat *sb,
3532 			  int typeflag, struct FTW *ftwbuf)
3533 {
3534 	remove(fpath);
3535 	return 0;
3536 }
3537 
del_trace_dir(char * dir)3538 void del_trace_dir(char *dir)
3539 {
3540 	nftw(dir, del_trace_walk, 20, FTW_DEPTH);
3541 }
3542 
test_custom_trace_dir(void)3543 static void test_custom_trace_dir(void)
3544 {
3545 	char *tdir = "/tmp/custom_tracefs";
3546 	struct tracefs_instance *instance;
3547 	char *dname = copy_trace_dir();
3548 	const char *trace_dir;
3549 	char *tfile;
3550 
3551 	instance = tracefs_instance_alloc(dname, NULL);
3552 	CU_TEST(instance != NULL);
3553 
3554 	system_event(dname);
3555 	local_events(dname);
3556 	test_instance_tracing_options(instance);
3557 	test_instance_get_clock(instance);
3558 	test_instance_file_fd(instance);
3559 	test_instance_tracers(instance);
3560 
3561 	tracefs_instance_free(instance);
3562 	del_trace_dir(dname);
3563 	free(dname);
3564 
3565 	trace_dir = tracefs_tracing_dir();
3566 	CU_TEST(trace_dir != NULL);
3567 	CU_TEST(tracefs_set_tracing_dir(tdir) == 0);
3568 	CU_TEST(strcmp(tdir, tracefs_tracing_dir()) == 0);
3569 	tfile = tracefs_get_tracing_file("trace");
3570 	CU_TEST(tfile != NULL);
3571 	CU_TEST(strcmp(tdir, dirname(tfile)) == 0);
3572 	free(tfile);
3573 
3574 	CU_TEST(tracefs_set_tracing_dir(NULL) == 0);
3575 	CU_TEST(strcmp(trace_dir, tracefs_tracing_dir()) == 0);
3576 	tfile = tracefs_get_tracing_file("trace");
3577 	CU_TEST(tfile != NULL);
3578 	CU_TEST(strcmp(trace_dir, dirname(tfile)) == 0);
3579 	free(tfile);
3580 }
3581 
test_suite_destroy(void)3582 static int test_suite_destroy(void)
3583 {
3584 	tracefs_instance_reset(NULL);
3585 	tracefs_instance_destroy(test_instance);
3586 	tracefs_instance_free(test_instance);
3587 	tep_free(test_tep);
3588 	return 0;
3589 }
3590 
test_suite_init(void)3591 static int test_suite_init(void)
3592 {
3593 	test_tep = tracefs_local_events(NULL);
3594 	if (test_tep == NULL)
3595 		return 1;
3596 	test_instance = tracefs_instance_create(TEST_INSTANCE_NAME);
3597 	if (!test_instance)
3598 		return 1;
3599 
3600 	mapping_is_supported = tracefs_mapped_is_supported();
3601 	if (mapping_is_supported)
3602 		printf("Testing mmapped buffers too\n");
3603 	else
3604 		printf("Memory mapped buffers not supported\n");
3605 
3606 	/* Start with a new slate */
3607 	tracefs_instance_reset(NULL);
3608 
3609 	return 0;
3610 }
3611 
test_tracefs_lib(void)3612 void test_tracefs_lib(void)
3613 {
3614 	CU_pSuite suite = NULL;
3615 
3616 	suite = CU_add_suite(TRACEFS_SUITE, test_suite_init, test_suite_destroy);
3617 	if (suite == NULL) {
3618 		fprintf(stderr, "Suite \"%s\" cannot be ceated\n", TRACEFS_SUITE);
3619 		return;
3620 	}
3621 
3622 	CU_add_test(suite, "Test tracefs/debugfs mounting", test_mounting);
3623 	CU_add_test(suite, "trace cpu read",
3624 		    test_trace_cpu_read);
3625 	CU_add_test(suite, "trace cpu read_buf_percent",
3626 		    test_trace_cpu_read_buf_percent);
3627 	CU_add_test(suite, "trace cpu pipe",
3628 		    test_trace_cpu_pipe);
3629 	CU_add_test(suite, "trace pid events filter",
3630 		    test_trace_events_pid_filter);
3631 	CU_add_test(suite, "trace pid function filter",
3632 		    test_trace_function_pid_filter);
3633 	CU_add_test(suite, "trace sql",
3634 		    test_trace_sql);
3635 	CU_add_test(suite, "trace sql trace onmax",
3636 		    test_trace_sql_trace_onmax);
3637 	CU_add_test(suite, "trace sql trace onchange",
3638 		    test_trace_sql_trace_onchange);
3639 	CU_add_test(suite, "trace sql snapshot onmax",
3640 		    test_trace_sql_snapshot_onmax);
3641 	CU_add_test(suite, "trace sql snapshot onchange",
3642 		    test_trace_sql_snapshot_onchange);
3643 	CU_add_test(suite, "trace sql save onmax",
3644 		    test_trace_sql_save_onmax);
3645 	CU_add_test(suite, "trace sql save onchange",
3646 		    test_trace_sql_save_onchange);
3647 	CU_add_test(suite, "trace sql trace and snapshot onmax",
3648 		    test_trace_sql_trace_snapshot_onmax);
3649 	CU_add_test(suite, "trace sql trace and snapshot onchange",
3650 		    test_trace_sql_trace_snapshot_onchange);
3651 	CU_add_test(suite, "tracing file / directory APIs",
3652 		    test_trace_file);
3653 	CU_add_test(suite, "instance file / directory APIs",
3654 		    test_file_fd);
3655 	CU_add_test(suite, "instance file descriptor",
3656 		    test_instance_file);
3657 	CU_add_test(suite, "instance reset",
3658 		    test_instance_reset);
3659 	CU_add_test(suite, "systems and events APIs",
3660 		    test_system_event);
3661 	CU_add_test(suite, "tracefs_iterate_snapshot_events API",
3662 		    test_iter_snapshot_events);
3663 
3664 	CU_add_test(suite, "tracefs_iterate_raw_events API",
3665 		    test_iter_raw_events);
3666 
3667 	/* Follow events test must be after the iterate raw events above */
3668 	CU_add_test(suite, "Follow events", test_follow_events);
3669 	CU_add_test(suite, "Follow events clear", test_follow_events_clear);
3670 
3671 	CU_add_test(suite, "tracefs_tracers API",
3672 		    test_tracers);
3673 	CU_add_test(suite, "tracefs_local events API",
3674 		    test_local_events);
3675 	CU_add_test(suite, "tracefs_instances_walk API",
3676 		    test_instances_walk);
3677 	CU_add_test(suite, "tracefs_get_clock API",
3678 		    test_get_clock);
3679 	CU_add_test(suite, "tracing on / off",
3680 		    test_tracing_onoff);
3681 	CU_add_test(suite, "tracing options",
3682 		    test_tracing_options);
3683 	CU_add_test(suite, "custom system directory",
3684 		    test_custom_trace_dir);
3685 	CU_add_test(suite, "ftrace marker",
3686 		    test_ftrace_marker);
3687 	CU_add_test(suite, "kprobes", test_kprobes);
3688 	CU_add_test(suite, "synthetic events", test_synthetic);
3689 	CU_add_test(suite, "eprobes", test_eprobes);
3690 	CU_add_test(suite, "uprobes", test_uprobes);
3691 }
3692