2015-11-06 13:49:43 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/epoll.h>
|
2016-01-25 09:55:53 +00:00
|
|
|
#include <util/util.h>
|
2015-11-06 13:49:43 +00:00
|
|
|
#include <util/bpf-loader.h>
|
|
|
|
#include <util/evlist.h>
|
2016-01-25 09:55:53 +00:00
|
|
|
#include <linux/bpf.h>
|
|
|
|
#include <linux/filter.h>
|
|
|
|
#include <bpf/bpf.h>
|
2015-11-06 13:49:43 +00:00
|
|
|
#include "tests.h"
|
|
|
|
#include "llvm.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#define NR_ITERS 111
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBBPF_SUPPORT
|
|
|
|
|
2016-07-12 02:22:30 +00:00
|
|
|
static int epoll_wait_loop(void)
|
2015-11-06 13:49:43 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Should fail NR_ITERS times */
|
|
|
|
for (i = 0; i < NR_ITERS; i++)
|
2016-07-12 02:22:30 +00:00
|
|
|
epoll_wait(-(i + 1), NULL, 0, 0);
|
2015-11-06 13:49:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
perf test: Test the BPF prologue adding infrastructure
This patch introduces a new BPF script to test the BPF prologue adding
routines. The new script probes at null_lseek, which is the function pointer
used when we try to lseek on '/dev/null'.
The null_lseek function is chosen because it is used by function pointers, so
we don't need to consider inlining and LTO.
By extracting file->f_mode, bpf-script-test-prologue.c should know whether the
file is writable or readonly. According to llseek_loop() and
bpf-script-test-prologue.c, one fourth of total lseeks should be collected.
Committer note:
Testing it:
# perf test -v BPF
<SNIP>
Kernel build dir is set to /lib/modules/4.3.0+/build
set env: KBUILD_DIR=/lib/modules/4.3.0+/build
unset env: KBUILD_OPTS
include option is set to -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/4.9.2/include -I/home/git/linux/arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated -I/home/git/linux/include -Iinclude -I/home/git/linux/arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I/home/git/linux/include/uapi -Iinclude/generated/uapi -include /home/git/linux/include/linux/kconfig.h
set env: NR_CPUS=4
set env: LINUX_VERSION_CODE=0x40300
set env: CLANG_EXEC=/usr/libexec/icecc/bin/clang
set env: CLANG_OPTIONS=-xc
set env: KERNEL_INC_OPTIONS= -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/4.9.2/include -I/home/git/linux/arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated -I/home/git/linux/include -Iinclude -I/home/git/linux/arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I/home/git/linux/include/uapi -Iinclude/generated/uapi -include /home/git/linux/include/linux/kconfig.h
set env: WORKING_DIR=/lib/modules/4.3.0+/build
set env: CLANG_SOURCE=-
llvm compiling command template: echo '/*
* bpf-script-test-prologue.c
* Test BPF prologue
*/
#ifndef LINUX_VERSION_CODE
# error Need LINUX_VERSION_CODE
# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
#endif
#define SEC(NAME) __attribute__((section(NAME), used))
#include <uapi/linux/fs.h>
#define FMODE_READ 0x1
#define FMODE_WRITE 0x2
static void (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
(void *) 6;
SEC("func=null_lseek file->f_mode offset orig")
int bpf_func__null_lseek(void *ctx, int err, unsigned long f_mode,
unsigned long offset, unsigned long orig)
{
if (err)
return 0;
if (f_mode & FMODE_WRITE)
return 0;
if (offset & 1)
return 0;
if (orig == SEEK_CUR)
return 0;
return 1;
}
char _license[] SEC("license") = "GPL";
int _version SEC("version") = LINUX_VERSION_CODE;
' | $CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS -DLINUX_VERSION_CODE=$LINUX_VERSION_CODE $CLANG_OPTIONS $KERNEL_INC_OPTIONS -Wno-unused-value -Wno-pointer-sign -working-directory $WORKING_DIR -c "$CLANG_SOURCE" -target bpf -O2 -o -
libbpf: loading object '[bpf_prologue_test]' from buffer
libbpf: section .strtab, size 135, link 0, flags 0, type=3
libbpf: section .text, size 0, link 0, flags 6, type=1
libbpf: section .data, size 0, link 0, flags 3, type=1
libbpf: section .bss, size 0, link 0, flags 3, type=8
libbpf: section func=null_lseek file->f_mode offset orig, size 112, link 0, flags 6, type=1
libbpf: found program func=null_lseek file->f_mode offset orig
libbpf: section license, size 4, link 0, flags 3, type=1
libbpf: license of [bpf_prologue_test] is GPL
libbpf: section version, size 4, link 0, flags 3, type=1
libbpf: kernel version of [bpf_prologue_test] is 40300
libbpf: section .symtab, size 168, link 1, flags 0, type=2
bpf: config program 'func=null_lseek file->f_mode offset orig'
symbol:null_lseek file:(null) line:0 offset:0 return:0 lazy:(null)
parsing arg: file->f_mode into file, f_mode(1)
parsing arg: offset into offset
parsing arg: orig into orig
bpf: config 'func=null_lseek file->f_mode offset orig' is ok
Looking at the vmlinux_path (7 entries long)
Using /lib/modules/4.3.0+/build/vmlinux for symbols
Open Debuginfo file: /lib/modules/4.3.0+/build/vmlinux
Try to find probe point from debuginfo.
Matched function: null_lseek
Probe point found: null_lseek+0
Searching 'file' variable in context.
Converting variable file into trace event.
converting f_mode in file
f_mode type is unsigned int.
Searching 'offset' variable in context.
Converting variable offset into trace event.
offset type is long long int.
Searching 'orig' variable in context.
Converting variable orig into trace event.
orig type is int.
Found 1 probe_trace_events.
Opening /sys/kernel/debug/tracing//kprobe_events write=1
Writing event: p:perf_bpf_probe/func _text+4840528 f_mode=+68(%di):u32 offset=%si:s64 orig=%dx:s32
libbpf: don't need create maps for [bpf_prologue_test]
prologue: pass validation
prologue: slow path
prologue: fetch arg 0, base reg is %di
prologue: arg 0: offset 68
prologue: fetch arg 1, base reg is %si
prologue: fetch arg 2, base reg is %dx
add bpf event perf_bpf_probe:func and attach bpf program 3
adding perf_bpf_probe:func
adding perf_bpf_probe:func to 0x51672c0
mmap size 1052672B
Opening /sys/kernel/debug/tracing//kprobe_events write=1
Opening /sys/kernel/debug/tracing//uprobe_events write=1
Parsing probe_events: p:perf_bpf_probe/func _text+4840528 f_mode=+68(%di):u32 offset=%si:s64 orig=%dx:s32
Group:perf_bpf_probe Event:func probe:p
Writing event: -:perf_bpf_probe/func
test child finished with 0
---- end ----
Test BPF filter: Ok
#
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1447675815-166222-13-git-send-email-wangnan0@huawei.com
[ Added tools/perf/tests/llvm-src-prologue.c to .gitignore ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-11-16 12:10:14 +00:00
|
|
|
#ifdef HAVE_BPF_PROLOGUE
|
|
|
|
|
|
|
|
static int llseek_loop(void)
|
|
|
|
{
|
|
|
|
int fds[2], i;
|
|
|
|
|
|
|
|
fds[0] = open("/dev/null", O_RDONLY);
|
|
|
|
fds[1] = open("/dev/null", O_RDWR);
|
|
|
|
|
|
|
|
if (fds[0] < 0 || fds[1] < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (i = 0; i < NR_ITERS; i++) {
|
|
|
|
lseek(fds[i % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
|
|
|
|
lseek(fds[(i + 1) % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
|
|
|
|
}
|
|
|
|
close(fds[0]);
|
|
|
|
close(fds[1]);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2015-11-06 13:49:43 +00:00
|
|
|
static struct {
|
|
|
|
enum test_llvm__testcase prog_id;
|
|
|
|
const char *desc;
|
|
|
|
const char *name;
|
|
|
|
const char *msg_compile_fail;
|
|
|
|
const char *msg_load_fail;
|
|
|
|
int (*target_func)(void);
|
|
|
|
int expect_result;
|
|
|
|
} bpf_testcase_table[] = {
|
|
|
|
{
|
|
|
|
LLVM_TESTCASE_BASE,
|
|
|
|
"Test basic BPF filtering",
|
|
|
|
"[basic_bpf_test]",
|
|
|
|
"fix 'perf test LLVM' first",
|
|
|
|
"load bpf object failed",
|
2016-07-12 02:22:30 +00:00
|
|
|
&epoll_wait_loop,
|
2015-11-06 13:49:43 +00:00
|
|
|
(NR_ITERS + 1) / 2,
|
|
|
|
},
|
perf test: Test the BPF prologue adding infrastructure
This patch introduces a new BPF script to test the BPF prologue adding
routines. The new script probes at null_lseek, which is the function pointer
used when we try to lseek on '/dev/null'.
The null_lseek function is chosen because it is used by function pointers, so
we don't need to consider inlining and LTO.
By extracting file->f_mode, bpf-script-test-prologue.c should know whether the
file is writable or readonly. According to llseek_loop() and
bpf-script-test-prologue.c, one fourth of total lseeks should be collected.
Committer note:
Testing it:
# perf test -v BPF
<SNIP>
Kernel build dir is set to /lib/modules/4.3.0+/build
set env: KBUILD_DIR=/lib/modules/4.3.0+/build
unset env: KBUILD_OPTS
include option is set to -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/4.9.2/include -I/home/git/linux/arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated -I/home/git/linux/include -Iinclude -I/home/git/linux/arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I/home/git/linux/include/uapi -Iinclude/generated/uapi -include /home/git/linux/include/linux/kconfig.h
set env: NR_CPUS=4
set env: LINUX_VERSION_CODE=0x40300
set env: CLANG_EXEC=/usr/libexec/icecc/bin/clang
set env: CLANG_OPTIONS=-xc
set env: KERNEL_INC_OPTIONS= -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/4.9.2/include -I/home/git/linux/arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated -I/home/git/linux/include -Iinclude -I/home/git/linux/arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I/home/git/linux/include/uapi -Iinclude/generated/uapi -include /home/git/linux/include/linux/kconfig.h
set env: WORKING_DIR=/lib/modules/4.3.0+/build
set env: CLANG_SOURCE=-
llvm compiling command template: echo '/*
* bpf-script-test-prologue.c
* Test BPF prologue
*/
#ifndef LINUX_VERSION_CODE
# error Need LINUX_VERSION_CODE
# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
#endif
#define SEC(NAME) __attribute__((section(NAME), used))
#include <uapi/linux/fs.h>
#define FMODE_READ 0x1
#define FMODE_WRITE 0x2
static void (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
(void *) 6;
SEC("func=null_lseek file->f_mode offset orig")
int bpf_func__null_lseek(void *ctx, int err, unsigned long f_mode,
unsigned long offset, unsigned long orig)
{
if (err)
return 0;
if (f_mode & FMODE_WRITE)
return 0;
if (offset & 1)
return 0;
if (orig == SEEK_CUR)
return 0;
return 1;
}
char _license[] SEC("license") = "GPL";
int _version SEC("version") = LINUX_VERSION_CODE;
' | $CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS -DLINUX_VERSION_CODE=$LINUX_VERSION_CODE $CLANG_OPTIONS $KERNEL_INC_OPTIONS -Wno-unused-value -Wno-pointer-sign -working-directory $WORKING_DIR -c "$CLANG_SOURCE" -target bpf -O2 -o -
libbpf: loading object '[bpf_prologue_test]' from buffer
libbpf: section .strtab, size 135, link 0, flags 0, type=3
libbpf: section .text, size 0, link 0, flags 6, type=1
libbpf: section .data, size 0, link 0, flags 3, type=1
libbpf: section .bss, size 0, link 0, flags 3, type=8
libbpf: section func=null_lseek file->f_mode offset orig, size 112, link 0, flags 6, type=1
libbpf: found program func=null_lseek file->f_mode offset orig
libbpf: section license, size 4, link 0, flags 3, type=1
libbpf: license of [bpf_prologue_test] is GPL
libbpf: section version, size 4, link 0, flags 3, type=1
libbpf: kernel version of [bpf_prologue_test] is 40300
libbpf: section .symtab, size 168, link 1, flags 0, type=2
bpf: config program 'func=null_lseek file->f_mode offset orig'
symbol:null_lseek file:(null) line:0 offset:0 return:0 lazy:(null)
parsing arg: file->f_mode into file, f_mode(1)
parsing arg: offset into offset
parsing arg: orig into orig
bpf: config 'func=null_lseek file->f_mode offset orig' is ok
Looking at the vmlinux_path (7 entries long)
Using /lib/modules/4.3.0+/build/vmlinux for symbols
Open Debuginfo file: /lib/modules/4.3.0+/build/vmlinux
Try to find probe point from debuginfo.
Matched function: null_lseek
Probe point found: null_lseek+0
Searching 'file' variable in context.
Converting variable file into trace event.
converting f_mode in file
f_mode type is unsigned int.
Searching 'offset' variable in context.
Converting variable offset into trace event.
offset type is long long int.
Searching 'orig' variable in context.
Converting variable orig into trace event.
orig type is int.
Found 1 probe_trace_events.
Opening /sys/kernel/debug/tracing//kprobe_events write=1
Writing event: p:perf_bpf_probe/func _text+4840528 f_mode=+68(%di):u32 offset=%si:s64 orig=%dx:s32
libbpf: don't need create maps for [bpf_prologue_test]
prologue: pass validation
prologue: slow path
prologue: fetch arg 0, base reg is %di
prologue: arg 0: offset 68
prologue: fetch arg 1, base reg is %si
prologue: fetch arg 2, base reg is %dx
add bpf event perf_bpf_probe:func and attach bpf program 3
adding perf_bpf_probe:func
adding perf_bpf_probe:func to 0x51672c0
mmap size 1052672B
Opening /sys/kernel/debug/tracing//kprobe_events write=1
Opening /sys/kernel/debug/tracing//uprobe_events write=1
Parsing probe_events: p:perf_bpf_probe/func _text+4840528 f_mode=+68(%di):u32 offset=%si:s64 orig=%dx:s32
Group:perf_bpf_probe Event:func probe:p
Writing event: -:perf_bpf_probe/func
test child finished with 0
---- end ----
Test BPF filter: Ok
#
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1447675815-166222-13-git-send-email-wangnan0@huawei.com
[ Added tools/perf/tests/llvm-src-prologue.c to .gitignore ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-11-16 12:10:14 +00:00
|
|
|
#ifdef HAVE_BPF_PROLOGUE
|
|
|
|
{
|
|
|
|
LLVM_TESTCASE_BPF_PROLOGUE,
|
|
|
|
"Test BPF prologue generation",
|
|
|
|
"[bpf_prologue_test]",
|
|
|
|
"fix kbuild first",
|
|
|
|
"check your vmlinux setting?",
|
|
|
|
&llseek_loop,
|
|
|
|
(NR_ITERS + 1) / 4,
|
|
|
|
},
|
|
|
|
#endif
|
perf test: Add libbpf relocation checker
There's a bug in LLVM that it can generate unneeded relocation
information. See [1] and [2]. Libbpf should check the target section of
a relocation symbol.
This patch adds a testcase which references a global variable (BPF
doesn't support global variables). Before fixing libbpf, the new test
case can be loaded into kernel, the global variable acts like the first
map. It is incorrect.
Result:
# ~/perf test BPF
37: Test BPF filter :
37.1: Test basic BPF filtering : Ok
37.2: Test BPF prologue generation : Ok
37.3: Test BPF relocation checker : FAILED!
# ~/perf test -v BPF
...
libbpf: loading object '[bpf_relocation_test]' from buffer
libbpf: section .strtab, size 126, link 0, flags 0, type=3
libbpf: section .text, size 0, link 0, flags 6, type=1
libbpf: section .data, size 0, link 0, flags 3, type=1
libbpf: section .bss, size 0, link 0, flags 3, type=8
libbpf: section func=sys_write, size 104, link 0, flags 6, type=1
libbpf: found program func=sys_write
libbpf: section .relfunc=sys_write, size 16, link 10, flags 0, type=9
libbpf: section maps, size 16, link 0, flags 3, type=1
libbpf: maps in [bpf_relocation_test]: 16 bytes
libbpf: section license, size 4, link 0, flags 3, type=1
libbpf: license of [bpf_relocation_test] is GPL
libbpf: section version, size 4, link 0, flags 3, type=1
libbpf: kernel version of [bpf_relocation_test] is 40400
libbpf: section .symtab, size 144, link 1, flags 0, type=2
libbpf: map 0 is "my_table"
libbpf: collecting relocating info for: 'func=sys_write'
libbpf: relocation: insn_idx=7
Success unexpectedly: libbpf error when dealing with relocation
test child finished with -1
---- end ----
Test BPF filter subtest 2: FAILED!
[1] https://llvm.org/bugs/show_bug.cgi?id=26243
[2] https://patchwork.ozlabs.org/patch/571385/
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Li Zefan <lizefan@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1453715801-7732-2-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-01-25 09:55:48 +00:00
|
|
|
{
|
|
|
|
LLVM_TESTCASE_BPF_RELOCATION,
|
|
|
|
"Test BPF relocation checker",
|
|
|
|
"[bpf_relocation_test]",
|
|
|
|
"fix 'perf test LLVM' first",
|
|
|
|
"libbpf error when dealing with relocation",
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
},
|
2015-11-06 13:49:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int do_test(struct bpf_object *obj, int (*func)(void),
|
|
|
|
int expect)
|
|
|
|
{
|
|
|
|
struct record_opts opts = {
|
|
|
|
.target = {
|
|
|
|
.uid = UINT_MAX,
|
|
|
|
.uses_mmap = true,
|
|
|
|
},
|
|
|
|
.freq = 0,
|
|
|
|
.mmap_pages = 256,
|
|
|
|
.default_interval = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
char pid[16];
|
|
|
|
char sbuf[STRERR_BUFSIZE];
|
|
|
|
struct perf_evlist *evlist;
|
|
|
|
int i, ret = TEST_FAIL, err = 0, count = 0;
|
|
|
|
|
|
|
|
struct parse_events_evlist parse_evlist;
|
|
|
|
struct parse_events_error parse_error;
|
|
|
|
|
|
|
|
bzero(&parse_error, sizeof(parse_error));
|
|
|
|
bzero(&parse_evlist, sizeof(parse_evlist));
|
|
|
|
parse_evlist.error = &parse_error;
|
|
|
|
INIT_LIST_HEAD(&parse_evlist.list);
|
|
|
|
|
2016-02-22 09:10:36 +00:00
|
|
|
err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj, NULL);
|
2015-11-06 13:49:43 +00:00
|
|
|
if (err || list_empty(&parse_evlist.list)) {
|
|
|
|
pr_debug("Failed to add events selected by BPF\n");
|
2015-11-17 08:32:46 +00:00
|
|
|
return TEST_FAIL;
|
2015-11-06 13:49:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(pid, sizeof(pid), "%d", getpid());
|
|
|
|
pid[sizeof(pid) - 1] = '\0';
|
|
|
|
opts.target.tid = opts.target.pid = pid;
|
|
|
|
|
|
|
|
/* Instead of perf_evlist__new_default, don't add default events */
|
|
|
|
evlist = perf_evlist__new();
|
|
|
|
if (!evlist) {
|
2016-10-13 16:18:11 +00:00
|
|
|
pr_debug("Not enough memory to create evlist\n");
|
2015-11-06 13:49:43 +00:00
|
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = perf_evlist__create_maps(evlist, &opts.target);
|
|
|
|
if (err < 0) {
|
|
|
|
pr_debug("Not enough memory to create thread/cpu maps\n");
|
|
|
|
goto out_delete_evlist;
|
|
|
|
}
|
|
|
|
|
|
|
|
perf_evlist__splice_list_tail(evlist, &parse_evlist.list);
|
|
|
|
evlist->nr_groups = parse_evlist.nr_groups;
|
|
|
|
|
2016-04-11 21:15:29 +00:00
|
|
|
perf_evlist__config(evlist, &opts, NULL);
|
2015-11-06 13:49:43 +00:00
|
|
|
|
|
|
|
err = perf_evlist__open(evlist);
|
|
|
|
if (err < 0) {
|
|
|
|
pr_debug("perf_evlist__open: %s\n",
|
tools: Introduce str_error_r()
The tools so far have been using the strerror_r() GNU variant, that
returns a string, be it the buffer passed or something else.
But that, besides being tricky in cases where we expect that the
function using strerror_r() returns the error formatted in a provided
buffer (we have to check if it returned something else and copy that
instead), breaks the build on systems not using glibc, like Alpine
Linux, where musl libc is used.
So, introduce yet another wrapper, str_error_r(), that has the GNU
interface, but uses the portable XSI variant of strerror_r(), so that
users rest asured that the provided buffer is used and it is what is
returned.
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/n/tip-d4t42fnf48ytlk8rjxs822tf@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-07-06 14:56:20 +00:00
|
|
|
str_error_r(errno, sbuf, sizeof(sbuf)));
|
2015-11-06 13:49:43 +00:00
|
|
|
goto out_delete_evlist;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
|
|
|
|
if (err < 0) {
|
|
|
|
pr_debug("perf_evlist__mmap: %s\n",
|
tools: Introduce str_error_r()
The tools so far have been using the strerror_r() GNU variant, that
returns a string, be it the buffer passed or something else.
But that, besides being tricky in cases where we expect that the
function using strerror_r() returns the error formatted in a provided
buffer (we have to check if it returned something else and copy that
instead), breaks the build on systems not using glibc, like Alpine
Linux, where musl libc is used.
So, introduce yet another wrapper, str_error_r(), that has the GNU
interface, but uses the portable XSI variant of strerror_r(), so that
users rest asured that the provided buffer is used and it is what is
returned.
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/n/tip-d4t42fnf48ytlk8rjxs822tf@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-07-06 14:56:20 +00:00
|
|
|
str_error_r(errno, sbuf, sizeof(sbuf)));
|
2015-11-06 13:49:43 +00:00
|
|
|
goto out_delete_evlist;
|
|
|
|
}
|
|
|
|
|
|
|
|
perf_evlist__enable(evlist);
|
|
|
|
(*func)();
|
|
|
|
perf_evlist__disable(evlist);
|
|
|
|
|
|
|
|
for (i = 0; i < evlist->nr_mmaps; i++) {
|
|
|
|
union perf_event *event;
|
|
|
|
|
|
|
|
while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
|
|
|
|
const u32 type = event->header.type;
|
|
|
|
|
|
|
|
if (type == PERF_RECORD_SAMPLE)
|
|
|
|
count ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-17 08:32:46 +00:00
|
|
|
if (count != expect) {
|
2015-11-06 13:49:43 +00:00
|
|
|
pr_debug("BPF filter result incorrect\n");
|
2015-11-17 08:32:46 +00:00
|
|
|
goto out_delete_evlist;
|
|
|
|
}
|
2015-11-06 13:49:43 +00:00
|
|
|
|
|
|
|
ret = TEST_OK;
|
|
|
|
|
|
|
|
out_delete_evlist:
|
|
|
|
perf_evlist__delete(evlist);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct bpf_object *
|
|
|
|
prepare_bpf(void *obj_buf, size_t obj_buf_sz, const char *name)
|
|
|
|
{
|
|
|
|
struct bpf_object *obj;
|
|
|
|
|
|
|
|
obj = bpf__prepare_load_buffer(obj_buf, obj_buf_sz, name);
|
|
|
|
if (IS_ERR(obj)) {
|
|
|
|
pr_debug("Compile BPF program failed.\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2015-11-18 20:38:49 +00:00
|
|
|
static int __test__bpf(int idx)
|
2015-11-06 13:49:43 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
void *obj_buf;
|
|
|
|
size_t obj_buf_sz;
|
|
|
|
struct bpf_object *obj;
|
|
|
|
|
|
|
|
ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
|
2015-11-18 20:38:49 +00:00
|
|
|
bpf_testcase_table[idx].prog_id,
|
perf test: Add libbpf relocation checker
There's a bug in LLVM that it can generate unneeded relocation
information. See [1] and [2]. Libbpf should check the target section of
a relocation symbol.
This patch adds a testcase which references a global variable (BPF
doesn't support global variables). Before fixing libbpf, the new test
case can be loaded into kernel, the global variable acts like the first
map. It is incorrect.
Result:
# ~/perf test BPF
37: Test BPF filter :
37.1: Test basic BPF filtering : Ok
37.2: Test BPF prologue generation : Ok
37.3: Test BPF relocation checker : FAILED!
# ~/perf test -v BPF
...
libbpf: loading object '[bpf_relocation_test]' from buffer
libbpf: section .strtab, size 126, link 0, flags 0, type=3
libbpf: section .text, size 0, link 0, flags 6, type=1
libbpf: section .data, size 0, link 0, flags 3, type=1
libbpf: section .bss, size 0, link 0, flags 3, type=8
libbpf: section func=sys_write, size 104, link 0, flags 6, type=1
libbpf: found program func=sys_write
libbpf: section .relfunc=sys_write, size 16, link 10, flags 0, type=9
libbpf: section maps, size 16, link 0, flags 3, type=1
libbpf: maps in [bpf_relocation_test]: 16 bytes
libbpf: section license, size 4, link 0, flags 3, type=1
libbpf: license of [bpf_relocation_test] is GPL
libbpf: section version, size 4, link 0, flags 3, type=1
libbpf: kernel version of [bpf_relocation_test] is 40400
libbpf: section .symtab, size 144, link 1, flags 0, type=2
libbpf: map 0 is "my_table"
libbpf: collecting relocating info for: 'func=sys_write'
libbpf: relocation: insn_idx=7
Success unexpectedly: libbpf error when dealing with relocation
test child finished with -1
---- end ----
Test BPF filter subtest 2: FAILED!
[1] https://llvm.org/bugs/show_bug.cgi?id=26243
[2] https://patchwork.ozlabs.org/patch/571385/
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Li Zefan <lizefan@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1453715801-7732-2-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-01-25 09:55:48 +00:00
|
|
|
true, NULL);
|
2015-11-06 13:49:43 +00:00
|
|
|
if (ret != TEST_OK || !obj_buf || !obj_buf_sz) {
|
|
|
|
pr_debug("Unable to get BPF object, %s\n",
|
2015-11-18 20:38:49 +00:00
|
|
|
bpf_testcase_table[idx].msg_compile_fail);
|
|
|
|
if (idx == 0)
|
2015-11-06 13:49:43 +00:00
|
|
|
return TEST_SKIP;
|
|
|
|
else
|
|
|
|
return TEST_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
obj = prepare_bpf(obj_buf, obj_buf_sz,
|
2015-11-18 20:38:49 +00:00
|
|
|
bpf_testcase_table[idx].name);
|
perf test: Add libbpf relocation checker
There's a bug in LLVM that it can generate unneeded relocation
information. See [1] and [2]. Libbpf should check the target section of
a relocation symbol.
This patch adds a testcase which references a global variable (BPF
doesn't support global variables). Before fixing libbpf, the new test
case can be loaded into kernel, the global variable acts like the first
map. It is incorrect.
Result:
# ~/perf test BPF
37: Test BPF filter :
37.1: Test basic BPF filtering : Ok
37.2: Test BPF prologue generation : Ok
37.3: Test BPF relocation checker : FAILED!
# ~/perf test -v BPF
...
libbpf: loading object '[bpf_relocation_test]' from buffer
libbpf: section .strtab, size 126, link 0, flags 0, type=3
libbpf: section .text, size 0, link 0, flags 6, type=1
libbpf: section .data, size 0, link 0, flags 3, type=1
libbpf: section .bss, size 0, link 0, flags 3, type=8
libbpf: section func=sys_write, size 104, link 0, flags 6, type=1
libbpf: found program func=sys_write
libbpf: section .relfunc=sys_write, size 16, link 10, flags 0, type=9
libbpf: section maps, size 16, link 0, flags 3, type=1
libbpf: maps in [bpf_relocation_test]: 16 bytes
libbpf: section license, size 4, link 0, flags 3, type=1
libbpf: license of [bpf_relocation_test] is GPL
libbpf: section version, size 4, link 0, flags 3, type=1
libbpf: kernel version of [bpf_relocation_test] is 40400
libbpf: section .symtab, size 144, link 1, flags 0, type=2
libbpf: map 0 is "my_table"
libbpf: collecting relocating info for: 'func=sys_write'
libbpf: relocation: insn_idx=7
Success unexpectedly: libbpf error when dealing with relocation
test child finished with -1
---- end ----
Test BPF filter subtest 2: FAILED!
[1] https://llvm.org/bugs/show_bug.cgi?id=26243
[2] https://patchwork.ozlabs.org/patch/571385/
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Li Zefan <lizefan@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1453715801-7732-2-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-01-25 09:55:48 +00:00
|
|
|
if ((!!bpf_testcase_table[idx].target_func) != (!!obj)) {
|
|
|
|
if (!obj)
|
|
|
|
pr_debug("Fail to load BPF object: %s\n",
|
|
|
|
bpf_testcase_table[idx].msg_load_fail);
|
|
|
|
else
|
|
|
|
pr_debug("Success unexpectedly: %s\n",
|
|
|
|
bpf_testcase_table[idx].msg_load_fail);
|
2015-11-06 13:49:43 +00:00
|
|
|
ret = TEST_FAIL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
perf test: Add libbpf relocation checker
There's a bug in LLVM that it can generate unneeded relocation
information. See [1] and [2]. Libbpf should check the target section of
a relocation symbol.
This patch adds a testcase which references a global variable (BPF
doesn't support global variables). Before fixing libbpf, the new test
case can be loaded into kernel, the global variable acts like the first
map. It is incorrect.
Result:
# ~/perf test BPF
37: Test BPF filter :
37.1: Test basic BPF filtering : Ok
37.2: Test BPF prologue generation : Ok
37.3: Test BPF relocation checker : FAILED!
# ~/perf test -v BPF
...
libbpf: loading object '[bpf_relocation_test]' from buffer
libbpf: section .strtab, size 126, link 0, flags 0, type=3
libbpf: section .text, size 0, link 0, flags 6, type=1
libbpf: section .data, size 0, link 0, flags 3, type=1
libbpf: section .bss, size 0, link 0, flags 3, type=8
libbpf: section func=sys_write, size 104, link 0, flags 6, type=1
libbpf: found program func=sys_write
libbpf: section .relfunc=sys_write, size 16, link 10, flags 0, type=9
libbpf: section maps, size 16, link 0, flags 3, type=1
libbpf: maps in [bpf_relocation_test]: 16 bytes
libbpf: section license, size 4, link 0, flags 3, type=1
libbpf: license of [bpf_relocation_test] is GPL
libbpf: section version, size 4, link 0, flags 3, type=1
libbpf: kernel version of [bpf_relocation_test] is 40400
libbpf: section .symtab, size 144, link 1, flags 0, type=2
libbpf: map 0 is "my_table"
libbpf: collecting relocating info for: 'func=sys_write'
libbpf: relocation: insn_idx=7
Success unexpectedly: libbpf error when dealing with relocation
test child finished with -1
---- end ----
Test BPF filter subtest 2: FAILED!
[1] https://llvm.org/bugs/show_bug.cgi?id=26243
[2] https://patchwork.ozlabs.org/patch/571385/
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Li Zefan <lizefan@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1453715801-7732-2-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-01-25 09:55:48 +00:00
|
|
|
if (obj)
|
|
|
|
ret = do_test(obj,
|
|
|
|
bpf_testcase_table[idx].target_func,
|
|
|
|
bpf_testcase_table[idx].expect_result);
|
2015-11-06 13:49:43 +00:00
|
|
|
out:
|
|
|
|
bpf__clear();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-11-17 08:32:49 +00:00
|
|
|
int test__bpf_subtest_get_nr(void)
|
|
|
|
{
|
|
|
|
return (int)ARRAY_SIZE(bpf_testcase_table);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *test__bpf_subtest_get_desc(int i)
|
|
|
|
{
|
|
|
|
if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table))
|
|
|
|
return NULL;
|
|
|
|
return bpf_testcase_table[i].desc;
|
|
|
|
}
|
|
|
|
|
2016-01-25 09:55:53 +00:00
|
|
|
static int check_env(void)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
unsigned int kver_int;
|
|
|
|
char license[] = "GPL";
|
|
|
|
|
|
|
|
struct bpf_insn insns[] = {
|
|
|
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
|
|
|
BPF_EXIT_INSN(),
|
|
|
|
};
|
|
|
|
|
|
|
|
err = fetch_kernel_version(&kver_int, NULL, 0);
|
|
|
|
if (err) {
|
|
|
|
pr_debug("Unable to get kernel version\n");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns,
|
|
|
|
sizeof(insns) / sizeof(insns[0]),
|
|
|
|
license, kver_int, NULL, 0);
|
|
|
|
if (err < 0) {
|
|
|
|
pr_err("Missing basic BPF support, skip this test: %s\n",
|
|
|
|
strerror(errno));
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
close(err);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-17 08:32:49 +00:00
|
|
|
int test__bpf(int i)
|
2015-11-06 13:49:43 +00:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2015-11-17 08:32:49 +00:00
|
|
|
if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table))
|
|
|
|
return TEST_FAIL;
|
|
|
|
|
2015-11-06 13:49:43 +00:00
|
|
|
if (geteuid() != 0) {
|
|
|
|
pr_debug("Only root can run BPF test\n");
|
|
|
|
return TEST_SKIP;
|
|
|
|
}
|
|
|
|
|
2016-01-25 09:55:53 +00:00
|
|
|
if (check_env())
|
|
|
|
return TEST_SKIP;
|
|
|
|
|
2015-11-17 08:32:49 +00:00
|
|
|
err = __test__bpf(i);
|
|
|
|
return err;
|
|
|
|
}
|
2015-11-06 13:49:43 +00:00
|
|
|
|
2015-11-17 08:32:49 +00:00
|
|
|
#else
|
|
|
|
int test__bpf_subtest_get_nr(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2015-11-06 13:49:43 +00:00
|
|
|
|
2015-11-17 08:32:49 +00:00
|
|
|
const char *test__bpf_subtest_get_desc(int i __maybe_unused)
|
|
|
|
{
|
|
|
|
return NULL;
|
2015-11-06 13:49:43 +00:00
|
|
|
}
|
|
|
|
|
2015-11-17 08:32:49 +00:00
|
|
|
int test__bpf(int i __maybe_unused)
|
2015-11-06 13:49:43 +00:00
|
|
|
{
|
|
|
|
pr_debug("Skip BPF test because BPF support is not compiled\n");
|
|
|
|
return TEST_SKIP;
|
|
|
|
}
|
|
|
|
#endif
|