182b0a103SAdrian Hunter // SPDX-License-Identifier: GPL-2.0
282b0a103SAdrian Hunter /*
382b0a103SAdrian Hunter  * Test v2 API for perf --dlfilter shared object
482b0a103SAdrian Hunter  * Copyright (c) 2023, Intel Corporation.
582b0a103SAdrian Hunter  */
682b0a103SAdrian Hunter #include <stdio.h>
782b0a103SAdrian Hunter #include <stdlib.h>
882b0a103SAdrian Hunter #include <string.h>
982b0a103SAdrian Hunter #include <stdbool.h>
1082b0a103SAdrian Hunter 
1182b0a103SAdrian Hunter /*
1282b0a103SAdrian Hunter  * Copy v2 API instead of including current API
1382b0a103SAdrian Hunter  */
1482b0a103SAdrian Hunter #include <linux/perf_event.h>
1582b0a103SAdrian Hunter #include <linux/types.h>
1682b0a103SAdrian Hunter 
1782b0a103SAdrian Hunter /*
1882b0a103SAdrian Hunter  * The following macro can be used to determine if this header defines
1982b0a103SAdrian Hunter  * perf_dlfilter_sample machine_pid and vcpu.
2082b0a103SAdrian Hunter  */
2182b0a103SAdrian Hunter #define PERF_DLFILTER_HAS_MACHINE_PID
2282b0a103SAdrian Hunter 
2382b0a103SAdrian Hunter /* Definitions for perf_dlfilter_sample flags */
2482b0a103SAdrian Hunter enum {
2582b0a103SAdrian Hunter 	PERF_DLFILTER_FLAG_BRANCH	= 1ULL << 0,
2682b0a103SAdrian Hunter 	PERF_DLFILTER_FLAG_CALL		= 1ULL << 1,
2782b0a103SAdrian Hunter 	PERF_DLFILTER_FLAG_RETURN	= 1ULL << 2,
2882b0a103SAdrian Hunter 	PERF_DLFILTER_FLAG_CONDITIONAL	= 1ULL << 3,
2982b0a103SAdrian Hunter 	PERF_DLFILTER_FLAG_SYSCALLRET	= 1ULL << 4,
3082b0a103SAdrian Hunter 	PERF_DLFILTER_FLAG_ASYNC	= 1ULL << 5,
3182b0a103SAdrian Hunter 	PERF_DLFILTER_FLAG_INTERRUPT	= 1ULL << 6,
3282b0a103SAdrian Hunter 	PERF_DLFILTER_FLAG_TX_ABORT	= 1ULL << 7,
3382b0a103SAdrian Hunter 	PERF_DLFILTER_FLAG_TRACE_BEGIN	= 1ULL << 8,
3482b0a103SAdrian Hunter 	PERF_DLFILTER_FLAG_TRACE_END	= 1ULL << 9,
3582b0a103SAdrian Hunter 	PERF_DLFILTER_FLAG_IN_TX	= 1ULL << 10,
3682b0a103SAdrian Hunter 	PERF_DLFILTER_FLAG_VMENTRY	= 1ULL << 11,
3782b0a103SAdrian Hunter 	PERF_DLFILTER_FLAG_VMEXIT	= 1ULL << 12,
3882b0a103SAdrian Hunter };
3982b0a103SAdrian Hunter 
4082b0a103SAdrian Hunter /*
4182b0a103SAdrian Hunter  * perf sample event information (as per perf script and <linux/perf_event.h>)
4282b0a103SAdrian Hunter  */
4382b0a103SAdrian Hunter struct perf_dlfilter_sample {
4482b0a103SAdrian Hunter 	__u32 size; /* Size of this structure (for compatibility checking) */
4582b0a103SAdrian Hunter 	__u16 ins_lat;		/* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */
4682b0a103SAdrian Hunter 	__u16 p_stage_cyc;	/* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */
4782b0a103SAdrian Hunter 	__u64 ip;
4882b0a103SAdrian Hunter 	__s32 pid;
4982b0a103SAdrian Hunter 	__s32 tid;
5082b0a103SAdrian Hunter 	__u64 time;
5182b0a103SAdrian Hunter 	__u64 addr;
5282b0a103SAdrian Hunter 	__u64 id;
5382b0a103SAdrian Hunter 	__u64 stream_id;
5482b0a103SAdrian Hunter 	__u64 period;
5582b0a103SAdrian Hunter 	__u64 weight;		/* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */
5682b0a103SAdrian Hunter 	__u64 transaction;	/* Refer PERF_SAMPLE_TRANSACTION in <linux/perf_event.h> */
5782b0a103SAdrian Hunter 	__u64 insn_cnt;	/* For instructions-per-cycle (IPC) */
5882b0a103SAdrian Hunter 	__u64 cyc_cnt;		/* For instructions-per-cycle (IPC) */
5982b0a103SAdrian Hunter 	__s32 cpu;
6082b0a103SAdrian Hunter 	__u32 flags;		/* Refer PERF_DLFILTER_FLAG_* above */
6182b0a103SAdrian Hunter 	__u64 data_src;		/* Refer PERF_SAMPLE_DATA_SRC in <linux/perf_event.h> */
6282b0a103SAdrian Hunter 	__u64 phys_addr;	/* Refer PERF_SAMPLE_PHYS_ADDR in <linux/perf_event.h> */
6382b0a103SAdrian Hunter 	__u64 data_page_size;	/* Refer PERF_SAMPLE_DATA_PAGE_SIZE in <linux/perf_event.h> */
6482b0a103SAdrian Hunter 	__u64 code_page_size;	/* Refer PERF_SAMPLE_CODE_PAGE_SIZE in <linux/perf_event.h> */
6582b0a103SAdrian Hunter 	__u64 cgroup;		/* Refer PERF_SAMPLE_CGROUP in <linux/perf_event.h> */
6682b0a103SAdrian Hunter 	__u8  cpumode;		/* Refer CPUMODE_MASK etc in <linux/perf_event.h> */
6782b0a103SAdrian Hunter 	__u8  addr_correlates_sym; /* True => resolve_addr() can be called */
6882b0a103SAdrian Hunter 	__u16 misc;		/* Refer perf_event_header in <linux/perf_event.h> */
6982b0a103SAdrian Hunter 	__u32 raw_size;		/* Refer PERF_SAMPLE_RAW in <linux/perf_event.h> */
7082b0a103SAdrian Hunter 	const void *raw_data;	/* Refer PERF_SAMPLE_RAW in <linux/perf_event.h> */
7182b0a103SAdrian Hunter 	__u64 brstack_nr;	/* Number of brstack entries */
7282b0a103SAdrian Hunter 	const struct perf_branch_entry *brstack; /* Refer <linux/perf_event.h> */
7382b0a103SAdrian Hunter 	__u64 raw_callchain_nr;	/* Number of raw_callchain entries */
7482b0a103SAdrian Hunter 	const __u64 *raw_callchain; /* Refer <linux/perf_event.h> */
7582b0a103SAdrian Hunter 	const char *event;
7682b0a103SAdrian Hunter 	__s32 machine_pid;
7782b0a103SAdrian Hunter 	__s32 vcpu;
7882b0a103SAdrian Hunter };
7982b0a103SAdrian Hunter 
8082b0a103SAdrian Hunter /*
8182b0a103SAdrian Hunter  * Address location (as per perf script)
8282b0a103SAdrian Hunter  */
8382b0a103SAdrian Hunter struct perf_dlfilter_al {
8482b0a103SAdrian Hunter 	__u32 size; /* Size of this structure (for compatibility checking) */
8582b0a103SAdrian Hunter 	__u32 symoff;
8682b0a103SAdrian Hunter 	const char *sym;
8782b0a103SAdrian Hunter 	__u64 addr; /* Mapped address (from dso) */
8882b0a103SAdrian Hunter 	__u64 sym_start;
8982b0a103SAdrian Hunter 	__u64 sym_end;
9082b0a103SAdrian Hunter 	const char *dso;
9182b0a103SAdrian Hunter 	__u8  sym_binding; /* STB_LOCAL, STB_GLOBAL or STB_WEAK, refer <elf.h> */
9282b0a103SAdrian Hunter 	__u8  is_64_bit; /* Only valid if dso is not NULL */
9382b0a103SAdrian Hunter 	__u8  is_kernel_ip; /* True if in kernel space */
9482b0a103SAdrian Hunter 	__u32 buildid_size;
9582b0a103SAdrian Hunter 	__u8 *buildid;
9682b0a103SAdrian Hunter 	/* Below members are only populated by resolve_ip() */
9782b0a103SAdrian Hunter 	__u8 filtered; /* True if this sample event will be filtered out */
9882b0a103SAdrian Hunter 	const char *comm;
9982b0a103SAdrian Hunter 	void *priv; /* Private data (v2 API) */
10082b0a103SAdrian Hunter };
10182b0a103SAdrian Hunter 
10282b0a103SAdrian Hunter struct perf_dlfilter_fns {
10382b0a103SAdrian Hunter 	/* Return information about ip */
10482b0a103SAdrian Hunter 	const struct perf_dlfilter_al *(*resolve_ip)(void *ctx);
10582b0a103SAdrian Hunter 	/* Return information about addr (if addr_correlates_sym) */
10682b0a103SAdrian Hunter 	const struct perf_dlfilter_al *(*resolve_addr)(void *ctx);
10782b0a103SAdrian Hunter 	/* Return arguments from --dlarg option */
10882b0a103SAdrian Hunter 	char **(*args)(void *ctx, int *dlargc);
10982b0a103SAdrian Hunter 	/*
11082b0a103SAdrian Hunter 	 * Return information about address (al->size must be set before
11182b0a103SAdrian Hunter 	 * calling). Returns 0 on success, -1 otherwise. Call al_cleanup()
11282b0a103SAdrian Hunter 	 * when 'al' data is no longer needed.
11382b0a103SAdrian Hunter 	 */
11482b0a103SAdrian Hunter 	__s32 (*resolve_address)(void *ctx, __u64 address, struct perf_dlfilter_al *al);
11582b0a103SAdrian Hunter 	/* Return instruction bytes and length */
11682b0a103SAdrian Hunter 	const __u8 *(*insn)(void *ctx, __u32 *length);
11782b0a103SAdrian Hunter 	/* Return source file name and line number */
11882b0a103SAdrian Hunter 	const char *(*srcline)(void *ctx, __u32 *line_number);
11982b0a103SAdrian Hunter 	/* Return perf_event_attr, refer <linux/perf_event.h> */
12082b0a103SAdrian Hunter 	struct perf_event_attr *(*attr)(void *ctx);
12182b0a103SAdrian Hunter 	/* Read object code, return numbers of bytes read */
12282b0a103SAdrian Hunter 	__s32 (*object_code)(void *ctx, __u64 ip, void *buf, __u32 len);
12382b0a103SAdrian Hunter 	/*
12482b0a103SAdrian Hunter 	 * If present (i.e. must check al_cleanup != NULL), call after
12582b0a103SAdrian Hunter 	 * resolve_address() to free any associated resources. (v2 API)
12682b0a103SAdrian Hunter 	 */
12782b0a103SAdrian Hunter 	void (*al_cleanup)(void *ctx, struct perf_dlfilter_al *al);
12882b0a103SAdrian Hunter 	/* Reserved */
12982b0a103SAdrian Hunter 	void *(*reserved[119])(void *);
13082b0a103SAdrian Hunter };
13182b0a103SAdrian Hunter 
13282b0a103SAdrian Hunter struct perf_dlfilter_fns perf_dlfilter_fns;
13382b0a103SAdrian Hunter 
13482b0a103SAdrian Hunter static int verbose;
13582b0a103SAdrian Hunter 
13682b0a103SAdrian Hunter #define pr_debug(fmt, ...) do { \
13782b0a103SAdrian Hunter 		if (verbose > 0) \
13882b0a103SAdrian Hunter 			fprintf(stderr, fmt, ##__VA_ARGS__); \
13982b0a103SAdrian Hunter 	} while (0)
14082b0a103SAdrian Hunter 
test_fail(const char * msg)14182b0a103SAdrian Hunter static int test_fail(const char *msg)
14282b0a103SAdrian Hunter {
14382b0a103SAdrian Hunter 	pr_debug("%s\n", msg);
14482b0a103SAdrian Hunter 	return -1;
14582b0a103SAdrian Hunter }
14682b0a103SAdrian Hunter 
14782b0a103SAdrian Hunter #define CHECK(x) do { \
14882b0a103SAdrian Hunter 		if (!(x)) \
14982b0a103SAdrian Hunter 			return test_fail("Check '" #x "' failed\n"); \
15082b0a103SAdrian Hunter 	} while (0)
15182b0a103SAdrian Hunter 
15282b0a103SAdrian Hunter struct filter_data {
15382b0a103SAdrian Hunter 	__u64 ip;
15482b0a103SAdrian Hunter 	__u64 addr;
15582b0a103SAdrian Hunter 	int do_early;
15682b0a103SAdrian Hunter 	int early_filter_cnt;
15782b0a103SAdrian Hunter 	int filter_cnt;
15882b0a103SAdrian Hunter };
15982b0a103SAdrian Hunter 
16082b0a103SAdrian Hunter static struct filter_data *filt_dat;
16182b0a103SAdrian Hunter 
start(void ** data,void * ctx)16282b0a103SAdrian Hunter int start(void **data, void *ctx)
16382b0a103SAdrian Hunter {
16482b0a103SAdrian Hunter 	int dlargc;
16582b0a103SAdrian Hunter 	char **dlargv;
16682b0a103SAdrian Hunter 	struct filter_data *d;
16782b0a103SAdrian Hunter 	static bool called;
16882b0a103SAdrian Hunter 
16982b0a103SAdrian Hunter 	verbose = 1;
17082b0a103SAdrian Hunter 
17182b0a103SAdrian Hunter 	CHECK(!filt_dat && !called);
17282b0a103SAdrian Hunter 	called = true;
17382b0a103SAdrian Hunter 
17482b0a103SAdrian Hunter 	d = calloc(1, sizeof(*d));
17582b0a103SAdrian Hunter 	if (!d)
17682b0a103SAdrian Hunter 		test_fail("Failed to allocate memory");
17782b0a103SAdrian Hunter 	filt_dat = d;
17882b0a103SAdrian Hunter 	*data = d;
17982b0a103SAdrian Hunter 
18082b0a103SAdrian Hunter 	dlargv = perf_dlfilter_fns.args(ctx, &dlargc);
18182b0a103SAdrian Hunter 
18282b0a103SAdrian Hunter 	CHECK(dlargc == 6);
18382b0a103SAdrian Hunter 	CHECK(!strcmp(dlargv[0], "first"));
18482b0a103SAdrian Hunter 	verbose = strtol(dlargv[1], NULL, 0);
18582b0a103SAdrian Hunter 	d->ip = strtoull(dlargv[2], NULL, 0);
18682b0a103SAdrian Hunter 	d->addr = strtoull(dlargv[3], NULL, 0);
18782b0a103SAdrian Hunter 	d->do_early = strtol(dlargv[4], NULL, 0);
18882b0a103SAdrian Hunter 	CHECK(!strcmp(dlargv[5], "last"));
18982b0a103SAdrian Hunter 
19082b0a103SAdrian Hunter 	pr_debug("%s API\n", __func__);
19182b0a103SAdrian Hunter 
19282b0a103SAdrian Hunter 	return 0;
19382b0a103SAdrian Hunter }
19482b0a103SAdrian Hunter 
19582b0a103SAdrian Hunter #define CHECK_SAMPLE(x) do { \
19682b0a103SAdrian Hunter 		if (sample->x != expected.x) \
19782b0a103SAdrian Hunter 			return test_fail("'" #x "' not expected value\n"); \
19882b0a103SAdrian Hunter 	} while (0)
19982b0a103SAdrian Hunter 
check_sample(struct filter_data * d,const struct perf_dlfilter_sample * sample)20082b0a103SAdrian Hunter static int check_sample(struct filter_data *d, const struct perf_dlfilter_sample *sample)
20182b0a103SAdrian Hunter {
20282b0a103SAdrian Hunter 	struct perf_dlfilter_sample expected = {
20382b0a103SAdrian Hunter 		.ip		= d->ip,
20482b0a103SAdrian Hunter 		.pid		= 12345,
20582b0a103SAdrian Hunter 		.tid		= 12346,
20682b0a103SAdrian Hunter 		.time		= 1234567890,
20782b0a103SAdrian Hunter 		.addr		= d->addr,
20882b0a103SAdrian Hunter 		.id		= 99,
20982b0a103SAdrian Hunter 		.stream_id	= 101,
21082b0a103SAdrian Hunter 		.period		= 543212345,
21182b0a103SAdrian Hunter 		.cpu		= 31,
21282b0a103SAdrian Hunter 		.cpumode	= PERF_RECORD_MISC_USER,
21382b0a103SAdrian Hunter 		.addr_correlates_sym = 1,
21482b0a103SAdrian Hunter 		.misc		= PERF_RECORD_MISC_USER,
21582b0a103SAdrian Hunter 	};
21682b0a103SAdrian Hunter 
21782b0a103SAdrian Hunter 	CHECK(sample->size >= sizeof(struct perf_dlfilter_sample));
21882b0a103SAdrian Hunter 
21982b0a103SAdrian Hunter 	CHECK_SAMPLE(ip);
22082b0a103SAdrian Hunter 	CHECK_SAMPLE(pid);
22182b0a103SAdrian Hunter 	CHECK_SAMPLE(tid);
22282b0a103SAdrian Hunter 	CHECK_SAMPLE(time);
22382b0a103SAdrian Hunter 	CHECK_SAMPLE(addr);
22482b0a103SAdrian Hunter 	CHECK_SAMPLE(id);
22582b0a103SAdrian Hunter 	CHECK_SAMPLE(stream_id);
22682b0a103SAdrian Hunter 	CHECK_SAMPLE(period);
22782b0a103SAdrian Hunter 	CHECK_SAMPLE(cpu);
22882b0a103SAdrian Hunter 	CHECK_SAMPLE(cpumode);
22982b0a103SAdrian Hunter 	CHECK_SAMPLE(addr_correlates_sym);
23082b0a103SAdrian Hunter 	CHECK_SAMPLE(misc);
23182b0a103SAdrian Hunter 
23282b0a103SAdrian Hunter 	CHECK(!sample->raw_data);
23382b0a103SAdrian Hunter 	CHECK_SAMPLE(brstack_nr);
23482b0a103SAdrian Hunter 	CHECK(!sample->brstack);
23582b0a103SAdrian Hunter 	CHECK_SAMPLE(raw_callchain_nr);
23682b0a103SAdrian Hunter 	CHECK(!sample->raw_callchain);
23782b0a103SAdrian Hunter 
23882b0a103SAdrian Hunter #define EVENT_NAME "branches:"
23982b0a103SAdrian Hunter 	CHECK(!strncmp(sample->event, EVENT_NAME, strlen(EVENT_NAME)));
24082b0a103SAdrian Hunter 
24182b0a103SAdrian Hunter 	return 0;
24282b0a103SAdrian Hunter }
24382b0a103SAdrian Hunter 
check_al(void * ctx)24482b0a103SAdrian Hunter static int check_al(void *ctx)
24582b0a103SAdrian Hunter {
24682b0a103SAdrian Hunter 	const struct perf_dlfilter_al *al;
24782b0a103SAdrian Hunter 
24882b0a103SAdrian Hunter 	al = perf_dlfilter_fns.resolve_ip(ctx);
24982b0a103SAdrian Hunter 	if (!al)
25082b0a103SAdrian Hunter 		return test_fail("resolve_ip() failed");
25182b0a103SAdrian Hunter 
25282b0a103SAdrian Hunter 	CHECK(al->sym && !strcmp("foo", al->sym));
25382b0a103SAdrian Hunter 	CHECK(!al->symoff);
25482b0a103SAdrian Hunter 
25582b0a103SAdrian Hunter 	return 0;
25682b0a103SAdrian Hunter }
25782b0a103SAdrian Hunter 
check_addr_al(void * ctx)25882b0a103SAdrian Hunter static int check_addr_al(void *ctx)
25982b0a103SAdrian Hunter {
26082b0a103SAdrian Hunter 	const struct perf_dlfilter_al *addr_al;
26182b0a103SAdrian Hunter 
26282b0a103SAdrian Hunter 	addr_al = perf_dlfilter_fns.resolve_addr(ctx);
26382b0a103SAdrian Hunter 	if (!addr_al)
26482b0a103SAdrian Hunter 		return test_fail("resolve_addr() failed");
26582b0a103SAdrian Hunter 
26682b0a103SAdrian Hunter 	CHECK(addr_al->sym && !strcmp("bar", addr_al->sym));
26782b0a103SAdrian Hunter 	CHECK(!addr_al->symoff);
26882b0a103SAdrian Hunter 
26982b0a103SAdrian Hunter 	return 0;
27082b0a103SAdrian Hunter }
27182b0a103SAdrian Hunter 
check_address_al(void * ctx,const struct perf_dlfilter_sample * sample)27282b0a103SAdrian Hunter static int check_address_al(void *ctx, const struct perf_dlfilter_sample *sample)
27382b0a103SAdrian Hunter {
27482b0a103SAdrian Hunter 	struct perf_dlfilter_al address_al;
27582b0a103SAdrian Hunter 	const struct perf_dlfilter_al *al;
27682b0a103SAdrian Hunter 
27782b0a103SAdrian Hunter 	al = perf_dlfilter_fns.resolve_ip(ctx);
27882b0a103SAdrian Hunter 	if (!al)
27982b0a103SAdrian Hunter 		return test_fail("resolve_ip() failed");
28082b0a103SAdrian Hunter 
28182b0a103SAdrian Hunter 	address_al.size = sizeof(address_al);
28282b0a103SAdrian Hunter 	if (perf_dlfilter_fns.resolve_address(ctx, sample->ip, &address_al))
28382b0a103SAdrian Hunter 		return test_fail("resolve_address() failed");
28482b0a103SAdrian Hunter 
28582b0a103SAdrian Hunter 	CHECK(address_al.sym && al->sym);
28682b0a103SAdrian Hunter 	CHECK(!strcmp(address_al.sym, al->sym));
28782b0a103SAdrian Hunter 	CHECK(address_al.addr == al->addr);
28882b0a103SAdrian Hunter 	CHECK(address_al.sym_start == al->sym_start);
28982b0a103SAdrian Hunter 	CHECK(address_al.sym_end == al->sym_end);
29082b0a103SAdrian Hunter 	CHECK(address_al.dso && al->dso);
29182b0a103SAdrian Hunter 	CHECK(!strcmp(address_al.dso, al->dso));
29282b0a103SAdrian Hunter 
29382b0a103SAdrian Hunter 	/* al_cleanup() is v2 API so may not be present */
29482b0a103SAdrian Hunter 	if (perf_dlfilter_fns.al_cleanup)
29582b0a103SAdrian Hunter 		perf_dlfilter_fns.al_cleanup(ctx, &address_al);
29682b0a103SAdrian Hunter 
29782b0a103SAdrian Hunter 	return 0;
29882b0a103SAdrian Hunter }
29982b0a103SAdrian Hunter 
check_attr(void * ctx)30082b0a103SAdrian Hunter static int check_attr(void *ctx)
30182b0a103SAdrian Hunter {
30282b0a103SAdrian Hunter 	struct perf_event_attr *attr = perf_dlfilter_fns.attr(ctx);
30382b0a103SAdrian Hunter 
30482b0a103SAdrian Hunter 	CHECK(attr);
30582b0a103SAdrian Hunter 	CHECK(attr->type == PERF_TYPE_HARDWARE);
30682b0a103SAdrian Hunter 	CHECK(attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
30782b0a103SAdrian Hunter 
30882b0a103SAdrian Hunter 	return 0;
30982b0a103SAdrian Hunter }
31082b0a103SAdrian Hunter 
check_object_code(void * ctx,const struct perf_dlfilter_sample * sample)311*f38f5473SAdrian Hunter static int check_object_code(void *ctx, const struct perf_dlfilter_sample *sample)
312*f38f5473SAdrian Hunter {
313*f38f5473SAdrian Hunter 	__u8 buf[15];
314*f38f5473SAdrian Hunter 
315*f38f5473SAdrian Hunter 	CHECK(perf_dlfilter_fns.object_code(ctx, sample->ip, buf, sizeof(buf)) > 0);
316*f38f5473SAdrian Hunter 
317*f38f5473SAdrian Hunter 	return 0;
318*f38f5473SAdrian Hunter }
319*f38f5473SAdrian Hunter 
do_checks(void * data,const struct perf_dlfilter_sample * sample,void * ctx,bool early)32082b0a103SAdrian Hunter static int do_checks(void *data, const struct perf_dlfilter_sample *sample, void *ctx, bool early)
32182b0a103SAdrian Hunter {
32282b0a103SAdrian Hunter 	struct filter_data *d = data;
32382b0a103SAdrian Hunter 
32482b0a103SAdrian Hunter 	CHECK(data && filt_dat == data);
32582b0a103SAdrian Hunter 
32682b0a103SAdrian Hunter 	if (early) {
32782b0a103SAdrian Hunter 		CHECK(!d->early_filter_cnt);
32882b0a103SAdrian Hunter 		d->early_filter_cnt += 1;
32982b0a103SAdrian Hunter 	} else {
33082b0a103SAdrian Hunter 		CHECK(!d->filter_cnt);
33182b0a103SAdrian Hunter 		CHECK(d->early_filter_cnt);
33282b0a103SAdrian Hunter 		CHECK(d->do_early != 2);
33382b0a103SAdrian Hunter 		d->filter_cnt += 1;
33482b0a103SAdrian Hunter 	}
33582b0a103SAdrian Hunter 
33682b0a103SAdrian Hunter 	if (check_sample(data, sample))
33782b0a103SAdrian Hunter 		return -1;
33882b0a103SAdrian Hunter 
33982b0a103SAdrian Hunter 	if (check_attr(ctx))
34082b0a103SAdrian Hunter 		return -1;
34182b0a103SAdrian Hunter 
34282b0a103SAdrian Hunter 	if (early && !d->do_early)
34382b0a103SAdrian Hunter 		return 0;
34482b0a103SAdrian Hunter 
345*f38f5473SAdrian Hunter 	if (check_al(ctx) || check_addr_al(ctx) || check_address_al(ctx, sample) ||
346*f38f5473SAdrian Hunter 	    check_object_code(ctx, sample))
34782b0a103SAdrian Hunter 		return -1;
34882b0a103SAdrian Hunter 
34982b0a103SAdrian Hunter 	if (early)
35082b0a103SAdrian Hunter 		return d->do_early == 2;
35182b0a103SAdrian Hunter 
35282b0a103SAdrian Hunter 	return 1;
35382b0a103SAdrian Hunter }
35482b0a103SAdrian Hunter 
filter_event_early(void * data,const struct perf_dlfilter_sample * sample,void * ctx)35582b0a103SAdrian Hunter int filter_event_early(void *data, const struct perf_dlfilter_sample *sample, void *ctx)
35682b0a103SAdrian Hunter {
35782b0a103SAdrian Hunter 	pr_debug("%s API\n", __func__);
35882b0a103SAdrian Hunter 
35982b0a103SAdrian Hunter 	return do_checks(data, sample, ctx, true);
36082b0a103SAdrian Hunter }
36182b0a103SAdrian Hunter 
filter_event(void * data,const struct perf_dlfilter_sample * sample,void * ctx)36282b0a103SAdrian Hunter int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ctx)
36382b0a103SAdrian Hunter {
36482b0a103SAdrian Hunter 	pr_debug("%s API\n", __func__);
36582b0a103SAdrian Hunter 
36682b0a103SAdrian Hunter 	return do_checks(data, sample, ctx, false);
36782b0a103SAdrian Hunter }
36882b0a103SAdrian Hunter 
stop(void * data,void * ctx)36982b0a103SAdrian Hunter int stop(void *data, void *ctx)
37082b0a103SAdrian Hunter {
37182b0a103SAdrian Hunter 	static bool called;
37282b0a103SAdrian Hunter 
37382b0a103SAdrian Hunter 	pr_debug("%s API\n", __func__);
37482b0a103SAdrian Hunter 
37582b0a103SAdrian Hunter 	CHECK(data && filt_dat == data && !called);
37682b0a103SAdrian Hunter 	called = true;
37782b0a103SAdrian Hunter 
37882b0a103SAdrian Hunter 	free(data);
37982b0a103SAdrian Hunter 	filt_dat = NULL;
38082b0a103SAdrian Hunter 	return 0;
38182b0a103SAdrian Hunter }
38282b0a103SAdrian Hunter 
filter_description(const char ** long_description)38382b0a103SAdrian Hunter const char *filter_description(const char **long_description)
38482b0a103SAdrian Hunter {
38582b0a103SAdrian Hunter 	*long_description = "Filter used by the 'dlfilter C API' perf test";
38682b0a103SAdrian Hunter 	return "dlfilter to test v2 C API";
38782b0a103SAdrian Hunter }
388