Commit acbd0620 authored by Andrii Nakryiko's avatar Andrii Nakryiko Committed by Daniel Borkmann
Browse files

selftests/bpf: Add vmlinux.h selftest exercising tracing of syscalls



Add vmlinux.h generation to selftest/bpf's Makefile. Use it from newly added
test_vmlinux to trace nanosleep syscall using 5 different types of programs:
  - tracepoint;
  - raw tracepoint;
  - raw tracepoint w/ direct memory reads (tp_btf);
  - kprobe;
  - fentry.

These programs are realistic variants of real-life tracing programs,
excercising vmlinux.h's usage with tracing applications.

Signed-off-by: default avatarAndrii Nakryiko <andriin@fb.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarMartin KaFai Lau <kafai@fb.com>
Link: https://lore.kernel.org/bpf/20200313172336.1879637-5-andriin@fb.com
parent b8ebce86
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -177,6 +177,10 @@ $(BUILD_DIR)/libbpf $(BUILD_DIR)/bpftool $(INCLUDE_DIR):
	$(call msg,MKDIR,,$@)
	mkdir -p $@

$(INCLUDE_DIR)/vmlinux.h: $(VMLINUX_BTF) | $(BPFTOOL) $(INCLUDE_DIR)
	$(call msg,GEN,,$@)
	$(BPFTOOL) btf dump file $(VMLINUX_BTF) format c > $@

# Get Clang's default includes on this system, as opposed to those seen by
# '-target bpf'. This fixes "missing" files on some architectures/distros,
# such as asm/byteorder.h, asm/socket.h, asm/sockios.h, sys/cdefs.h etc.
@@ -285,6 +289,7 @@ $(TRUNNER_BPF_PROGS_DIR)$(if $2,-)$2-bpfobjs := y
$(TRUNNER_BPF_OBJS): $(TRUNNER_OUTPUT)/%.o:				\
		     $(TRUNNER_BPF_PROGS_DIR)/%.c			\
		     $(TRUNNER_BPF_PROGS_DIR)/*.h			\
		     $$(INCLUDE_DIR)/vmlinux.h				\
		     $$(BPFOBJ) | $(TRUNNER_OUTPUT)
	$$(call $(TRUNNER_BPF_BUILD_RULE),$$<,$$@,			\
					  $(TRUNNER_BPF_CFLAGS),	\
+43 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2020 Facebook */

#include <test_progs.h>
#include <time.h>
#include "test_vmlinux.skel.h"

#define MY_TV_NSEC 1337

static void nsleep()
{
	struct timespec ts = { .tv_nsec = MY_TV_NSEC };

	(void)nanosleep(&ts, NULL);
}

void test_vmlinux(void)
{
	int duration = 0, err;
	struct test_vmlinux* skel;
	struct test_vmlinux__bss *bss;

	skel = test_vmlinux__open_and_load();
	if (CHECK(!skel, "skel_open", "failed to open skeleton\n"))
		return;
	bss = skel->bss;

	err = test_vmlinux__attach(skel);
	if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err))
		goto cleanup;

	/* trigger everything */
	nsleep();

	CHECK(!bss->tp_called, "tp", "not called\n");
	CHECK(!bss->raw_tp_called, "raw_tp", "not called\n");
	CHECK(!bss->tp_btf_called, "tp_btf", "not called\n");
	CHECK(!bss->kprobe_called, "kprobe", "not called\n");
	CHECK(!bss->fentry_called, "fentry", "not called\n");

cleanup:
	test_vmlinux__destroy(skel);
}
+84 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2020 Facebook */

#include "vmlinux.h"
#include <asm/unistd.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>

#define MY_TV_NSEC 1337

bool tp_called = false;
bool raw_tp_called = false;
bool tp_btf_called = false;
bool kprobe_called = false;
bool fentry_called = false;

SEC("tp/syscalls/sys_enter_nanosleep")
int handle__tp(struct trace_event_raw_sys_enter *args)
{
	struct __kernel_timespec *ts;

	if (args->id != __NR_nanosleep)
		return 0;

	ts = (void *)args->args[0];
	if (BPF_CORE_READ(ts, tv_nsec) != MY_TV_NSEC)
		return 0;

	tp_called = true;
	return 0;
}

SEC("raw_tp/sys_enter")
int BPF_PROG(handle__raw_tp, struct pt_regs *regs, long id)
{
	struct __kernel_timespec *ts;

	if (id != __NR_nanosleep)
		return 0;

	ts = (void *)PT_REGS_PARM1_CORE(regs);
	if (BPF_CORE_READ(ts, tv_nsec) != MY_TV_NSEC)
		return 0;

	raw_tp_called = true;
	return 0;
}

SEC("tp_btf/sys_enter")
int BPF_PROG(handle__tp_btf, struct pt_regs *regs, long id)
{
	struct __kernel_timespec *ts;

	if (id != __NR_nanosleep)
		return 0;

	ts = (void *)PT_REGS_PARM1_CORE(regs);
	if (BPF_CORE_READ(ts, tv_nsec) != MY_TV_NSEC)
		return 0;

	tp_btf_called = true;
	return 0;
}

SEC("kprobe/hrtimer_nanosleep")
int BPF_KPROBE(handle__kprobe,
	       ktime_t rqtp, enum hrtimer_mode mode, clockid_t clockid)
{
	if (rqtp == MY_TV_NSEC)
		kprobe_called = true;
	return 0;
}

SEC("fentry/hrtimer_nanosleep")
int BPF_PROG(handle__fentry,
	     ktime_t rqtp, enum hrtimer_mode mode, clockid_t clockid)
{
	if (rqtp == MY_TV_NSEC)
		fentry_called = true;
	return 0;
}

char _license[] SEC("license") = "GPL";