1 // SPDX-License-Identifier: GPL-2.0
3 * dlfilter-test-api-v0.c: test original (v0) API for perf --dlfilter shared object
4 * Copyright (c) 2021, Intel Corporation.
12 * Copy original (v0) API instead of including current API
14 #include <linux/perf_event.h>
15 #include <linux/types.h>
17 /* Definitions for perf_dlfilter_sample flags */
19 PERF_DLFILTER_FLAG_BRANCH
= 1ULL << 0,
20 PERF_DLFILTER_FLAG_CALL
= 1ULL << 1,
21 PERF_DLFILTER_FLAG_RETURN
= 1ULL << 2,
22 PERF_DLFILTER_FLAG_CONDITIONAL
= 1ULL << 3,
23 PERF_DLFILTER_FLAG_SYSCALLRET
= 1ULL << 4,
24 PERF_DLFILTER_FLAG_ASYNC
= 1ULL << 5,
25 PERF_DLFILTER_FLAG_INTERRUPT
= 1ULL << 6,
26 PERF_DLFILTER_FLAG_TX_ABORT
= 1ULL << 7,
27 PERF_DLFILTER_FLAG_TRACE_BEGIN
= 1ULL << 8,
28 PERF_DLFILTER_FLAG_TRACE_END
= 1ULL << 9,
29 PERF_DLFILTER_FLAG_IN_TX
= 1ULL << 10,
30 PERF_DLFILTER_FLAG_VMENTRY
= 1ULL << 11,
31 PERF_DLFILTER_FLAG_VMEXIT
= 1ULL << 12,
35 * perf sample event information (as per perf script and <linux/perf_event.h>)
37 struct perf_dlfilter_sample
{
38 __u32 size
; /* Size of this structure (for compatibility checking) */
39 __u16 ins_lat
; /* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */
40 __u16 p_stage_cyc
; /* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */
49 __u64 weight
; /* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */
50 __u64 transaction
; /* Refer PERF_SAMPLE_TRANSACTION in <linux/perf_event.h> */
51 __u64 insn_cnt
; /* For instructions-per-cycle (IPC) */
52 __u64 cyc_cnt
; /* For instructions-per-cycle (IPC) */
54 __u32 flags
; /* Refer PERF_DLFILTER_FLAG_* above */
55 __u64 data_src
; /* Refer PERF_SAMPLE_DATA_SRC in <linux/perf_event.h> */
56 __u64 phys_addr
; /* Refer PERF_SAMPLE_PHYS_ADDR in <linux/perf_event.h> */
57 __u64 data_page_size
; /* Refer PERF_SAMPLE_DATA_PAGE_SIZE in <linux/perf_event.h> */
58 __u64 code_page_size
; /* Refer PERF_SAMPLE_CODE_PAGE_SIZE in <linux/perf_event.h> */
59 __u64 cgroup
; /* Refer PERF_SAMPLE_CGROUP in <linux/perf_event.h> */
60 __u8 cpumode
; /* Refer CPUMODE_MASK etc in <linux/perf_event.h> */
61 __u8 addr_correlates_sym
; /* True => resolve_addr() can be called */
62 __u16 misc
; /* Refer perf_event_header in <linux/perf_event.h> */
63 __u32 raw_size
; /* Refer PERF_SAMPLE_RAW in <linux/perf_event.h> */
64 const void *raw_data
; /* Refer PERF_SAMPLE_RAW in <linux/perf_event.h> */
65 __u64 brstack_nr
; /* Number of brstack entries */
66 const struct perf_branch_entry
*brstack
; /* Refer <linux/perf_event.h> */
67 __u64 raw_callchain_nr
; /* Number of raw_callchain entries */
68 const __u64
*raw_callchain
; /* Refer <linux/perf_event.h> */
73 * Address location (as per perf script)
75 struct perf_dlfilter_al
{
76 __u32 size
; /* Size of this structure (for compatibility checking) */
79 __u64 addr
; /* Mapped address (from dso) */
83 __u8 sym_binding
; /* STB_LOCAL, STB_GLOBAL or STB_WEAK, refer <elf.h> */
84 __u8 is_64_bit
; /* Only valid if dso is not NULL */
85 __u8 is_kernel_ip
; /* True if in kernel space */
88 /* Below members are only populated by resolve_ip() */
89 __u8 filtered
; /* True if this sample event will be filtered out */
93 struct perf_dlfilter_fns
{
94 /* Return information about ip */
95 const struct perf_dlfilter_al
*(*resolve_ip
)(void *ctx
);
96 /* Return information about addr (if addr_correlates_sym) */
97 const struct perf_dlfilter_al
*(*resolve_addr
)(void *ctx
);
98 /* Return arguments from --dlarg option */
99 char **(*args
)(void *ctx
, int *dlargc
);
101 * Return information about address (al->size must be set before
102 * calling). Returns 0 on success, -1 otherwise.
104 __s32 (*resolve_address
)(void *ctx
, __u64 address
, struct perf_dlfilter_al
*al
);
105 /* Return instruction bytes and length */
106 const __u8
*(*insn
)(void *ctx
, __u32
*length
);
107 /* Return source file name and line number */
108 const char *(*srcline
)(void *ctx
, __u32
*line_number
);
109 /* Return perf_event_attr, refer <linux/perf_event.h> */
110 struct perf_event_attr
*(*attr
)(void *ctx
);
111 /* Read object code, return numbers of bytes read */
112 __s32 (*object_code
)(void *ctx
, __u64 ip
, void *buf
, __u32 len
);
114 void *(*reserved
[120])(void *);
117 struct perf_dlfilter_fns perf_dlfilter_fns
;
121 #define pr_debug(fmt, ...) do { \
123 fprintf(stderr, fmt, ##__VA_ARGS__); \
126 static int test_fail(const char *msg
)
128 pr_debug("%s\n", msg
);
132 #define CHECK(x) do { \
134 return test_fail("Check '" #x "' failed\n"); \
141 int early_filter_cnt
;
145 static struct filter_data
*filt_dat
;
147 int start(void **data
, void *ctx
)
151 struct filter_data
*d
;
156 CHECK(!filt_dat
&& !called
);
159 d
= calloc(1, sizeof(*d
));
161 test_fail("Failed to allocate memory");
165 dlargv
= perf_dlfilter_fns
.args(ctx
, &dlargc
);
168 CHECK(!strcmp(dlargv
[0], "first"));
169 verbose
= strtol(dlargv
[1], NULL
, 0);
170 d
->ip
= strtoull(dlargv
[2], NULL
, 0);
171 d
->addr
= strtoull(dlargv
[3], NULL
, 0);
172 d
->do_early
= strtol(dlargv
[4], NULL
, 0);
173 CHECK(!strcmp(dlargv
[5], "last"));
175 pr_debug("%s API\n", __func__
);
180 #define CHECK_SAMPLE(x) do { \
181 if (sample->x != expected.x) \
182 return test_fail("'" #x "' not expected value\n"); \
185 static int check_sample(struct filter_data
*d
, const struct perf_dlfilter_sample
*sample
)
187 struct perf_dlfilter_sample expected
= {
197 .cpumode
= PERF_RECORD_MISC_USER
,
198 .addr_correlates_sym
= 1,
199 .misc
= PERF_RECORD_MISC_USER
,
202 CHECK(sample
->size
>= sizeof(struct perf_dlfilter_sample
));
210 CHECK_SAMPLE(stream_id
);
211 CHECK_SAMPLE(period
);
213 CHECK_SAMPLE(cpumode
);
214 CHECK_SAMPLE(addr_correlates_sym
);
217 CHECK(!sample
->raw_data
);
218 CHECK_SAMPLE(brstack_nr
);
219 CHECK(!sample
->brstack
);
220 CHECK_SAMPLE(raw_callchain_nr
);
221 CHECK(!sample
->raw_callchain
);
223 #define EVENT_NAME "branches"
224 CHECK(!strncmp(sample
->event
, EVENT_NAME
, strlen(EVENT_NAME
)));
229 static int check_al(void *ctx
)
231 const struct perf_dlfilter_al
*al
;
233 al
= perf_dlfilter_fns
.resolve_ip(ctx
);
235 return test_fail("resolve_ip() failed");
237 CHECK(al
->sym
&& !strcmp("foo", al
->sym
));
243 static int check_addr_al(void *ctx
)
245 const struct perf_dlfilter_al
*addr_al
;
247 addr_al
= perf_dlfilter_fns
.resolve_addr(ctx
);
249 return test_fail("resolve_addr() failed");
251 CHECK(addr_al
->sym
&& !strcmp("bar", addr_al
->sym
));
252 CHECK(!addr_al
->symoff
);
257 static int check_address_al(void *ctx
, const struct perf_dlfilter_sample
*sample
)
259 struct perf_dlfilter_al address_al
;
260 const struct perf_dlfilter_al
*al
;
262 al
= perf_dlfilter_fns
.resolve_ip(ctx
);
264 return test_fail("resolve_ip() failed");
266 address_al
.size
= sizeof(address_al
);
267 if (perf_dlfilter_fns
.resolve_address(ctx
, sample
->ip
, &address_al
))
268 return test_fail("resolve_address() failed");
270 CHECK(address_al
.sym
&& al
->sym
);
271 CHECK(!strcmp(address_al
.sym
, al
->sym
));
272 CHECK(address_al
.addr
== al
->addr
);
273 CHECK(address_al
.sym_start
== al
->sym_start
);
274 CHECK(address_al
.sym_end
== al
->sym_end
);
275 CHECK(address_al
.dso
&& al
->dso
);
276 CHECK(!strcmp(address_al
.dso
, al
->dso
));
281 static int check_attr(void *ctx
)
283 struct perf_event_attr
*attr
= perf_dlfilter_fns
.attr(ctx
);
286 CHECK(attr
->type
== PERF_TYPE_HARDWARE
);
287 CHECK(attr
->config
== PERF_COUNT_HW_BRANCH_INSTRUCTIONS
);
292 static int check_object_code(void *ctx
, const struct perf_dlfilter_sample
*sample
)
296 CHECK(perf_dlfilter_fns
.object_code(ctx
, sample
->ip
, buf
, sizeof(buf
)) > 0);
301 static int do_checks(void *data
, const struct perf_dlfilter_sample
*sample
, void *ctx
, bool early
)
303 struct filter_data
*d
= data
;
305 CHECK(data
&& filt_dat
== data
);
308 CHECK(!d
->early_filter_cnt
);
309 d
->early_filter_cnt
+= 1;
311 CHECK(!d
->filter_cnt
);
312 CHECK(d
->early_filter_cnt
);
313 CHECK(d
->do_early
!= 2);
317 if (check_sample(data
, sample
))
323 if (early
&& !d
->do_early
)
326 if (check_al(ctx
) || check_addr_al(ctx
) || check_address_al(ctx
, sample
) ||
327 check_object_code(ctx
, sample
))
331 return d
->do_early
== 2;
336 int filter_event_early(void *data
, const struct perf_dlfilter_sample
*sample
, void *ctx
)
338 pr_debug("%s API\n", __func__
);
340 return do_checks(data
, sample
, ctx
, true);
343 int filter_event(void *data
, const struct perf_dlfilter_sample
*sample
, void *ctx
)
345 pr_debug("%s API\n", __func__
);
347 return do_checks(data
, sample
, ctx
, false);
350 int stop(void *data
, void *ctx
)
354 pr_debug("%s API\n", __func__
);
356 CHECK(data
&& filt_dat
== data
&& !called
);
364 const char *filter_description(const char **long_description
)
366 *long_description
= "Filter used by the 'dlfilter C API' perf test";
367 return "dlfilter to test v0 C API";