Skip to content

Commit 52cfac2

Browse files
namhyungKernel Patches Daemon
authored and
Kernel Patches Daemon
committed
selftests/bpf: Add perf_event_read_sample test cases
It checks the perf event sample access with bpf_cast_to_kern_ctx(). It should access sample data only event->attr.sample_type allows. Other fields might not be initialized. $ ./vmtest.sh ./test_progs -t perf_event_read_sample ... #135/1 perf_event_read_sample/perf_event_read_sample_ok:OK #135/2 perf_event_read_sample/perf_event_read_sample_invalid:OK #135 perf_event_read_sample:OK Signed-off-by: Namhyung Kim <[email protected]>
1 parent 169e265 commit 52cfac2

File tree

2 files changed

+200
-0
lines changed

2 files changed

+200
-0
lines changed
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#define _GNU_SOURCE
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <unistd.h>
6+
#include <linux/perf_event.h>
7+
#include <sys/ioctl.h>
8+
#include <sys/mman.h>
9+
#include <sys/syscall.h>
10+
11+
#include <test_progs.h>
12+
#include "test_perf_sample.skel.h"
13+
14+
#ifndef noinline
15+
#define noinline __attribute__((noinline))
16+
#endif
17+
18+
/* treat user-stack data as invalid (for testing only) */
19+
#define PERF_SAMPLE_INVALID PERF_SAMPLE_STACK_USER
20+
21+
#define PERF_MMAP_SIZE 8192
22+
#define DATA_MMAP_SIZE 4096
23+
24+
static int perf_fd = -1;
25+
static void *perf_ringbuf;
26+
static struct test_perf_sample *skel;
27+
28+
static int open_perf_event(u64 sample_flags)
29+
{
30+
struct perf_event_attr attr = {
31+
.type = PERF_TYPE_SOFTWARE,
32+
.config = PERF_COUNT_SW_PAGE_FAULTS,
33+
.sample_type = sample_flags,
34+
.sample_period = 1,
35+
.disabled = 1,
36+
.size = sizeof(attr),
37+
};
38+
int fd;
39+
void *ptr;
40+
41+
fd = syscall(SYS_perf_event_open, &attr, 0, -1, -1, 0);
42+
if (!ASSERT_GT(fd, 0, "perf_event_open"))
43+
return -1;
44+
45+
ptr = mmap(NULL, PERF_MMAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
46+
if (!ASSERT_NEQ(ptr, MAP_FAILED, "mmap")) {
47+
close(fd);
48+
return -1;
49+
}
50+
51+
perf_fd = fd;
52+
perf_ringbuf = ptr;
53+
54+
return 0;
55+
}
56+
57+
static void close_perf_event(void)
58+
{
59+
if (perf_fd == -1)
60+
return;
61+
62+
munmap(perf_ringbuf, PERF_MMAP_SIZE);
63+
close(perf_fd);
64+
65+
perf_fd = -1;
66+
perf_ringbuf = NULL;
67+
}
68+
69+
static noinline void *trigger_perf_event(void)
70+
{
71+
int *buf = mmap(NULL, DATA_MMAP_SIZE, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
72+
73+
if (!ASSERT_NEQ(buf, MAP_FAILED, "mmap"))
74+
return NULL;
75+
76+
ioctl(perf_fd, PERF_EVENT_IOC_ENABLE);
77+
78+
/* it should generate a page fault which triggers the perf_event */
79+
*buf = 1;
80+
81+
ioctl(perf_fd, PERF_EVENT_IOC_DISABLE);
82+
83+
munmap(buf, DATA_MMAP_SIZE);
84+
85+
/* return the map address to check the sample addr */
86+
return buf;
87+
}
88+
89+
/* check if the perf ringbuf has a sample data */
90+
static int check_perf_event(void)
91+
{
92+
struct perf_event_mmap_page *page = perf_ringbuf;
93+
struct perf_event_header *hdr;
94+
95+
if (page->data_head == page->data_tail)
96+
return 0;
97+
98+
hdr = perf_ringbuf + page->data_offset;
99+
100+
if (hdr->type != PERF_RECORD_SAMPLE)
101+
return 0;
102+
103+
return 1;
104+
}
105+
106+
static void setup_perf_sample_bpf_skel(void)
107+
{
108+
struct bpf_link *link;
109+
110+
skel = test_perf_sample__open_and_load();
111+
if (!ASSERT_OK_PTR(skel, "test_perf_sample_open_and_load"))
112+
return;
113+
114+
link = bpf_program__attach_perf_event(skel->progs.perf_sample_filter, perf_fd);
115+
if (!ASSERT_OK_PTR(link, "bpf_program__attach_perf_event"))
116+
return;
117+
}
118+
119+
static void clean_perf_sample_bpf_skel(void)
120+
{
121+
test_perf_sample__detach(skel);
122+
test_perf_sample__destroy(skel);
123+
}
124+
125+
static void test_perf_event_read_sample_ok(void)
126+
{
127+
u64 flags = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_ADDR;
128+
uintptr_t map_addr;
129+
130+
if (open_perf_event(flags) < 0)
131+
return;
132+
setup_perf_sample_bpf_skel();
133+
map_addr = (uintptr_t)trigger_perf_event();
134+
135+
ASSERT_EQ(check_perf_event(), 1, "number of sample");
136+
ASSERT_EQ(skel->bss->sample_addr, map_addr, "sample addr");
137+
ASSERT_EQ((int)skel->bss->sample_pid, getpid(), "sample pid");
138+
/* just assume the IP in (trigger_perf_event, +4096) */
139+
ASSERT_GT(skel->bss->sample_ip, (uintptr_t)trigger_perf_event, "sample ip");
140+
ASSERT_LT(skel->bss->sample_ip, (uintptr_t)trigger_perf_event + 4096, "sample ip");
141+
142+
clean_perf_sample_bpf_skel();
143+
close_perf_event();
144+
}
145+
146+
static void test_perf_event_read_sample_invalid(void)
147+
{
148+
u64 flags = PERF_SAMPLE_INVALID;
149+
150+
if (open_perf_event(flags) < 0)
151+
return;
152+
setup_perf_sample_bpf_skel();
153+
trigger_perf_event();
154+
155+
ASSERT_EQ(check_perf_event(), 0, "number of sample");
156+
157+
clean_perf_sample_bpf_skel();
158+
close_perf_event();
159+
}
160+
161+
void test_perf_event_read_sample(void)
162+
{
163+
if (test__start_subtest("perf_event_read_sample_ok"))
164+
test_perf_event_read_sample_ok();
165+
if (test__start_subtest("perf_event_read_sample_invalid"))
166+
test_perf_event_read_sample_invalid();
167+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
// Copyright (c) 2022 Google
3+
4+
#include "vmlinux.h"
5+
#include <bpf/bpf_helpers.h>
6+
7+
unsigned long long sample_ip;
8+
unsigned long long sample_pid;
9+
unsigned long long sample_addr;
10+
11+
void *bpf_cast_to_kern_ctx(void *) __ksym;
12+
13+
#define SAMPLE_FLAGS (PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_ADDR)
14+
15+
SEC("perf_event")
16+
int perf_sample_filter(void *ctx)
17+
{
18+
struct bpf_perf_event_data_kern *kctx;
19+
20+
kctx = bpf_cast_to_kern_ctx(ctx);
21+
22+
if ((kctx->event->attr.sample_type & SAMPLE_FLAGS) != SAMPLE_FLAGS)
23+
return 0;
24+
25+
sample_ip = kctx->data->ip;
26+
sample_pid = kctx->data->tid_entry.pid;
27+
sample_addr = kctx->data->addr;
28+
29+
/* generate sample data */
30+
return 1;
31+
}
32+
33+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)