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