1#include <stdbool.h>
2#include <inttypes.h>
3
4#include "util.h"
5#include "event.h"
6#include "evsel.h"
7
8#include "tests.h"
9
10#define COMP(m) do {					\
11	if (s1->m != s2->m) {				\
12		pr_debug("Samples differ at '"#m"'\n");	\
13		return false;				\
14	}						\
15} while (0)
16
17#define MCOMP(m) do {					\
18	if (memcmp(&s1->m, &s2->m, sizeof(s1->m))) {	\
19		pr_debug("Samples differ at '"#m"'\n");	\
20		return false;				\
21	}						\
22} while (0)
23
24static bool samples_same(const struct perf_sample *s1,
25			 const struct perf_sample *s2, u64 type, u64 regs_user,
26			 u64 read_format)
27{
28	size_t i;
29
30	if (type & PERF_SAMPLE_IDENTIFIER)
31		COMP(id);
32
33	if (type & PERF_SAMPLE_IP)
34		COMP(ip);
35
36	if (type & PERF_SAMPLE_TID) {
37		COMP(pid);
38		COMP(tid);
39	}
40
41	if (type & PERF_SAMPLE_TIME)
42		COMP(time);
43
44	if (type & PERF_SAMPLE_ADDR)
45		COMP(addr);
46
47	if (type & PERF_SAMPLE_ID)
48		COMP(id);
49
50	if (type & PERF_SAMPLE_STREAM_ID)
51		COMP(stream_id);
52
53	if (type & PERF_SAMPLE_CPU)
54		COMP(cpu);
55
56	if (type & PERF_SAMPLE_PERIOD)
57		COMP(period);
58
59	if (type & PERF_SAMPLE_READ) {
60		if (read_format & PERF_FORMAT_GROUP)
61			COMP(read.group.nr);
62		else
63			COMP(read.one.value);
64		if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
65			COMP(read.time_enabled);
66		if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
67			COMP(read.time_running);
68		/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
69		if (read_format & PERF_FORMAT_GROUP) {
70			for (i = 0; i < s1->read.group.nr; i++)
71				MCOMP(read.group.values[i]);
72		} else {
73			COMP(read.one.id);
74		}
75	}
76
77	if (type & PERF_SAMPLE_CALLCHAIN) {
78		COMP(callchain->nr);
79		for (i = 0; i < s1->callchain->nr; i++)
80			COMP(callchain->ips[i]);
81	}
82
83	if (type & PERF_SAMPLE_RAW) {
84		COMP(raw_size);
85		if (memcmp(s1->raw_data, s2->raw_data, s1->raw_size)) {
86			pr_debug("Samples differ at 'raw_data'\n");
87			return false;
88		}
89	}
90
91	if (type & PERF_SAMPLE_BRANCH_STACK) {
92		COMP(branch_stack->nr);
93		for (i = 0; i < s1->branch_stack->nr; i++)
94			MCOMP(branch_stack->entries[i]);
95	}
96
97	if (type & PERF_SAMPLE_REGS_USER) {
98		size_t sz = hweight_long(regs_user) * sizeof(u64);
99
100		COMP(user_regs.abi);
101		if (s1->user_regs.abi &&
102		    (!s1->user_regs.regs || !s2->user_regs.regs ||
103		     memcmp(s1->user_regs.regs, s2->user_regs.regs, sz))) {
104			pr_debug("Samples differ at 'user_regs'\n");
105			return false;
106		}
107	}
108
109	if (type & PERF_SAMPLE_STACK_USER) {
110		COMP(user_stack.size);
111		if (memcmp(s1->user_stack.data, s1->user_stack.data,
112			   s1->user_stack.size)) {
113			pr_debug("Samples differ at 'user_stack'\n");
114			return false;
115		}
116	}
117
118	if (type & PERF_SAMPLE_WEIGHT)
119		COMP(weight);
120
121	if (type & PERF_SAMPLE_DATA_SRC)
122		COMP(data_src);
123
124	return true;
125}
126
127static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
128{
129	struct perf_evsel evsel = {
130		.needs_swap = false,
131		.attr = {
132			.sample_type = sample_type,
133			.sample_regs_user = sample_regs_user,
134			.read_format = read_format,
135		},
136	};
137	union perf_event *event;
138	union {
139		struct ip_callchain callchain;
140		u64 data[64];
141	} callchain = {
142		/* 3 ips */
143		.data = {3, 201, 202, 203},
144	};
145	union {
146		struct branch_stack branch_stack;
147		u64 data[64];
148	} branch_stack = {
149		/* 1 branch_entry */
150		.data = {1, 211, 212, 213},
151	};
152	u64 user_regs[64];
153	const u64 raw_data[] = {0x123456780a0b0c0dULL, 0x1102030405060708ULL};
154	const u64 data[] = {0x2211443366558877ULL, 0, 0xaabbccddeeff4321ULL};
155	struct perf_sample sample = {
156		.ip		= 101,
157		.pid		= 102,
158		.tid		= 103,
159		.time		= 104,
160		.addr		= 105,
161		.id		= 106,
162		.stream_id	= 107,
163		.period		= 108,
164		.weight		= 109,
165		.cpu		= 110,
166		.raw_size	= sizeof(raw_data),
167		.data_src	= 111,
168		.raw_data	= (void *)raw_data,
169		.callchain	= &callchain.callchain,
170		.branch_stack	= &branch_stack.branch_stack,
171		.user_regs	= {
172			.abi	= PERF_SAMPLE_REGS_ABI_64,
173			.regs	= user_regs,
174		},
175		.user_stack	= {
176			.size	= sizeof(data),
177			.data	= (void *)data,
178		},
179		.read		= {
180			.time_enabled = 0x030a59d664fca7deULL,
181			.time_running = 0x011b6ae553eb98edULL,
182		},
183	};
184	struct sample_read_value values[] = {{1, 5}, {9, 3}, {2, 7}, {6, 4},};
185	struct perf_sample sample_out;
186	size_t i, sz, bufsz;
187	int err, ret = -1;
188
189	for (i = 0; i < sizeof(user_regs); i++)
190		*(i + (u8 *)user_regs) = i & 0xfe;
191
192	if (read_format & PERF_FORMAT_GROUP) {
193		sample.read.group.nr     = 4;
194		sample.read.group.values = values;
195	} else {
196		sample.read.one.value = 0x08789faeb786aa87ULL;
197		sample.read.one.id    = 99;
198	}
199
200	sz = perf_event__sample_event_size(&sample, sample_type,
201					   sample_regs_user, read_format);
202	bufsz = sz + 4096; /* Add a bit for overrun checking */
203	event = malloc(bufsz);
204	if (!event) {
205		pr_debug("malloc failed\n");
206		return -1;
207	}
208
209	memset(event, 0xff, bufsz);
210	event->header.type = PERF_RECORD_SAMPLE;
211	event->header.misc = 0;
212	event->header.size = sz;
213
214	err = perf_event__synthesize_sample(event, sample_type,
215					    sample_regs_user, read_format,
216					    &sample, false);
217	if (err) {
218		pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
219			 "perf_event__synthesize_sample", sample_type, err);
220		goto out_free;
221	}
222
223	/* The data does not contain 0xff so we use that to check the size */
224	for (i = bufsz; i > 0; i--) {
225		if (*(i - 1 + (u8 *)event) != 0xff)
226			break;
227	}
228	if (i != sz) {
229		pr_debug("Event size mismatch: actual %zu vs expected %zu\n",
230			 i, sz);
231		goto out_free;
232	}
233
234	evsel.sample_size = __perf_evsel__sample_size(sample_type);
235
236	err = perf_evsel__parse_sample(&evsel, event, &sample_out);
237	if (err) {
238		pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
239			 "perf_evsel__parse_sample", sample_type, err);
240		goto out_free;
241	}
242
243	if (!samples_same(&sample, &sample_out, sample_type,
244			  sample_regs_user, read_format)) {
245		pr_debug("parsing failed for sample_type %#"PRIx64"\n",
246			 sample_type);
247		goto out_free;
248	}
249
250	ret = 0;
251out_free:
252	free(event);
253	if (ret && read_format)
254		pr_debug("read_format %#"PRIx64"\n", read_format);
255	return ret;
256}
257
258/**
259 * test__sample_parsing - test sample parsing.
260 *
261 * This function implements a test that synthesizes a sample event, parses it
262 * and then checks that the parsed sample matches the original sample.  The test
263 * checks sample format bits separately and together.  If the test passes %0 is
264 * returned, otherwise %-1 is returned.
265 */
266int test__sample_parsing(void)
267{
268	const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15};
269	u64 sample_type;
270	u64 sample_regs_user;
271	size_t i;
272	int err;
273
274	/*
275	 * Fail the test if it has not been updated when new sample format bits
276	 * were added.
277	 */
278	if (PERF_SAMPLE_MAX > PERF_SAMPLE_IDENTIFIER << 1) {
279		pr_debug("sample format has changed - test needs updating\n");
280		return -1;
281	}
282
283	/* Test each sample format bit separately */
284	for (sample_type = 1; sample_type != PERF_SAMPLE_MAX;
285	     sample_type <<= 1) {
286		/* Test read_format variations */
287		if (sample_type == PERF_SAMPLE_READ) {
288			for (i = 0; i < ARRAY_SIZE(rf); i++) {
289				err = do_test(sample_type, 0, rf[i]);
290				if (err)
291					return err;
292			}
293			continue;
294		}
295
296		if (sample_type == PERF_SAMPLE_REGS_USER)
297			sample_regs_user = 0x3fff;
298		else
299			sample_regs_user = 0;
300
301		err = do_test(sample_type, sample_regs_user, 0);
302		if (err)
303			return err;
304	}
305
306	/* Test all sample format bits together */
307	sample_type = PERF_SAMPLE_MAX - 1;
308	sample_regs_user = 0x3fff;
309	for (i = 0; i < ARRAY_SIZE(rf); i++) {
310		err = do_test(sample_type, sample_regs_user, rf[i]);
311		if (err)
312			return err;
313	}
314
315	return 0;
316}
317