1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <stdbool.h>
3 #include <inttypes.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <linux/bitops.h>
7 #include <linux/kernel.h>
8 #include <linux/types.h>
9 
10 #include "event.h"
11 #include "evsel.h"
12 #include "debug.h"
13 #include "util/sample.h"
14 #include "util/synthetic-events.h"
15 
16 #include "tests/tests.h"
17 #include "arch-tests.h"
18 
19 #define COMP(m) do {					\
20 	if (s1->m != s2->m) {				\
21 		pr_debug("Samples differ at '"#m"'\n");	\
22 		return false;				\
23 	}						\
24 } while (0)
25 
26 static bool samples_same(const struct perf_sample *s1,
27 			 const struct perf_sample *s2,
28 			 u64 type)
29 {
30 	if (type & PERF_SAMPLE_WEIGHT_STRUCT)
31 		COMP(ins_lat);
32 
33 	return true;
34 }
35 
36 static int do_test(u64 sample_type)
37 {
38 	struct evsel evsel = {
39 		.needs_swap = false,
40 		.core = {
41 			. attr = {
42 				.sample_type = sample_type,
43 				.read_format = 0,
44 			},
45 		},
46 	};
47 	union perf_event *event;
48 	struct perf_sample sample = {
49 		.weight		= 101,
50 		.ins_lat        = 102,
51 	};
52 	struct perf_sample sample_out;
53 	size_t i, sz, bufsz;
54 	int err, ret = -1;
55 
56 	sz = perf_event__sample_event_size(&sample, sample_type, 0);
57 	bufsz = sz + 4096; /* Add a bit for overrun checking */
58 	event = malloc(bufsz);
59 	if (!event) {
60 		pr_debug("malloc failed\n");
61 		return -1;
62 	}
63 
64 	memset(event, 0xff, bufsz);
65 	event->header.type = PERF_RECORD_SAMPLE;
66 	event->header.misc = 0;
67 	event->header.size = sz;
68 
69 	err = perf_event__synthesize_sample(event, sample_type, 0, &sample);
70 	if (err) {
71 		pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
72 			 "perf_event__synthesize_sample", sample_type, err);
73 		goto out_free;
74 	}
75 
76 	/* The data does not contain 0xff so we use that to check the size */
77 	for (i = bufsz; i > 0; i--) {
78 		if (*(i - 1 + (u8 *)event) != 0xff)
79 			break;
80 	}
81 	if (i != sz) {
82 		pr_debug("Event size mismatch: actual %zu vs expected %zu\n",
83 			 i, sz);
84 		goto out_free;
85 	}
86 
87 	evsel.sample_size = __evsel__sample_size(sample_type);
88 
89 	err = evsel__parse_sample(&evsel, event, &sample_out);
90 	if (err) {
91 		pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
92 			 "evsel__parse_sample", sample_type, err);
93 		goto out_free;
94 	}
95 
96 	if (!samples_same(&sample, &sample_out, sample_type)) {
97 		pr_debug("parsing failed for sample_type %#"PRIx64"\n",
98 			 sample_type);
99 		goto out_free;
100 	}
101 
102 	ret = 0;
103 out_free:
104 	free(event);
105 
106 	return ret;
107 }
108 
109 /**
110  * test__x86_sample_parsing - test X86 specific sample parsing
111  *
112  * This function implements a test that synthesizes a sample event, parses it
113  * and then checks that the parsed sample matches the original sample. If the
114  * test passes %0 is returned, otherwise %-1 is returned.
115  *
116  * For now, the PERF_SAMPLE_WEIGHT_STRUCT is the only X86 specific sample type.
117  * The test only checks the PERF_SAMPLE_WEIGHT_STRUCT type.
118  */
119 int test__x86_sample_parsing(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
120 {
121 	return do_test(PERF_SAMPLE_WEIGHT_STRUCT);
122 }
123