The tests check if ctx and data are correctly prepared from ctx_in and
data_in, so accessing the ctx and using the bpf_perf_prog_read_value
work as expected.
Signed-off-by: Krzesimir Nowak <[email protected]>
---
tools/testing/selftests/bpf/test_verifier.c | 48 ++++++++++
.../selftests/bpf/verifier/perf_event_run.c | 96 +++++++++++++++++++
2 files changed, 144 insertions(+)
create mode 100644 tools/testing/selftests/bpf/verifier/perf_event_run.c
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
index 6f124cc4ee34..484ea8842b06 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -295,6 +295,54 @@ static void bpf_fill_scale(struct bpf_test *self)
}
}
+static void bpf_fill_perf_event_test_run_check(struct bpf_test *self)
+{
+ compiletime_assert(
+ sizeof(struct bpf_perf_event_data) <= TEST_CTX_LEN,
+ "buffer for ctx is too short to fit struct bpf_perf_event_data");
+ compiletime_assert(
+ sizeof(struct bpf_perf_event_value) <= TEST_DATA_LEN,
+ "buffer for data is too short to fit struct bpf_perf_event_value");
+
+ struct bpf_perf_event_data ctx = {
+ .regs = (bpf_user_pt_regs_t) {
+ .r15 = 1,
+ .r14 = 2,
+ .r13 = 3,
+ .r12 = 4,
+ .rbp = 5,
+ .rbx = 6,
+ .r11 = 7,
+ .r10 = 8,
+ .r9 = 9,
+ .r8 = 10,
+ .rax = 11,
+ .rcx = 12,
+ .rdx = 13,
+ .rsi = 14,
+ .rdi = 15,
+ .orig_rax = 16,
+ .rip = 17,
+ .cs = 18,
+ .eflags = 19,
+ .rsp = 20,
+ .ss = 21,
+ },
+ .sample_period = 1,
+ .addr = 2,
+ };
+ struct bpf_perf_event_value data = {
+ .counter = 1,
+ .enabled = 2,
+ .running = 3,
+ };
+
+ memcpy(self->ctx, &ctx, sizeof(ctx));
+ memcpy(self->data, &data, sizeof(data));
+ free(self->fill_insns);
+ self->fill_insns = NULL;
+}
+
/* BPF_SK_LOOKUP contains 13 instructions, if you need to fix up maps */
#define BPF_SK_LOOKUP(func) \
/* struct bpf_sock_tuple tuple = {} */ \
diff --git a/tools/testing/selftests/bpf/verifier/perf_event_run.c b/tools/testing/selftests/bpf/verifier/perf_event_run.c
new file mode 100644
index 000000000000..3f877458a7f8
--- /dev/null
+++ b/tools/testing/selftests/bpf/verifier/perf_event_run.c
@@ -0,0 +1,96 @@
+#define PER_LOAD_AND_CHECK_PTREG(PT_REG_FIELD, VALUE) \
+ PER_LOAD_AND_CHECK_CTX(offsetof(bpf_user_pt_regs_t, PT_REG_FIELD), VALUE)
+#define PER_LOAD_AND_CHECK_EVENT(PED_FIELD, VALUE) \
+ PER_LOAD_AND_CHECK_CTX(offsetof(struct bpf_perf_event_data, PED_FIELD), VALUE)
+#define PER_LOAD_AND_CHECK_CTX(OFFSET, VALUE) \
+ PER_LOAD_AND_CHECK_64(BPF_REG_4, BPF_REG_1, OFFSET, VALUE)
+#define PER_LOAD_AND_CHECK_VALUE(PEV_FIELD, VALUE) \
+ PER_LOAD_AND_CHECK_64(BPF_REG_7, BPF_REG_6, offsetof(struct bpf_perf_event_value, PEV_FIELD), VALUE)
+#define PER_LOAD_AND_CHECK_64(DST, SRC, OFFSET, VALUE) \
+ BPF_LDX_MEM(BPF_DW, DST, SRC, OFFSET), \
+ BPF_JMP_IMM(BPF_JEQ, DST, VALUE, 2), \
+ BPF_MOV64_IMM(BPF_REG_0, VALUE), \
+ BPF_EXIT_INSN()
+
+{
+ "check if regs contain expected values",
+ .insns = {
+ PER_LOAD_AND_CHECK_PTREG(r15, 1),
+ PER_LOAD_AND_CHECK_PTREG(r14, 2),
+ PER_LOAD_AND_CHECK_PTREG(r13, 3),
+ PER_LOAD_AND_CHECK_PTREG(r12, 4),
+ PER_LOAD_AND_CHECK_PTREG(rbp, 5),
+ PER_LOAD_AND_CHECK_PTREG(rbx, 6),
+ PER_LOAD_AND_CHECK_PTREG(r11, 7),
+ PER_LOAD_AND_CHECK_PTREG(r10, 8),
+ PER_LOAD_AND_CHECK_PTREG(r9, 9),
+ PER_LOAD_AND_CHECK_PTREG(r8, 10),
+ PER_LOAD_AND_CHECK_PTREG(rax, 11),
+ PER_LOAD_AND_CHECK_PTREG(rcx, 12),
+ PER_LOAD_AND_CHECK_PTREG(rdx, 13),
+ PER_LOAD_AND_CHECK_PTREG(rsi, 14),
+ PER_LOAD_AND_CHECK_PTREG(rdi, 15),
+ PER_LOAD_AND_CHECK_PTREG(orig_rax, 16),
+ PER_LOAD_AND_CHECK_PTREG(rip, 17),
+ PER_LOAD_AND_CHECK_PTREG(cs, 18),
+ PER_LOAD_AND_CHECK_PTREG(eflags, 19),
+ PER_LOAD_AND_CHECK_PTREG(rsp, 20),
+ PER_LOAD_AND_CHECK_PTREG(ss, 21),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_PERF_EVENT,
+ .ctx_len = sizeof(struct bpf_perf_event_data),
+ .data_len = sizeof(struct bpf_perf_event_value),
+ .fill_helper = bpf_fill_perf_event_test_run_check,
+ .override_data_out_len = true,
+},
+{
+ "check if sample period and addr contain expected values",
+ .insns = {
+ PER_LOAD_AND_CHECK_EVENT(sample_period, 1),
+ PER_LOAD_AND_CHECK_EVENT(addr, 2),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_PERF_EVENT,
+ .ctx_len = sizeof(struct bpf_perf_event_data),
+ .data_len = sizeof(struct bpf_perf_event_value),
+ .fill_helper = bpf_fill_perf_event_test_run_check,
+ .override_data_out_len = true,
+},
+{
+ "check if bpf_perf_prog_read_value returns expected data",
+ .insns = {
+ // allocate space for a struct bpf_perf_event_value
+ BPF_MOV64_REG(BPF_REG_6, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, -(int)sizeof(struct bpf_perf_event_value)),
+ // prepare parameters for bpf_perf_prog_read_value(ctx, struct bpf_perf_event_value*, u32)
+ // BPF_REG_1 already contains the context
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
+ BPF_MOV64_IMM(BPF_REG_3, sizeof(struct bpf_perf_event_value)),
+ BPF_EMIT_CALL(BPF_FUNC_perf_prog_read_value),
+ // check the return value
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
+ BPF_EXIT_INSN(),
+ // check if the fields match the expected values
+ PER_LOAD_AND_CHECK_VALUE(counter, 1),
+ PER_LOAD_AND_CHECK_VALUE(enabled, 2),
+ PER_LOAD_AND_CHECK_VALUE(running, 3),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ .prog_type = BPF_PROG_TYPE_PERF_EVENT,
+ .ctx_len = sizeof(struct bpf_perf_event_data),
+ .data_len = sizeof(struct bpf_perf_event_value),
+ .fill_helper = bpf_fill_perf_event_test_run_check,
+ .override_data_out_len = true,
+},
+#undef PER_LOAD_AND_CHECK_64
+#undef PER_LOAD_AND_CHECK_VALUE
+#undef PER_LOAD_AND_CHECK_CTX
+#undef PER_LOAD_AND_CHECK_EVENT
+#undef PER_LOAD_AND_CHECK_PTREG
--
2.20.1
On Mon, Jul 8, 2019 at 3:42 PM Krzesimir Nowak <[email protected]> wrote:
>
> The tests check if ctx and data are correctly prepared from ctx_in and
> data_in, so accessing the ctx and using the bpf_perf_prog_read_value
> work as expected.
>
These are x86_64-specific tests, aren't they? Should probably guard
them behind #ifdef's.
> Signed-off-by: Krzesimir Nowak <[email protected]>
> ---
> tools/testing/selftests/bpf/test_verifier.c | 48 ++++++++++
> .../selftests/bpf/verifier/perf_event_run.c | 96 +++++++++++++++++++
> 2 files changed, 144 insertions(+)
> create mode 100644 tools/testing/selftests/bpf/verifier/perf_event_run.c
>
> diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
> index 6f124cc4ee34..484ea8842b06 100644
> --- a/tools/testing/selftests/bpf/test_verifier.c
> +++ b/tools/testing/selftests/bpf/test_verifier.c
> @@ -295,6 +295,54 @@ static void bpf_fill_scale(struct bpf_test *self)
> }
> }
>
> +static void bpf_fill_perf_event_test_run_check(struct bpf_test *self)
> +{
> + compiletime_assert(
> + sizeof(struct bpf_perf_event_data) <= TEST_CTX_LEN,
> + "buffer for ctx is too short to fit struct bpf_perf_event_data");
> + compiletime_assert(
> + sizeof(struct bpf_perf_event_value) <= TEST_DATA_LEN,
> + "buffer for data is too short to fit struct bpf_perf_event_value");
> +
> + struct bpf_perf_event_data ctx = {
> + .regs = (bpf_user_pt_regs_t) {
> + .r15 = 1,
> + .r14 = 2,
> + .r13 = 3,
> + .r12 = 4,
> + .rbp = 5,
> + .rbx = 6,
> + .r11 = 7,
> + .r10 = 8,
> + .r9 = 9,
> + .r8 = 10,
> + .rax = 11,
> + .rcx = 12,
> + .rdx = 13,
> + .rsi = 14,
> + .rdi = 15,
> + .orig_rax = 16,
> + .rip = 17,
> + .cs = 18,
> + .eflags = 19,
> + .rsp = 20,
> + .ss = 21,
> + },
> + .sample_period = 1,
> + .addr = 2,
> + };
> + struct bpf_perf_event_value data = {
> + .counter = 1,
> + .enabled = 2,
> + .running = 3,
> + };
> +
> + memcpy(self->ctx, &ctx, sizeof(ctx));
> + memcpy(self->data, &data, sizeof(data));
Just curious, just assignment didn't work?
> + free(self->fill_insns);
> + self->fill_insns = NULL;
> +}
> +
> /* BPF_SK_LOOKUP contains 13 instructions, if you need to fix up maps */
> #define BPF_SK_LOOKUP(func) \
> /* struct bpf_sock_tuple tuple = {} */ \
> diff --git a/tools/testing/selftests/bpf/verifier/perf_event_run.c b/tools/testing/selftests/bpf/verifier/perf_event_run.c
> new file mode 100644
> index 000000000000..3f877458a7f8
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/verifier/perf_event_run.c
> @@ -0,0 +1,96 @@
> +#define PER_LOAD_AND_CHECK_PTREG(PT_REG_FIELD, VALUE) \
> + PER_LOAD_AND_CHECK_CTX(offsetof(bpf_user_pt_regs_t, PT_REG_FIELD), VALUE)
> +#define PER_LOAD_AND_CHECK_EVENT(PED_FIELD, VALUE) \
> + PER_LOAD_AND_CHECK_CTX(offsetof(struct bpf_perf_event_data, PED_FIELD), VALUE)
> +#define PER_LOAD_AND_CHECK_CTX(OFFSET, VALUE) \
> + PER_LOAD_AND_CHECK_64(BPF_REG_4, BPF_REG_1, OFFSET, VALUE)
> +#define PER_LOAD_AND_CHECK_VALUE(PEV_FIELD, VALUE) \
> + PER_LOAD_AND_CHECK_64(BPF_REG_7, BPF_REG_6, offsetof(struct bpf_perf_event_value, PEV_FIELD), VALUE)
Wrap long lines? Try also running scripts/checkpatch.pl again these
files you are modifying.
> +#define PER_LOAD_AND_CHECK_64(DST, SRC, OFFSET, VALUE) \
> + BPF_LDX_MEM(BPF_DW, DST, SRC, OFFSET), \
> + BPF_JMP_IMM(BPF_JEQ, DST, VALUE, 2), \
> + BPF_MOV64_IMM(BPF_REG_0, VALUE), \
> + BPF_EXIT_INSN()
> +
> +{
> + "check if regs contain expected values",
> + .insns = {
> + PER_LOAD_AND_CHECK_PTREG(r15, 1),
> + PER_LOAD_AND_CHECK_PTREG(r14, 2),
> + PER_LOAD_AND_CHECK_PTREG(r13, 3),
> + PER_LOAD_AND_CHECK_PTREG(r12, 4),
> + PER_LOAD_AND_CHECK_PTREG(rbp, 5),
> + PER_LOAD_AND_CHECK_PTREG(rbx, 6),
> + PER_LOAD_AND_CHECK_PTREG(r11, 7),
> + PER_LOAD_AND_CHECK_PTREG(r10, 8),
> + PER_LOAD_AND_CHECK_PTREG(r9, 9),
> + PER_LOAD_AND_CHECK_PTREG(r8, 10),
> + PER_LOAD_AND_CHECK_PTREG(rax, 11),
> + PER_LOAD_AND_CHECK_PTREG(rcx, 12),
> + PER_LOAD_AND_CHECK_PTREG(rdx, 13),
> + PER_LOAD_AND_CHECK_PTREG(rsi, 14),
> + PER_LOAD_AND_CHECK_PTREG(rdi, 15),
> + PER_LOAD_AND_CHECK_PTREG(orig_rax, 16),
> + PER_LOAD_AND_CHECK_PTREG(rip, 17),
> + PER_LOAD_AND_CHECK_PTREG(cs, 18),
> + PER_LOAD_AND_CHECK_PTREG(eflags, 19),
> + PER_LOAD_AND_CHECK_PTREG(rsp, 20),
> + PER_LOAD_AND_CHECK_PTREG(ss, 21),
> + BPF_MOV64_IMM(BPF_REG_0, 0),
> + BPF_EXIT_INSN(),
> + },
> + .result = ACCEPT,
> + .prog_type = BPF_PROG_TYPE_PERF_EVENT,
> + .ctx_len = sizeof(struct bpf_perf_event_data),
> + .data_len = sizeof(struct bpf_perf_event_value),
> + .fill_helper = bpf_fill_perf_event_test_run_check,
> + .override_data_out_len = true,
> +},
> +{
> + "check if sample period and addr contain expected values",
> + .insns = {
> + PER_LOAD_AND_CHECK_EVENT(sample_period, 1),
> + PER_LOAD_AND_CHECK_EVENT(addr, 2),
> + BPF_MOV64_IMM(BPF_REG_0, 0),
> + BPF_EXIT_INSN(),
> + },
> + .result = ACCEPT,
> + .prog_type = BPF_PROG_TYPE_PERF_EVENT,
> + .ctx_len = sizeof(struct bpf_perf_event_data),
> + .data_len = sizeof(struct bpf_perf_event_value),
> + .fill_helper = bpf_fill_perf_event_test_run_check,
> + .override_data_out_len = true,
> +},
> +{
> + "check if bpf_perf_prog_read_value returns expected data",
> + .insns = {
> + // allocate space for a struct bpf_perf_event_value
> + BPF_MOV64_REG(BPF_REG_6, BPF_REG_10),
> + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, -(int)sizeof(struct bpf_perf_event_value)),
> + // prepare parameters for bpf_perf_prog_read_value(ctx, struct bpf_perf_event_value*, u32)
> + // BPF_REG_1 already contains the context
> + BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
> + BPF_MOV64_IMM(BPF_REG_3, sizeof(struct bpf_perf_event_value)),
> + BPF_EMIT_CALL(BPF_FUNC_perf_prog_read_value),
> + // check the return value
> + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
> + BPF_EXIT_INSN(),
> + // check if the fields match the expected values
Use /* */ comments.
> + PER_LOAD_AND_CHECK_VALUE(counter, 1),
> + PER_LOAD_AND_CHECK_VALUE(enabled, 2),
> + PER_LOAD_AND_CHECK_VALUE(running, 3),
> + BPF_MOV64_IMM(BPF_REG_0, 0),
> + BPF_EXIT_INSN(),
> + },
> + .result = ACCEPT,
> + .prog_type = BPF_PROG_TYPE_PERF_EVENT,
> + .ctx_len = sizeof(struct bpf_perf_event_data),
> + .data_len = sizeof(struct bpf_perf_event_value),
> + .fill_helper = bpf_fill_perf_event_test_run_check,
> + .override_data_out_len = true,
> +},
> +#undef PER_LOAD_AND_CHECK_64
> +#undef PER_LOAD_AND_CHECK_VALUE
> +#undef PER_LOAD_AND_CHECK_CTX
> +#undef PER_LOAD_AND_CHECK_EVENT
> +#undef PER_LOAD_AND_CHECK_PTREG
> --
> 2.20.1
>
On Fri, Jul 12, 2019 at 2:38 AM Andrii Nakryiko
<[email protected]> wrote:
>
> On Mon, Jul 8, 2019 at 3:42 PM Krzesimir Nowak <[email protected]> wrote:
> >
> > The tests check if ctx and data are correctly prepared from ctx_in and
> > data_in, so accessing the ctx and using the bpf_perf_prog_read_value
> > work as expected.
> >
>
> These are x86_64-specific tests, aren't they? Should probably guard
> them behind #ifdef's.
Yeah, they are x86_64 specific, because pt_regs are arch specific. I
was wondering what to do here in the cover letter. Ifdef? Ifdef and
cover also other arches (please no)? Do some weird tricks with
overriding the definition of pt_regs? Else?
>
> > Signed-off-by: Krzesimir Nowak <[email protected]>
> > ---
> > tools/testing/selftests/bpf/test_verifier.c | 48 ++++++++++
> > .../selftests/bpf/verifier/perf_event_run.c | 96 +++++++++++++++++++
> > 2 files changed, 144 insertions(+)
> > create mode 100644 tools/testing/selftests/bpf/verifier/perf_event_run.c
> >
> > diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
> > index 6f124cc4ee34..484ea8842b06 100644
> > --- a/tools/testing/selftests/bpf/test_verifier.c
> > +++ b/tools/testing/selftests/bpf/test_verifier.c
> > @@ -295,6 +295,54 @@ static void bpf_fill_scale(struct bpf_test *self)
> > }
> > }
> >
> > +static void bpf_fill_perf_event_test_run_check(struct bpf_test *self)
> > +{
> > + compiletime_assert(
> > + sizeof(struct bpf_perf_event_data) <= TEST_CTX_LEN,
> > + "buffer for ctx is too short to fit struct bpf_perf_event_data");
> > + compiletime_assert(
> > + sizeof(struct bpf_perf_event_value) <= TEST_DATA_LEN,
> > + "buffer for data is too short to fit struct bpf_perf_event_value");
> > +
> > + struct bpf_perf_event_data ctx = {
> > + .regs = (bpf_user_pt_regs_t) {
> > + .r15 = 1,
> > + .r14 = 2,
> > + .r13 = 3,
> > + .r12 = 4,
> > + .rbp = 5,
> > + .rbx = 6,
> > + .r11 = 7,
> > + .r10 = 8,
> > + .r9 = 9,
> > + .r8 = 10,
> > + .rax = 11,
> > + .rcx = 12,
> > + .rdx = 13,
> > + .rsi = 14,
> > + .rdi = 15,
> > + .orig_rax = 16,
> > + .rip = 17,
> > + .cs = 18,
> > + .eflags = 19,
> > + .rsp = 20,
> > + .ss = 21,
> > + },
> > + .sample_period = 1,
> > + .addr = 2,
> > + };
> > + struct bpf_perf_event_value data = {
> > + .counter = 1,
> > + .enabled = 2,
> > + .running = 3,
> > + };
> > +
> > + memcpy(self->ctx, &ctx, sizeof(ctx));
> > + memcpy(self->data, &data, sizeof(data));
>
> Just curious, just assignment didn't work?
>
> > + free(self->fill_insns);
> > + self->fill_insns = NULL;
> > +}
> > +
> > /* BPF_SK_LOOKUP contains 13 instructions, if you need to fix up maps */
> > #define BPF_SK_LOOKUP(func) \
> > /* struct bpf_sock_tuple tuple = {} */ \
> > diff --git a/tools/testing/selftests/bpf/verifier/perf_event_run.c b/tools/testing/selftests/bpf/verifier/perf_event_run.c
> > new file mode 100644
> > index 000000000000..3f877458a7f8
> > --- /dev/null
> > +++ b/tools/testing/selftests/bpf/verifier/perf_event_run.c
> > @@ -0,0 +1,96 @@
> > +#define PER_LOAD_AND_CHECK_PTREG(PT_REG_FIELD, VALUE) \
> > + PER_LOAD_AND_CHECK_CTX(offsetof(bpf_user_pt_regs_t, PT_REG_FIELD), VALUE)
> > +#define PER_LOAD_AND_CHECK_EVENT(PED_FIELD, VALUE) \
> > + PER_LOAD_AND_CHECK_CTX(offsetof(struct bpf_perf_event_data, PED_FIELD), VALUE)
> > +#define PER_LOAD_AND_CHECK_CTX(OFFSET, VALUE) \
> > + PER_LOAD_AND_CHECK_64(BPF_REG_4, BPF_REG_1, OFFSET, VALUE)
> > +#define PER_LOAD_AND_CHECK_VALUE(PEV_FIELD, VALUE) \
> > + PER_LOAD_AND_CHECK_64(BPF_REG_7, BPF_REG_6, offsetof(struct bpf_perf_event_value, PEV_FIELD), VALUE)
>
> Wrap long lines? Try also running scripts/checkpatch.pl again these
> files you are modifying.
Will wrap. Checkpatch was also complaining about complex macro not
being inside parens, but I can't see how to wrap it in parens and keep
it working at the same time.
>
> > +#define PER_LOAD_AND_CHECK_64(DST, SRC, OFFSET, VALUE) \
> > + BPF_LDX_MEM(BPF_DW, DST, SRC, OFFSET), \
> > + BPF_JMP_IMM(BPF_JEQ, DST, VALUE, 2), \
> > + BPF_MOV64_IMM(BPF_REG_0, VALUE), \
> > + BPF_EXIT_INSN()
> > +
> > +{
> > + "check if regs contain expected values",
> > + .insns = {
> > + PER_LOAD_AND_CHECK_PTREG(r15, 1),
> > + PER_LOAD_AND_CHECK_PTREG(r14, 2),
> > + PER_LOAD_AND_CHECK_PTREG(r13, 3),
> > + PER_LOAD_AND_CHECK_PTREG(r12, 4),
> > + PER_LOAD_AND_CHECK_PTREG(rbp, 5),
> > + PER_LOAD_AND_CHECK_PTREG(rbx, 6),
> > + PER_LOAD_AND_CHECK_PTREG(r11, 7),
> > + PER_LOAD_AND_CHECK_PTREG(r10, 8),
> > + PER_LOAD_AND_CHECK_PTREG(r9, 9),
> > + PER_LOAD_AND_CHECK_PTREG(r8, 10),
> > + PER_LOAD_AND_CHECK_PTREG(rax, 11),
> > + PER_LOAD_AND_CHECK_PTREG(rcx, 12),
> > + PER_LOAD_AND_CHECK_PTREG(rdx, 13),
> > + PER_LOAD_AND_CHECK_PTREG(rsi, 14),
> > + PER_LOAD_AND_CHECK_PTREG(rdi, 15),
> > + PER_LOAD_AND_CHECK_PTREG(orig_rax, 16),
> > + PER_LOAD_AND_CHECK_PTREG(rip, 17),
> > + PER_LOAD_AND_CHECK_PTREG(cs, 18),
> > + PER_LOAD_AND_CHECK_PTREG(eflags, 19),
> > + PER_LOAD_AND_CHECK_PTREG(rsp, 20),
> > + PER_LOAD_AND_CHECK_PTREG(ss, 21),
> > + BPF_MOV64_IMM(BPF_REG_0, 0),
> > + BPF_EXIT_INSN(),
> > + },
> > + .result = ACCEPT,
> > + .prog_type = BPF_PROG_TYPE_PERF_EVENT,
> > + .ctx_len = sizeof(struct bpf_perf_event_data),
> > + .data_len = sizeof(struct bpf_perf_event_value),
> > + .fill_helper = bpf_fill_perf_event_test_run_check,
> > + .override_data_out_len = true,
> > +},
> > +{
> > + "check if sample period and addr contain expected values",
> > + .insns = {
> > + PER_LOAD_AND_CHECK_EVENT(sample_period, 1),
> > + PER_LOAD_AND_CHECK_EVENT(addr, 2),
> > + BPF_MOV64_IMM(BPF_REG_0, 0),
> > + BPF_EXIT_INSN(),
> > + },
> > + .result = ACCEPT,
> > + .prog_type = BPF_PROG_TYPE_PERF_EVENT,
> > + .ctx_len = sizeof(struct bpf_perf_event_data),
> > + .data_len = sizeof(struct bpf_perf_event_value),
> > + .fill_helper = bpf_fill_perf_event_test_run_check,
> > + .override_data_out_len = true,
> > +},
> > +{
> > + "check if bpf_perf_prog_read_value returns expected data",
> > + .insns = {
> > + // allocate space for a struct bpf_perf_event_value
> > + BPF_MOV64_REG(BPF_REG_6, BPF_REG_10),
> > + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, -(int)sizeof(struct bpf_perf_event_value)),
> > + // prepare parameters for bpf_perf_prog_read_value(ctx, struct bpf_perf_event_value*, u32)
> > + // BPF_REG_1 already contains the context
> > + BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
> > + BPF_MOV64_IMM(BPF_REG_3, sizeof(struct bpf_perf_event_value)),
> > + BPF_EMIT_CALL(BPF_FUNC_perf_prog_read_value),
> > + // check the return value
> > + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
> > + BPF_EXIT_INSN(),
> > + // check if the fields match the expected values
>
> Use /* */ comments.
Oops. Will fix.
>
> > + PER_LOAD_AND_CHECK_VALUE(counter, 1),
> > + PER_LOAD_AND_CHECK_VALUE(enabled, 2),
> > + PER_LOAD_AND_CHECK_VALUE(running, 3),
> > + BPF_MOV64_IMM(BPF_REG_0, 0),
> > + BPF_EXIT_INSN(),
> > + },
> > + .result = ACCEPT,
> > + .prog_type = BPF_PROG_TYPE_PERF_EVENT,
> > + .ctx_len = sizeof(struct bpf_perf_event_data),
> > + .data_len = sizeof(struct bpf_perf_event_value),
> > + .fill_helper = bpf_fill_perf_event_test_run_check,
> > + .override_data_out_len = true,
> > +},
> > +#undef PER_LOAD_AND_CHECK_64
> > +#undef PER_LOAD_AND_CHECK_VALUE
> > +#undef PER_LOAD_AND_CHECK_CTX
> > +#undef PER_LOAD_AND_CHECK_EVENT
> > +#undef PER_LOAD_AND_CHECK_PTREG
> > --
> > 2.20.1
> >
--
Kinvolk GmbH | Adalbertstr.6a, 10999 Berlin | tel: +491755589364
Geschäftsführer/Directors: Alban Crequy, Chris Kühl, Iago López Galeiras
Registergericht/Court of registration: Amtsgericht Charlottenburg
Registernummer/Registration number: HRB 171414 B
Ust-ID-Nummer/VAT ID number: DE302207000
On Fri, Jul 12, 2019 at 10:37 AM Krzesimir Nowak <[email protected]> wrote:
>
> On Fri, Jul 12, 2019 at 2:38 AM Andrii Nakryiko
> <[email protected]> wrote:
> >
> > On Mon, Jul 8, 2019 at 3:42 PM Krzesimir Nowak <[email protected]> wrote:
> > >
> > > The tests check if ctx and data are correctly prepared from ctx_in and
> > > data_in, so accessing the ctx and using the bpf_perf_prog_read_value
> > > work as expected.
> > >
> >
> > These are x86_64-specific tests, aren't they? Should probably guard
> > them behind #ifdef's.
>
> Yeah, they are x86_64 specific, because pt_regs are arch specific. I
> was wondering what to do here in the cover letter. Ifdef? Ifdef and
> cover also other arches (please no)? Do some weird tricks with
> overriding the definition of pt_regs? Else?
So one way to go about this would be to use bpf_helpers.h's
PT_REGS_PARM{1-5} and PT_REGS_RC, which seem to be define for all
"supported" platforms. You won't be testing all possible registers,
but those that are most commonly used by BPF programs (to get input
params and func result) would be tested, which is probably the most
important one. That way your test will be arch-agnostic.
>
> >
> > > Signed-off-by: Krzesimir Nowak <[email protected]>
> > > ---
> > > tools/testing/selftests/bpf/test_verifier.c | 48 ++++++++++
> > > .../selftests/bpf/verifier/perf_event_run.c | 96 +++++++++++++++++++
> > > 2 files changed, 144 insertions(+)
> > > create mode 100644 tools/testing/selftests/bpf/verifier/perf_event_run.c
> > >
> > > diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
> > > index 6f124cc4ee34..484ea8842b06 100644
> > > --- a/tools/testing/selftests/bpf/test_verifier.c
> > > +++ b/tools/testing/selftests/bpf/test_verifier.c
> > > @@ -295,6 +295,54 @@ static void bpf_fill_scale(struct bpf_test *self)
> > > }
> > > }
> > >
> > > +static void bpf_fill_perf_event_test_run_check(struct bpf_test *self)
> > > +{
> > > + compiletime_assert(
> > > + sizeof(struct bpf_perf_event_data) <= TEST_CTX_LEN,
> > > + "buffer for ctx is too short to fit struct bpf_perf_event_data");
> > > + compiletime_assert(
> > > + sizeof(struct bpf_perf_event_value) <= TEST_DATA_LEN,
> > > + "buffer for data is too short to fit struct bpf_perf_event_value");
> > > +
> > > + struct bpf_perf_event_data ctx = {
> > > + .regs = (bpf_user_pt_regs_t) {
> > > + .r15 = 1,
> > > + .r14 = 2,
> > > + .r13 = 3,
> > > + .r12 = 4,
> > > + .rbp = 5,
> > > + .rbx = 6,
> > > + .r11 = 7,
> > > + .r10 = 8,
> > > + .r9 = 9,
> > > + .r8 = 10,
> > > + .rax = 11,
> > > + .rcx = 12,
> > > + .rdx = 13,
> > > + .rsi = 14,
> > > + .rdi = 15,
> > > + .orig_rax = 16,
> > > + .rip = 17,
> > > + .cs = 18,
> > > + .eflags = 19,
> > > + .rsp = 20,
> > > + .ss = 21,
> > > + },
> > > + .sample_period = 1,
> > > + .addr = 2,
> > > + };
> > > + struct bpf_perf_event_value data = {
> > > + .counter = 1,
> > > + .enabled = 2,
> > > + .running = 3,
> > > + };
> > > +
> > > + memcpy(self->ctx, &ctx, sizeof(ctx));
> > > + memcpy(self->data, &data, sizeof(data));
> >
> > Just curious, just assignment didn't work?
> >
> > > + free(self->fill_insns);
> > > + self->fill_insns = NULL;
> > > +}
> > > +
> > > /* BPF_SK_LOOKUP contains 13 instructions, if you need to fix up maps */
> > > #define BPF_SK_LOOKUP(func) \
> > > /* struct bpf_sock_tuple tuple = {} */ \
> > > diff --git a/tools/testing/selftests/bpf/verifier/perf_event_run.c b/tools/testing/selftests/bpf/verifier/perf_event_run.c
> > > new file mode 100644
> > > index 000000000000..3f877458a7f8
> > > --- /dev/null
> > > +++ b/tools/testing/selftests/bpf/verifier/perf_event_run.c
> > > @@ -0,0 +1,96 @@
> > > +#define PER_LOAD_AND_CHECK_PTREG(PT_REG_FIELD, VALUE) \
> > > + PER_LOAD_AND_CHECK_CTX(offsetof(bpf_user_pt_regs_t, PT_REG_FIELD), VALUE)
> > > +#define PER_LOAD_AND_CHECK_EVENT(PED_FIELD, VALUE) \
> > > + PER_LOAD_AND_CHECK_CTX(offsetof(struct bpf_perf_event_data, PED_FIELD), VALUE)
> > > +#define PER_LOAD_AND_CHECK_CTX(OFFSET, VALUE) \
> > > + PER_LOAD_AND_CHECK_64(BPF_REG_4, BPF_REG_1, OFFSET, VALUE)
> > > +#define PER_LOAD_AND_CHECK_VALUE(PEV_FIELD, VALUE) \
> > > + PER_LOAD_AND_CHECK_64(BPF_REG_7, BPF_REG_6, offsetof(struct bpf_perf_event_value, PEV_FIELD), VALUE)
> >
> > Wrap long lines? Try also running scripts/checkpatch.pl again these
> > files you are modifying.
>
> Will wrap. Checkpatch was also complaining about complex macro not
> being inside parens, but I can't see how to wrap it in parens and keep
> it working at the same time.
>
> >
> > > +#define PER_LOAD_AND_CHECK_64(DST, SRC, OFFSET, VALUE) \
> > > + BPF_LDX_MEM(BPF_DW, DST, SRC, OFFSET), \
> > > + BPF_JMP_IMM(BPF_JEQ, DST, VALUE, 2), \
> > > + BPF_MOV64_IMM(BPF_REG_0, VALUE), \
> > > + BPF_EXIT_INSN()
> > > +
> > > +{
> > > + "check if regs contain expected values",
> > > + .insns = {
> > > + PER_LOAD_AND_CHECK_PTREG(r15, 1),
> > > + PER_LOAD_AND_CHECK_PTREG(r14, 2),
> > > + PER_LOAD_AND_CHECK_PTREG(r13, 3),
> > > + PER_LOAD_AND_CHECK_PTREG(r12, 4),
> > > + PER_LOAD_AND_CHECK_PTREG(rbp, 5),
> > > + PER_LOAD_AND_CHECK_PTREG(rbx, 6),
> > > + PER_LOAD_AND_CHECK_PTREG(r11, 7),
> > > + PER_LOAD_AND_CHECK_PTREG(r10, 8),
> > > + PER_LOAD_AND_CHECK_PTREG(r9, 9),
> > > + PER_LOAD_AND_CHECK_PTREG(r8, 10),
> > > + PER_LOAD_AND_CHECK_PTREG(rax, 11),
> > > + PER_LOAD_AND_CHECK_PTREG(rcx, 12),
> > > + PER_LOAD_AND_CHECK_PTREG(rdx, 13),
> > > + PER_LOAD_AND_CHECK_PTREG(rsi, 14),
> > > + PER_LOAD_AND_CHECK_PTREG(rdi, 15),
> > > + PER_LOAD_AND_CHECK_PTREG(orig_rax, 16),
> > > + PER_LOAD_AND_CHECK_PTREG(rip, 17),
> > > + PER_LOAD_AND_CHECK_PTREG(cs, 18),
> > > + PER_LOAD_AND_CHECK_PTREG(eflags, 19),
> > > + PER_LOAD_AND_CHECK_PTREG(rsp, 20),
> > > + PER_LOAD_AND_CHECK_PTREG(ss, 21),
> > > + BPF_MOV64_IMM(BPF_REG_0, 0),
> > > + BPF_EXIT_INSN(),
> > > + },
> > > + .result = ACCEPT,
> > > + .prog_type = BPF_PROG_TYPE_PERF_EVENT,
> > > + .ctx_len = sizeof(struct bpf_perf_event_data),
> > > + .data_len = sizeof(struct bpf_perf_event_value),
> > > + .fill_helper = bpf_fill_perf_event_test_run_check,
> > > + .override_data_out_len = true,
> > > +},
> > > +{
> > > + "check if sample period and addr contain expected values",
> > > + .insns = {
> > > + PER_LOAD_AND_CHECK_EVENT(sample_period, 1),
> > > + PER_LOAD_AND_CHECK_EVENT(addr, 2),
> > > + BPF_MOV64_IMM(BPF_REG_0, 0),
> > > + BPF_EXIT_INSN(),
> > > + },
> > > + .result = ACCEPT,
> > > + .prog_type = BPF_PROG_TYPE_PERF_EVENT,
> > > + .ctx_len = sizeof(struct bpf_perf_event_data),
> > > + .data_len = sizeof(struct bpf_perf_event_value),
> > > + .fill_helper = bpf_fill_perf_event_test_run_check,
> > > + .override_data_out_len = true,
> > > +},
> > > +{
> > > + "check if bpf_perf_prog_read_value returns expected data",
> > > + .insns = {
> > > + // allocate space for a struct bpf_perf_event_value
> > > + BPF_MOV64_REG(BPF_REG_6, BPF_REG_10),
> > > + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, -(int)sizeof(struct bpf_perf_event_value)),
> > > + // prepare parameters for bpf_perf_prog_read_value(ctx, struct bpf_perf_event_value*, u32)
> > > + // BPF_REG_1 already contains the context
> > > + BPF_MOV64_REG(BPF_REG_2, BPF_REG_6),
> > > + BPF_MOV64_IMM(BPF_REG_3, sizeof(struct bpf_perf_event_value)),
> > > + BPF_EMIT_CALL(BPF_FUNC_perf_prog_read_value),
> > > + // check the return value
> > > + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
> > > + BPF_EXIT_INSN(),
> > > + // check if the fields match the expected values
> >
> > Use /* */ comments.
>
> Oops. Will fix.
>
> >
> > > + PER_LOAD_AND_CHECK_VALUE(counter, 1),
> > > + PER_LOAD_AND_CHECK_VALUE(enabled, 2),
> > > + PER_LOAD_AND_CHECK_VALUE(running, 3),
> > > + BPF_MOV64_IMM(BPF_REG_0, 0),
> > > + BPF_EXIT_INSN(),
> > > + },
> > > + .result = ACCEPT,
> > > + .prog_type = BPF_PROG_TYPE_PERF_EVENT,
> > > + .ctx_len = sizeof(struct bpf_perf_event_data),
> > > + .data_len = sizeof(struct bpf_perf_event_value),
> > > + .fill_helper = bpf_fill_perf_event_test_run_check,
> > > + .override_data_out_len = true,
> > > +},
> > > +#undef PER_LOAD_AND_CHECK_64
> > > +#undef PER_LOAD_AND_CHECK_VALUE
> > > +#undef PER_LOAD_AND_CHECK_CTX
> > > +#undef PER_LOAD_AND_CHECK_EVENT
> > > +#undef PER_LOAD_AND_CHECK_PTREG
> > > --
> > > 2.20.1
> > >
>
>
>
> --
> Kinvolk GmbH | Adalbertstr.6a, 10999 Berlin | tel: +491755589364
> Geschäftsführer/Directors: Alban Crequy, Chris Kühl, Iago López Galeiras
> Registergericht/Court of registration: Amtsgericht Charlottenburg
> Registernummer/Registration number: HRB 171414 B
> Ust-ID-Nummer/VAT ID number: DE302207000