19f9c9a8dSAdrian Hunter // SPDX-License-Identifier: GPL-2.0
29f9c9a8dSAdrian Hunter /*
39f9c9a8dSAdrian Hunter  * dlfilter-test-api-v0.c: test original (v0) API for perf --dlfilter shared object
49f9c9a8dSAdrian Hunter  * Copyright (c) 2021, Intel Corporation.
59f9c9a8dSAdrian Hunter  */
69f9c9a8dSAdrian Hunter #include <stdio.h>
79f9c9a8dSAdrian Hunter #include <stdlib.h>
89f9c9a8dSAdrian Hunter #include <string.h>
99f9c9a8dSAdrian Hunter #include <stdbool.h>
109f9c9a8dSAdrian Hunter 
119f9c9a8dSAdrian Hunter /*
129f9c9a8dSAdrian Hunter  * Copy original (v0) API instead of including current API
139f9c9a8dSAdrian Hunter  */
149f9c9a8dSAdrian Hunter #include <linux/perf_event.h>
159f9c9a8dSAdrian Hunter #include <linux/types.h>
169f9c9a8dSAdrian Hunter 
179f9c9a8dSAdrian Hunter /* Definitions for perf_dlfilter_sample flags */
189f9c9a8dSAdrian Hunter enum {
199f9c9a8dSAdrian Hunter 	PERF_DLFILTER_FLAG_BRANCH	= 1ULL << 0,
209f9c9a8dSAdrian Hunter 	PERF_DLFILTER_FLAG_CALL		= 1ULL << 1,
219f9c9a8dSAdrian Hunter 	PERF_DLFILTER_FLAG_RETURN	= 1ULL << 2,
229f9c9a8dSAdrian Hunter 	PERF_DLFILTER_FLAG_CONDITIONAL	= 1ULL << 3,
239f9c9a8dSAdrian Hunter 	PERF_DLFILTER_FLAG_SYSCALLRET	= 1ULL << 4,
249f9c9a8dSAdrian Hunter 	PERF_DLFILTER_FLAG_ASYNC	= 1ULL << 5,
259f9c9a8dSAdrian Hunter 	PERF_DLFILTER_FLAG_INTERRUPT	= 1ULL << 6,
269f9c9a8dSAdrian Hunter 	PERF_DLFILTER_FLAG_TX_ABORT	= 1ULL << 7,
279f9c9a8dSAdrian Hunter 	PERF_DLFILTER_FLAG_TRACE_BEGIN	= 1ULL << 8,
289f9c9a8dSAdrian Hunter 	PERF_DLFILTER_FLAG_TRACE_END	= 1ULL << 9,
299f9c9a8dSAdrian Hunter 	PERF_DLFILTER_FLAG_IN_TX	= 1ULL << 10,
309f9c9a8dSAdrian Hunter 	PERF_DLFILTER_FLAG_VMENTRY	= 1ULL << 11,
319f9c9a8dSAdrian Hunter 	PERF_DLFILTER_FLAG_VMEXIT	= 1ULL << 12,
329f9c9a8dSAdrian Hunter };
339f9c9a8dSAdrian Hunter 
349f9c9a8dSAdrian Hunter /*
359f9c9a8dSAdrian Hunter  * perf sample event information (as per perf script and <linux/perf_event.h>)
369f9c9a8dSAdrian Hunter  */
379f9c9a8dSAdrian Hunter struct perf_dlfilter_sample {
389f9c9a8dSAdrian Hunter 	__u32 size; /* Size of this structure (for compatibility checking) */
399f9c9a8dSAdrian Hunter 	__u16 ins_lat;		/* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */
409f9c9a8dSAdrian Hunter 	__u16 p_stage_cyc;	/* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */
419f9c9a8dSAdrian Hunter 	__u64 ip;
429f9c9a8dSAdrian Hunter 	__s32 pid;
439f9c9a8dSAdrian Hunter 	__s32 tid;
449f9c9a8dSAdrian Hunter 	__u64 time;
459f9c9a8dSAdrian Hunter 	__u64 addr;
469f9c9a8dSAdrian Hunter 	__u64 id;
479f9c9a8dSAdrian Hunter 	__u64 stream_id;
489f9c9a8dSAdrian Hunter 	__u64 period;
499f9c9a8dSAdrian Hunter 	__u64 weight;		/* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */
509f9c9a8dSAdrian Hunter 	__u64 transaction;	/* Refer PERF_SAMPLE_TRANSACTION in <linux/perf_event.h> */
519f9c9a8dSAdrian Hunter 	__u64 insn_cnt;	/* For instructions-per-cycle (IPC) */
529f9c9a8dSAdrian Hunter 	__u64 cyc_cnt;		/* For instructions-per-cycle (IPC) */
539f9c9a8dSAdrian Hunter 	__s32 cpu;
549f9c9a8dSAdrian Hunter 	__u32 flags;		/* Refer PERF_DLFILTER_FLAG_* above */
559f9c9a8dSAdrian Hunter 	__u64 data_src;		/* Refer PERF_SAMPLE_DATA_SRC in <linux/perf_event.h> */
569f9c9a8dSAdrian Hunter 	__u64 phys_addr;	/* Refer PERF_SAMPLE_PHYS_ADDR in <linux/perf_event.h> */
579f9c9a8dSAdrian Hunter 	__u64 data_page_size;	/* Refer PERF_SAMPLE_DATA_PAGE_SIZE in <linux/perf_event.h> */
589f9c9a8dSAdrian Hunter 	__u64 code_page_size;	/* Refer PERF_SAMPLE_CODE_PAGE_SIZE in <linux/perf_event.h> */
599f9c9a8dSAdrian Hunter 	__u64 cgroup;		/* Refer PERF_SAMPLE_CGROUP in <linux/perf_event.h> */
609f9c9a8dSAdrian Hunter 	__u8  cpumode;		/* Refer CPUMODE_MASK etc in <linux/perf_event.h> */
619f9c9a8dSAdrian Hunter 	__u8  addr_correlates_sym; /* True => resolve_addr() can be called */
629f9c9a8dSAdrian Hunter 	__u16 misc;		/* Refer perf_event_header in <linux/perf_event.h> */
639f9c9a8dSAdrian Hunter 	__u32 raw_size;		/* Refer PERF_SAMPLE_RAW in <linux/perf_event.h> */
649f9c9a8dSAdrian Hunter 	const void *raw_data;	/* Refer PERF_SAMPLE_RAW in <linux/perf_event.h> */
659f9c9a8dSAdrian Hunter 	__u64 brstack_nr;	/* Number of brstack entries */
669f9c9a8dSAdrian Hunter 	const struct perf_branch_entry *brstack; /* Refer <linux/perf_event.h> */
679f9c9a8dSAdrian Hunter 	__u64 raw_callchain_nr;	/* Number of raw_callchain entries */
689f9c9a8dSAdrian Hunter 	const __u64 *raw_callchain; /* Refer <linux/perf_event.h> */
699f9c9a8dSAdrian Hunter 	const char *event;
709f9c9a8dSAdrian Hunter };
719f9c9a8dSAdrian Hunter 
729f9c9a8dSAdrian Hunter /*
739f9c9a8dSAdrian Hunter  * Address location (as per perf script)
749f9c9a8dSAdrian Hunter  */
759f9c9a8dSAdrian Hunter struct perf_dlfilter_al {
769f9c9a8dSAdrian Hunter 	__u32 size; /* Size of this structure (for compatibility checking) */
779f9c9a8dSAdrian Hunter 	__u32 symoff;
789f9c9a8dSAdrian Hunter 	const char *sym;
799f9c9a8dSAdrian Hunter 	__u64 addr; /* Mapped address (from dso) */
809f9c9a8dSAdrian Hunter 	__u64 sym_start;
819f9c9a8dSAdrian Hunter 	__u64 sym_end;
829f9c9a8dSAdrian Hunter 	const char *dso;
839f9c9a8dSAdrian Hunter 	__u8  sym_binding; /* STB_LOCAL, STB_GLOBAL or STB_WEAK, refer <elf.h> */
849f9c9a8dSAdrian Hunter 	__u8  is_64_bit; /* Only valid if dso is not NULL */
859f9c9a8dSAdrian Hunter 	__u8  is_kernel_ip; /* True if in kernel space */
869f9c9a8dSAdrian Hunter 	__u32 buildid_size;
879f9c9a8dSAdrian Hunter 	__u8 *buildid;
889f9c9a8dSAdrian Hunter 	/* Below members are only populated by resolve_ip() */
899f9c9a8dSAdrian Hunter 	__u8 filtered; /* True if this sample event will be filtered out */
909f9c9a8dSAdrian Hunter 	const char *comm;
919f9c9a8dSAdrian Hunter };
929f9c9a8dSAdrian Hunter 
939f9c9a8dSAdrian Hunter struct perf_dlfilter_fns {
949f9c9a8dSAdrian Hunter 	/* Return information about ip */
959f9c9a8dSAdrian Hunter 	const struct perf_dlfilter_al *(*resolve_ip)(void *ctx);
969f9c9a8dSAdrian Hunter 	/* Return information about addr (if addr_correlates_sym) */
979f9c9a8dSAdrian Hunter 	const struct perf_dlfilter_al *(*resolve_addr)(void *ctx);
989f9c9a8dSAdrian Hunter 	/* Return arguments from --dlarg option */
999f9c9a8dSAdrian Hunter 	char **(*args)(void *ctx, int *dlargc);
1009f9c9a8dSAdrian Hunter 	/*
1019f9c9a8dSAdrian Hunter 	 * Return information about address (al->size must be set before
1029f9c9a8dSAdrian Hunter 	 * calling). Returns 0 on success, -1 otherwise.
1039f9c9a8dSAdrian Hunter 	 */
1049f9c9a8dSAdrian Hunter 	__s32 (*resolve_address)(void *ctx, __u64 address, struct perf_dlfilter_al *al);
1059f9c9a8dSAdrian Hunter 	/* Return instruction bytes and length */
1069f9c9a8dSAdrian Hunter 	const __u8 *(*insn)(void *ctx, __u32 *length);
1079f9c9a8dSAdrian Hunter 	/* Return source file name and line number */
1089f9c9a8dSAdrian Hunter 	const char *(*srcline)(void *ctx, __u32 *line_number);
1099f9c9a8dSAdrian Hunter 	/* Return perf_event_attr, refer <linux/perf_event.h> */
1109f9c9a8dSAdrian Hunter 	struct perf_event_attr *(*attr)(void *ctx);
1119f9c9a8dSAdrian Hunter 	/* Read object code, return numbers of bytes read */
1129f9c9a8dSAdrian Hunter 	__s32 (*object_code)(void *ctx, __u64 ip, void *buf, __u32 len);
1139f9c9a8dSAdrian Hunter 	/* Reserved */
1149f9c9a8dSAdrian Hunter 	void *(*reserved[120])(void *);
1159f9c9a8dSAdrian Hunter };
1169f9c9a8dSAdrian Hunter 
1179f9c9a8dSAdrian Hunter struct perf_dlfilter_fns perf_dlfilter_fns;
1189f9c9a8dSAdrian Hunter 
1199f9c9a8dSAdrian Hunter static int verbose;
1209f9c9a8dSAdrian Hunter 
1219f9c9a8dSAdrian Hunter #define pr_debug(fmt, ...) do { \
1227c0a6144SYang Jihong 		if (verbose > 0) \
1239f9c9a8dSAdrian Hunter 			fprintf(stderr, fmt, ##__VA_ARGS__); \
1249f9c9a8dSAdrian Hunter 	} while (0)
1259f9c9a8dSAdrian Hunter 
test_fail(const char * msg)1269f9c9a8dSAdrian Hunter static int test_fail(const char *msg)
1279f9c9a8dSAdrian Hunter {
1289f9c9a8dSAdrian Hunter 	pr_debug("%s\n", msg);
1299f9c9a8dSAdrian Hunter 	return -1;
1309f9c9a8dSAdrian Hunter }
1319f9c9a8dSAdrian Hunter 
1329f9c9a8dSAdrian Hunter #define CHECK(x) do { \
1339f9c9a8dSAdrian Hunter 		if (!(x)) \
1349f9c9a8dSAdrian Hunter 			return test_fail("Check '" #x "' failed\n"); \
1359f9c9a8dSAdrian Hunter 	} while (0)
1369f9c9a8dSAdrian Hunter 
1379f9c9a8dSAdrian Hunter struct filter_data {
1389f9c9a8dSAdrian Hunter 	__u64 ip;
1399f9c9a8dSAdrian Hunter 	__u64 addr;
1409f9c9a8dSAdrian Hunter 	int do_early;
1419f9c9a8dSAdrian Hunter 	int early_filter_cnt;
1429f9c9a8dSAdrian Hunter 	int filter_cnt;
1439f9c9a8dSAdrian Hunter };
1449f9c9a8dSAdrian Hunter 
1459f9c9a8dSAdrian Hunter static struct filter_data *filt_dat;
1469f9c9a8dSAdrian Hunter 
start(void ** data,void * ctx)1479f9c9a8dSAdrian Hunter int start(void **data, void *ctx)
1489f9c9a8dSAdrian Hunter {
1499f9c9a8dSAdrian Hunter 	int dlargc;
1509f9c9a8dSAdrian Hunter 	char **dlargv;
1519f9c9a8dSAdrian Hunter 	struct filter_data *d;
1529f9c9a8dSAdrian Hunter 	static bool called;
1539f9c9a8dSAdrian Hunter 
1549f9c9a8dSAdrian Hunter 	verbose = 1;
1559f9c9a8dSAdrian Hunter 
1569f9c9a8dSAdrian Hunter 	CHECK(!filt_dat && !called);
1579f9c9a8dSAdrian Hunter 	called = true;
1589f9c9a8dSAdrian Hunter 
1599f9c9a8dSAdrian Hunter 	d = calloc(1, sizeof(*d));
1609f9c9a8dSAdrian Hunter 	if (!d)
1619f9c9a8dSAdrian Hunter 		test_fail("Failed to allocate memory");
1629f9c9a8dSAdrian Hunter 	filt_dat = d;
1639f9c9a8dSAdrian Hunter 	*data = d;
1649f9c9a8dSAdrian Hunter 
1659f9c9a8dSAdrian Hunter 	dlargv = perf_dlfilter_fns.args(ctx, &dlargc);
1669f9c9a8dSAdrian Hunter 
1679f9c9a8dSAdrian Hunter 	CHECK(dlargc == 6);
1689f9c9a8dSAdrian Hunter 	CHECK(!strcmp(dlargv[0], "first"));
1699f9c9a8dSAdrian Hunter 	verbose = strtol(dlargv[1], NULL, 0);
1709f9c9a8dSAdrian Hunter 	d->ip = strtoull(dlargv[2], NULL, 0);
1719f9c9a8dSAdrian Hunter 	d->addr = strtoull(dlargv[3], NULL, 0);
1729f9c9a8dSAdrian Hunter 	d->do_early = strtol(dlargv[4], NULL, 0);
1739f9c9a8dSAdrian Hunter 	CHECK(!strcmp(dlargv[5], "last"));
1749f9c9a8dSAdrian Hunter 
1759f9c9a8dSAdrian Hunter 	pr_debug("%s API\n", __func__);
1769f9c9a8dSAdrian Hunter 
1779f9c9a8dSAdrian Hunter 	return 0;
1789f9c9a8dSAdrian Hunter }
1799f9c9a8dSAdrian Hunter 
1809f9c9a8dSAdrian Hunter #define CHECK_SAMPLE(x) do { \
1819f9c9a8dSAdrian Hunter 		if (sample->x != expected.x) \
1829f9c9a8dSAdrian Hunter 			return test_fail("'" #x "' not expected value\n"); \
1839f9c9a8dSAdrian Hunter 	} while (0)
1849f9c9a8dSAdrian Hunter 
check_sample(struct filter_data * d,const struct perf_dlfilter_sample * sample)1859f9c9a8dSAdrian Hunter static int check_sample(struct filter_data *d, const struct perf_dlfilter_sample *sample)
1869f9c9a8dSAdrian Hunter {
1879f9c9a8dSAdrian Hunter 	struct perf_dlfilter_sample expected = {
1889f9c9a8dSAdrian Hunter 		.ip		= d->ip,
1899f9c9a8dSAdrian Hunter 		.pid		= 12345,
1909f9c9a8dSAdrian Hunter 		.tid		= 12346,
1919f9c9a8dSAdrian Hunter 		.time		= 1234567890,
1929f9c9a8dSAdrian Hunter 		.addr		= d->addr,
1939f9c9a8dSAdrian Hunter 		.id		= 99,
1949f9c9a8dSAdrian Hunter 		.stream_id	= 101,
1959f9c9a8dSAdrian Hunter 		.period		= 543212345,
1969f9c9a8dSAdrian Hunter 		.cpu		= 31,
1979f9c9a8dSAdrian Hunter 		.cpumode	= PERF_RECORD_MISC_USER,
1989f9c9a8dSAdrian Hunter 		.addr_correlates_sym = 1,
1999f9c9a8dSAdrian Hunter 		.misc		= PERF_RECORD_MISC_USER,
2009f9c9a8dSAdrian Hunter 	};
2019f9c9a8dSAdrian Hunter 
2029f9c9a8dSAdrian Hunter 	CHECK(sample->size >= sizeof(struct perf_dlfilter_sample));
2039f9c9a8dSAdrian Hunter 
2049f9c9a8dSAdrian Hunter 	CHECK_SAMPLE(ip);
2059f9c9a8dSAdrian Hunter 	CHECK_SAMPLE(pid);
2069f9c9a8dSAdrian Hunter 	CHECK_SAMPLE(tid);
2079f9c9a8dSAdrian Hunter 	CHECK_SAMPLE(time);
2089f9c9a8dSAdrian Hunter 	CHECK_SAMPLE(addr);
2099f9c9a8dSAdrian Hunter 	CHECK_SAMPLE(id);
2109f9c9a8dSAdrian Hunter 	CHECK_SAMPLE(stream_id);
2119f9c9a8dSAdrian Hunter 	CHECK_SAMPLE(period);
2129f9c9a8dSAdrian Hunter 	CHECK_SAMPLE(cpu);
2139f9c9a8dSAdrian Hunter 	CHECK_SAMPLE(cpumode);
2149f9c9a8dSAdrian Hunter 	CHECK_SAMPLE(addr_correlates_sym);
2159f9c9a8dSAdrian Hunter 	CHECK_SAMPLE(misc);
2169f9c9a8dSAdrian Hunter 
2179f9c9a8dSAdrian Hunter 	CHECK(!sample->raw_data);
2189f9c9a8dSAdrian Hunter 	CHECK_SAMPLE(brstack_nr);
2199f9c9a8dSAdrian Hunter 	CHECK(!sample->brstack);
2209f9c9a8dSAdrian Hunter 	CHECK_SAMPLE(raw_callchain_nr);
2219f9c9a8dSAdrian Hunter 	CHECK(!sample->raw_callchain);
2229f9c9a8dSAdrian Hunter 
2239f9c9a8dSAdrian Hunter #define EVENT_NAME "branches:"
2249f9c9a8dSAdrian Hunter 	CHECK(!strncmp(sample->event, EVENT_NAME, strlen(EVENT_NAME)));
2259f9c9a8dSAdrian Hunter 
2269f9c9a8dSAdrian Hunter 	return 0;
2279f9c9a8dSAdrian Hunter }
2289f9c9a8dSAdrian Hunter 
check_al(void * ctx)2299f9c9a8dSAdrian Hunter static int check_al(void *ctx)
2309f9c9a8dSAdrian Hunter {
2319f9c9a8dSAdrian Hunter 	const struct perf_dlfilter_al *al;
2329f9c9a8dSAdrian Hunter 
2339f9c9a8dSAdrian Hunter 	al = perf_dlfilter_fns.resolve_ip(ctx);
2349f9c9a8dSAdrian Hunter 	if (!al)
2359f9c9a8dSAdrian Hunter 		return test_fail("resolve_ip() failed");
2369f9c9a8dSAdrian Hunter 
2379f9c9a8dSAdrian Hunter 	CHECK(al->sym && !strcmp("foo", al->sym));
2389f9c9a8dSAdrian Hunter 	CHECK(!al->symoff);
2399f9c9a8dSAdrian Hunter 
2409f9c9a8dSAdrian Hunter 	return 0;
2419f9c9a8dSAdrian Hunter }
2429f9c9a8dSAdrian Hunter 
check_addr_al(void * ctx)2439f9c9a8dSAdrian Hunter static int check_addr_al(void *ctx)
2449f9c9a8dSAdrian Hunter {
2459f9c9a8dSAdrian Hunter 	const struct perf_dlfilter_al *addr_al;
2469f9c9a8dSAdrian Hunter 
2479f9c9a8dSAdrian Hunter 	addr_al = perf_dlfilter_fns.resolve_addr(ctx);
2489f9c9a8dSAdrian Hunter 	if (!addr_al)
2499f9c9a8dSAdrian Hunter 		return test_fail("resolve_addr() failed");
2509f9c9a8dSAdrian Hunter 
2519f9c9a8dSAdrian Hunter 	CHECK(addr_al->sym && !strcmp("bar", addr_al->sym));
2529f9c9a8dSAdrian Hunter 	CHECK(!addr_al->symoff);
2539f9c9a8dSAdrian Hunter 
2549f9c9a8dSAdrian Hunter 	return 0;
2559f9c9a8dSAdrian Hunter }
2569f9c9a8dSAdrian Hunter 
check_address_al(void * ctx,const struct perf_dlfilter_sample * sample)257f178a76bSAdrian Hunter static int check_address_al(void *ctx, const struct perf_dlfilter_sample *sample)
258f178a76bSAdrian Hunter {
259f178a76bSAdrian Hunter 	struct perf_dlfilter_al address_al;
260f178a76bSAdrian Hunter 	const struct perf_dlfilter_al *al;
261f178a76bSAdrian Hunter 
262f178a76bSAdrian Hunter 	al = perf_dlfilter_fns.resolve_ip(ctx);
263f178a76bSAdrian Hunter 	if (!al)
264f178a76bSAdrian Hunter 		return test_fail("resolve_ip() failed");
265f178a76bSAdrian Hunter 
266f178a76bSAdrian Hunter 	address_al.size = sizeof(address_al);
267f178a76bSAdrian Hunter 	if (perf_dlfilter_fns.resolve_address(ctx, sample->ip, &address_al))
268f178a76bSAdrian Hunter 		return test_fail("resolve_address() failed");
269f178a76bSAdrian Hunter 
270f178a76bSAdrian Hunter 	CHECK(address_al.sym && al->sym);
271f178a76bSAdrian Hunter 	CHECK(!strcmp(address_al.sym, al->sym));
272f178a76bSAdrian Hunter 	CHECK(address_al.addr == al->addr);
273f178a76bSAdrian Hunter 	CHECK(address_al.sym_start == al->sym_start);
274f178a76bSAdrian Hunter 	CHECK(address_al.sym_end == al->sym_end);
275f178a76bSAdrian Hunter 	CHECK(address_al.dso && al->dso);
276f178a76bSAdrian Hunter 	CHECK(!strcmp(address_al.dso, al->dso));
277f178a76bSAdrian Hunter 
278f178a76bSAdrian Hunter 	return 0;
279f178a76bSAdrian Hunter }
280f178a76bSAdrian Hunter 
check_attr(void * ctx)2819f9c9a8dSAdrian Hunter static int check_attr(void *ctx)
2829f9c9a8dSAdrian Hunter {
2839f9c9a8dSAdrian Hunter 	struct perf_event_attr *attr = perf_dlfilter_fns.attr(ctx);
2849f9c9a8dSAdrian Hunter 
2859f9c9a8dSAdrian Hunter 	CHECK(attr);
2869f9c9a8dSAdrian Hunter 	CHECK(attr->type == PERF_TYPE_HARDWARE);
2879f9c9a8dSAdrian Hunter 	CHECK(attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
2889f9c9a8dSAdrian Hunter 
2899f9c9a8dSAdrian Hunter 	return 0;
2909f9c9a8dSAdrian Hunter }
2919f9c9a8dSAdrian Hunter 
check_object_code(void * ctx,const struct perf_dlfilter_sample * sample)292*f38f5473SAdrian Hunter static int check_object_code(void *ctx, const struct perf_dlfilter_sample *sample)
293*f38f5473SAdrian Hunter {
294*f38f5473SAdrian Hunter 	__u8 buf[15];
295*f38f5473SAdrian Hunter 
296*f38f5473SAdrian Hunter 	CHECK(perf_dlfilter_fns.object_code(ctx, sample->ip, buf, sizeof(buf)) > 0);
297*f38f5473SAdrian Hunter 
298*f38f5473SAdrian Hunter 	return 0;
299*f38f5473SAdrian Hunter }
300*f38f5473SAdrian Hunter 
do_checks(void * data,const struct perf_dlfilter_sample * sample,void * ctx,bool early)3019f9c9a8dSAdrian Hunter static int do_checks(void *data, const struct perf_dlfilter_sample *sample, void *ctx, bool early)
3029f9c9a8dSAdrian Hunter {
3039f9c9a8dSAdrian Hunter 	struct filter_data *d = data;
3049f9c9a8dSAdrian Hunter 
3059f9c9a8dSAdrian Hunter 	CHECK(data && filt_dat == data);
3069f9c9a8dSAdrian Hunter 
3079f9c9a8dSAdrian Hunter 	if (early) {
3089f9c9a8dSAdrian Hunter 		CHECK(!d->early_filter_cnt);
3099f9c9a8dSAdrian Hunter 		d->early_filter_cnt += 1;
3109f9c9a8dSAdrian Hunter 	} else {
3119f9c9a8dSAdrian Hunter 		CHECK(!d->filter_cnt);
3129f9c9a8dSAdrian Hunter 		CHECK(d->early_filter_cnt);
3139f9c9a8dSAdrian Hunter 		CHECK(d->do_early != 2);
3149f9c9a8dSAdrian Hunter 		d->filter_cnt += 1;
3159f9c9a8dSAdrian Hunter 	}
3169f9c9a8dSAdrian Hunter 
3179f9c9a8dSAdrian Hunter 	if (check_sample(data, sample))
3189f9c9a8dSAdrian Hunter 		return -1;
3199f9c9a8dSAdrian Hunter 
3209f9c9a8dSAdrian Hunter 	if (check_attr(ctx))
3219f9c9a8dSAdrian Hunter 		return -1;
3229f9c9a8dSAdrian Hunter 
3239f9c9a8dSAdrian Hunter 	if (early && !d->do_early)
3249f9c9a8dSAdrian Hunter 		return 0;
3259f9c9a8dSAdrian Hunter 
326*f38f5473SAdrian Hunter 	if (check_al(ctx) || check_addr_al(ctx) || check_address_al(ctx, sample) ||
327*f38f5473SAdrian Hunter 	    check_object_code(ctx, sample))
3289f9c9a8dSAdrian Hunter 		return -1;
3299f9c9a8dSAdrian Hunter 
3309f9c9a8dSAdrian Hunter 	if (early)
3319f9c9a8dSAdrian Hunter 		return d->do_early == 2;
3329f9c9a8dSAdrian Hunter 
3339f9c9a8dSAdrian Hunter 	return 1;
3349f9c9a8dSAdrian Hunter }
3359f9c9a8dSAdrian Hunter 
filter_event_early(void * data,const struct perf_dlfilter_sample * sample,void * ctx)3369f9c9a8dSAdrian Hunter int filter_event_early(void *data, const struct perf_dlfilter_sample *sample, void *ctx)
3379f9c9a8dSAdrian Hunter {
3389f9c9a8dSAdrian Hunter 	pr_debug("%s API\n", __func__);
3399f9c9a8dSAdrian Hunter 
3409f9c9a8dSAdrian Hunter 	return do_checks(data, sample, ctx, true);
3419f9c9a8dSAdrian Hunter }
3429f9c9a8dSAdrian Hunter 
filter_event(void * data,const struct perf_dlfilter_sample * sample,void * ctx)3439f9c9a8dSAdrian Hunter int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ctx)
3449f9c9a8dSAdrian Hunter {
3459f9c9a8dSAdrian Hunter 	pr_debug("%s API\n", __func__);
3469f9c9a8dSAdrian Hunter 
3479f9c9a8dSAdrian Hunter 	return do_checks(data, sample, ctx, false);
3489f9c9a8dSAdrian Hunter }
3499f9c9a8dSAdrian Hunter 
stop(void * data,void * ctx)3509f9c9a8dSAdrian Hunter int stop(void *data, void *ctx)
3519f9c9a8dSAdrian Hunter {
3529f9c9a8dSAdrian Hunter 	static bool called;
3539f9c9a8dSAdrian Hunter 
3549f9c9a8dSAdrian Hunter 	pr_debug("%s API\n", __func__);
3559f9c9a8dSAdrian Hunter 
3569f9c9a8dSAdrian Hunter 	CHECK(data && filt_dat == data && !called);
3579f9c9a8dSAdrian Hunter 	called = true;
3589f9c9a8dSAdrian Hunter 
3599f9c9a8dSAdrian Hunter 	free(data);
3609f9c9a8dSAdrian Hunter 	filt_dat = NULL;
3619f9c9a8dSAdrian Hunter 	return 0;
3629f9c9a8dSAdrian Hunter }
3639f9c9a8dSAdrian Hunter 
filter_description(const char ** long_description)3649f9c9a8dSAdrian Hunter const char *filter_description(const char **long_description)
3659f9c9a8dSAdrian Hunter {
3669f9c9a8dSAdrian Hunter 	*long_description = "Filter used by the 'dlfilter C API' perf test";
3679f9c9a8dSAdrian Hunter 	return "dlfilter to test v0 C API";
3689f9c9a8dSAdrian Hunter }
369