1 // SPDX-License-Identifier: GPL-2.0
2 #include <stdbool.h>
3 #include <linux/err.h>
4 #include <linux/string.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 #include "evlist.h"
9 #include "evsel.h"
10 #include "thread_map.h"
11 #include "record.h"
12 #include "tests.h"
13 #include "debug.h"
14 #include "util/mmap.h"
15 #include <errno.h>
16 
17 #ifndef O_DIRECTORY
18 #define O_DIRECTORY    00200000
19 #endif
20 #ifndef AT_FDCWD
21 #define AT_FDCWD       -100
22 #endif
23 
24 int test__syscall_openat_tp_fields(struct test *test __maybe_unused, int subtest __maybe_unused)
25 {
26 	struct record_opts opts = {
27 		.target = {
28 			.uid = UINT_MAX,
29 			.uses_mmap = true,
30 		},
31 		.no_buffering = true,
32 		.freq	      = 1,
33 		.mmap_pages   = 256,
34 		.raw_samples  = true,
35 	};
36 	const char *filename = "/etc/passwd";
37 	int flags = O_RDONLY | O_DIRECTORY;
38 	struct evlist *evlist = evlist__new();
39 	struct evsel *evsel;
40 	int err = -1, i, nr_events = 0, nr_polls = 0;
41 	char sbuf[STRERR_BUFSIZE];
42 
43 	if (evlist == NULL) {
44 		pr_debug("%s: perf_evlist__new\n", __func__);
45 		goto out;
46 	}
47 
48 	evsel = perf_evsel__newtp("syscalls", "sys_enter_openat");
49 	if (IS_ERR(evsel)) {
50 		pr_debug("%s: perf_evsel__newtp\n", __func__);
51 		goto out_delete_evlist;
52 	}
53 
54 	evlist__add(evlist, evsel);
55 
56 	err = perf_evlist__create_maps(evlist, &opts.target);
57 	if (err < 0) {
58 		pr_debug("%s: perf_evlist__create_maps\n", __func__);
59 		goto out_delete_evlist;
60 	}
61 
62 	perf_evsel__config(evsel, &opts, NULL);
63 
64 	perf_thread_map__set_pid(evlist->core.threads, 0, getpid());
65 
66 	err = evlist__open(evlist);
67 	if (err < 0) {
68 		pr_debug("perf_evlist__open: %s\n",
69 			 str_error_r(errno, sbuf, sizeof(sbuf)));
70 		goto out_delete_evlist;
71 	}
72 
73 	err = evlist__mmap(evlist, UINT_MAX);
74 	if (err < 0) {
75 		pr_debug("evlist__mmap: %s\n",
76 			 str_error_r(errno, sbuf, sizeof(sbuf)));
77 		goto out_delete_evlist;
78 	}
79 
80 	evlist__enable(evlist);
81 
82 	/*
83 	 * Generate the event:
84 	 */
85 	openat(AT_FDCWD, filename, flags);
86 
87 	while (1) {
88 		int before = nr_events;
89 
90 		for (i = 0; i < evlist->core.nr_mmaps; i++) {
91 			union perf_event *event;
92 			struct mmap *md;
93 
94 			md = &evlist->mmap[i];
95 			if (perf_mmap__read_init(md) < 0)
96 				continue;
97 
98 			while ((event = perf_mmap__read_event(md)) != NULL) {
99 				const u32 type = event->header.type;
100 				int tp_flags;
101 				struct perf_sample sample;
102 
103 				++nr_events;
104 
105 				if (type != PERF_RECORD_SAMPLE) {
106 					perf_mmap__consume(md);
107 					continue;
108 				}
109 
110 				err = perf_evsel__parse_sample(evsel, event, &sample);
111 				if (err) {
112 					pr_debug("Can't parse sample, err = %d\n", err);
113 					goto out_delete_evlist;
114 				}
115 
116 				tp_flags = perf_evsel__intval(evsel, &sample, "flags");
117 
118 				if (flags != tp_flags) {
119 					pr_debug("%s: Expected flags=%#x, got %#x\n",
120 						 __func__, flags, tp_flags);
121 					goto out_delete_evlist;
122 				}
123 
124 				goto out_ok;
125 			}
126 			perf_mmap__read_done(md);
127 		}
128 
129 		if (nr_events == before)
130 			evlist__poll(evlist, 10);
131 
132 		if (++nr_polls > 5) {
133 			pr_debug("%s: no events!\n", __func__);
134 			goto out_delete_evlist;
135 		}
136 	}
137 out_ok:
138 	err = 0;
139 out_delete_evlist:
140 	evlist__delete(evlist);
141 out:
142 	return err;
143 }
144