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