From: Eduard Zingerman <eddyz87@gmail.com>
To: bpf@vger.kernel.org, ast@kernel.org
Cc: andrii@kernel.org, daniel@iogearbox.net, martin.lau@linux.dev,
kernel-team@fb.com, yonghong.song@linux.dev, hffilwlqm@gmail.com,
Eduard Zingerman <eddyz87@gmail.com>
Subject: [PATCH bpf-next 3/4] selftests/bpf: __jited_x86 test tag to check x86 assembly after jit
Date: Thu, 8 Aug 2024 18:05:17 -0700 [thread overview]
Message-ID: <20240809010518.1137758-4-eddyz87@gmail.com> (raw)
In-Reply-To: <20240809010518.1137758-1-eddyz87@gmail.com>
Allow to verify jit behaviour by writing tests as below:
SEC("tp")
__jit_x86("endbr64")
__jit_x86("movabs $0x.*,%r9")
__jit_x86("add %gs:0x.*,%r9")
__jit_x86("mov $0x1,%edi")
__jit_x86("mov %rdi,-0x8(%r9)")
__jit_x86("mov -0x8(%r9),%rdi")
__jit_x86("xor %eax,%eax")
__jit_x86("lock xchg %rax,-0x8(%r9)")
__jit_x86("lock xadd %rax,-0x8(%r9)")
__naked void stack_access_insns(void)
{
asm volatile (... ::: __clobber_all);
}
Use regular expressions by default, use basic regular expressions
class in order to avoid escaping symbols like $(), often used in AT&T
disassembly syntax.
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
---
tools/testing/selftests/bpf/progs/bpf_misc.h | 2 +
tools/testing/selftests/bpf/test_loader.c | 156 +++++++++++++------
2 files changed, 112 insertions(+), 46 deletions(-)
diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h
index a225cd87897c..06e353a0a5b1 100644
--- a/tools/testing/selftests/bpf/progs/bpf_misc.h
+++ b/tools/testing/selftests/bpf/progs/bpf_misc.h
@@ -90,6 +90,8 @@
#define __arch_x86_64 __arch("X86_64")
#define __arch_arm64 __arch("ARM64")
#define __arch_riscv64 __arch("RISCV64")
+#define __jit_x86(basic_regex) __attribute__((btf_decl_tag("comment:test_jit_x86=" basic_regex)))
+#define __jit_x86_unpriv(basic_regex) __attribute__((btf_decl_tag("comment:test_jit_x86_unpriv=" basic_regex)))
/* Convenience macro for use with 'asm volatile' blocks */
#define __naked __attribute__((naked))
diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c
index 1b1290e090e7..7d8a0cf9904a 100644
--- a/tools/testing/selftests/bpf/test_loader.c
+++ b/tools/testing/selftests/bpf/test_loader.c
@@ -10,6 +10,7 @@
#include "disasm_helpers.h"
#include "unpriv_helpers.h"
#include "cap_helpers.h"
+#include "jit_disasm_helpers.h"
#define str_has_pfx(str, pfx) \
(strncmp(str, pfx, __builtin_constant_p(pfx) ? sizeof(pfx) - 1 : strlen(pfx)) == 0)
@@ -35,6 +36,8 @@
#define TEST_TAG_AUXILIARY_UNPRIV "comment:test_auxiliary_unpriv"
#define TEST_BTF_PATH "comment:test_btf_path="
#define TEST_TAG_ARCH "comment:test_arch="
+#define TEST_TAG_JIT_X86_PFX "comment:test_jit_x86="
+#define TEST_TAG_JIT_X86_PFX_UNPRIV "comment:test_jit_x86_unpriv="
/* Warning: duplicated in bpf_misc.h */
#define POINTER_VALUE 0xcafe4all
@@ -53,10 +56,18 @@ enum mode {
UNPRIV = 2
};
+enum arch {
+ ARCH_X86_64 = 1,
+ ARCH_ARM64 = 2,
+ ARCH_RISCV64 = 3,
+ ARCH_MAX
+};
+
struct expect_msg {
const char *substr; /* substring match */
const char *regex_str; /* regex-based match */
regex_t regex;
+ int regex_flags;
};
struct expected_msgs {
@@ -69,6 +80,7 @@ struct test_subspec {
bool expect_failure;
struct expected_msgs expect_msgs;
struct expected_msgs expect_xlated;
+ struct expected_msgs jited[ARCH_MAX];
int retval;
bool execute;
};
@@ -120,11 +132,17 @@ static void free_msgs(struct expected_msgs *msgs)
static void free_test_spec(struct test_spec *spec)
{
+ int i;
+
/* Deallocate expect_msgs arrays. */
free_msgs(&spec->priv.expect_msgs);
free_msgs(&spec->unpriv.expect_msgs);
free_msgs(&spec->priv.expect_xlated);
free_msgs(&spec->unpriv.expect_xlated);
+ for (i = 0; i < ARCH_MAX; ++i) {
+ free_msgs(&spec->priv.jited[i]);
+ free_msgs(&spec->unpriv.jited[i]);
+ }
free(spec->priv.name);
free(spec->unpriv.name);
@@ -132,7 +150,8 @@ static void free_test_spec(struct test_spec *spec)
spec->unpriv.name = NULL;
}
-static int push_msg(const char *substr, const char *regex_str, struct expected_msgs *msgs)
+static int __push_msg(const char *substr, const char *regex_str, int regex_flags,
+ struct expected_msgs *msgs)
{
void *tmp;
int regcomp_res;
@@ -151,10 +170,12 @@ static int push_msg(const char *substr, const char *regex_str, struct expected_m
if (substr) {
msg->substr = substr;
msg->regex_str = NULL;
+ msg->regex_flags = 0;
} else {
msg->regex_str = regex_str;
msg->substr = NULL;
- regcomp_res = regcomp(&msg->regex, regex_str, REG_EXTENDED|REG_NEWLINE);
+ msg->regex_flags = regex_flags;
+ regcomp_res = regcomp(&msg->regex, regex_str, regex_flags|REG_NEWLINE);
if (regcomp_res != 0) {
regerror(regcomp_res, &msg->regex, error_msg, sizeof(error_msg));
PRINT_FAIL("Regexp compilation error in '%s': '%s'\n",
@@ -167,6 +188,35 @@ static int push_msg(const char *substr, const char *regex_str, struct expected_m
return 0;
}
+static int clone_msgs(struct expected_msgs *from, struct expected_msgs *to)
+{
+ struct expect_msg *msg;
+ int i, err;
+
+ for (i = 0; i < from->cnt; i++) {
+ msg = &from->patterns[i];
+ err = __push_msg(msg->substr, msg->regex_str, msg->regex_flags, to);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static int push_msg(const char *substr, struct expected_msgs *msgs)
+{
+ return __push_msg(substr, NULL, 0, msgs);
+}
+
+static int push_extended_regex(const char *regex_str, struct expected_msgs *msgs)
+{
+ return __push_msg(NULL, regex_str, REG_EXTENDED, msgs);
+}
+
+static int push_basic_regex(const char *regex_str, struct expected_msgs *msgs)
+{
+ return __push_msg(NULL, regex_str, 0, msgs);
+}
+
static int parse_int(const char *str, int *val, const char *name)
{
char *end;
@@ -215,12 +265,6 @@ static void update_flags(int *flags, int flag, bool clear)
*flags |= flag;
}
-enum arch {
- ARCH_X86_64 = 0x1,
- ARCH_ARM64 = 0x2,
- ARCH_RISCV64 = 0x4,
-};
-
/* Uses btf_decl_tag attributes to describe the expected test
* behavior, see bpf_misc.h for detailed description of each attribute
* and attribute combinations.
@@ -292,37 +336,49 @@ static int parse_test_spec(struct test_loader *tester,
spec->mode_mask |= UNPRIV;
} else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX)) {
msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1;
- err = push_msg(msg, NULL, &spec->priv.expect_msgs);
+ err = push_msg(msg, &spec->priv.expect_msgs);
if (err)
goto cleanup;
spec->mode_mask |= PRIV;
} else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX_UNPRIV)) {
msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX_UNPRIV) - 1;
- err = push_msg(msg, NULL, &spec->unpriv.expect_msgs);
+ err = push_msg(msg, &spec->unpriv.expect_msgs);
if (err)
goto cleanup;
spec->mode_mask |= UNPRIV;
} else if (str_has_pfx(s, TEST_TAG_EXPECT_REGEX_PFX)) {
msg = s + sizeof(TEST_TAG_EXPECT_REGEX_PFX) - 1;
- err = push_msg(NULL, msg, &spec->priv.expect_msgs);
+ err = push_extended_regex(msg, &spec->priv.expect_msgs);
if (err)
goto cleanup;
spec->mode_mask |= PRIV;
} else if (str_has_pfx(s, TEST_TAG_EXPECT_REGEX_PFX_UNPRIV)) {
msg = s + sizeof(TEST_TAG_EXPECT_REGEX_PFX_UNPRIV) - 1;
- err = push_msg(NULL, msg, &spec->unpriv.expect_msgs);
+ err = push_extended_regex(msg, &spec->unpriv.expect_msgs);
+ if (err)
+ goto cleanup;
+ spec->mode_mask |= UNPRIV;
+ } else if (str_has_pfx(s, TEST_TAG_JIT_X86_PFX)) {
+ msg = s + sizeof(TEST_TAG_JIT_X86_PFX) - 1;
+ err = push_basic_regex(msg, &spec->priv.jited[ARCH_X86_64]);
+ if (err)
+ goto cleanup;
+ spec->mode_mask |= PRIV;
+ } else if (str_has_pfx(s, TEST_TAG_JIT_X86_PFX_UNPRIV)) {
+ msg = s + sizeof(TEST_TAG_JIT_X86_PFX_UNPRIV) - 1;
+ err = push_basic_regex(msg, &spec->unpriv.jited[ARCH_X86_64]);
if (err)
goto cleanup;
spec->mode_mask |= UNPRIV;
} else if (str_has_pfx(s, TEST_TAG_EXPECT_XLATED_PFX)) {
msg = s + sizeof(TEST_TAG_EXPECT_XLATED_PFX) - 1;
- err = push_msg(msg, NULL, &spec->priv.expect_xlated);
+ err = push_msg(msg, &spec->priv.expect_xlated);
if (err)
goto cleanup;
spec->mode_mask |= PRIV;
} else if (str_has_pfx(s, TEST_TAG_EXPECT_XLATED_PFX_UNPRIV)) {
msg = s + sizeof(TEST_TAG_EXPECT_XLATED_PFX_UNPRIV) - 1;
- err = push_msg(msg, NULL, &spec->unpriv.expect_xlated);
+ err = push_msg(msg, &spec->unpriv.expect_xlated);
if (err)
goto cleanup;
spec->mode_mask |= UNPRIV;
@@ -376,11 +432,11 @@ static int parse_test_spec(struct test_loader *tester,
} else if (str_has_pfx(s, TEST_TAG_ARCH)) {
val = s + sizeof(TEST_TAG_ARCH) - 1;
if (strcmp(val, "X86_64") == 0) {
- arch_mask |= ARCH_X86_64;
+ arch_mask |= 1u << ARCH_X86_64;
} else if (strcmp(val, "ARM64") == 0) {
- arch_mask |= ARCH_ARM64;
+ arch_mask |= 1u << ARCH_ARM64;
} else if (strcmp(val, "RISCV64") == 0) {
- arch_mask |= ARCH_RISCV64;
+ arch_mask |= 1u << ARCH_RISCV64;
} else {
PRINT_FAIL("bad arch spec: '%s'", val);
err = -EINVAL;
@@ -434,26 +490,13 @@ static int parse_test_spec(struct test_loader *tester,
spec->unpriv.execute = spec->priv.execute;
}
- if (spec->unpriv.expect_msgs.cnt == 0) {
- for (i = 0; i < spec->priv.expect_msgs.cnt; i++) {
- struct expect_msg *msg = &spec->priv.expect_msgs.patterns[i];
-
- err = push_msg(msg->substr, msg->regex_str,
- &spec->unpriv.expect_msgs);
- if (err)
- goto cleanup;
- }
- }
- if (spec->unpriv.expect_xlated.cnt == 0) {
- for (i = 0; i < spec->priv.expect_xlated.cnt; i++) {
- struct expect_msg *msg = &spec->priv.expect_xlated.patterns[i];
-
- err = push_msg(msg->substr, msg->regex_str,
- &spec->unpriv.expect_xlated);
- if (err)
- goto cleanup;
- }
- }
+ if (spec->unpriv.expect_msgs.cnt == 0)
+ clone_msgs(&spec->priv.expect_msgs, &spec->unpriv.expect_msgs);
+ if (spec->unpriv.expect_xlated.cnt == 0)
+ clone_msgs(&spec->priv.expect_xlated, &spec->unpriv.expect_xlated);
+ for (i = 0; i < ARCH_MAX; ++i)
+ if (spec->unpriv.jited[i].cnt == 0)
+ clone_msgs(&spec->priv.jited[i], &spec->unpriv.jited[i]);
}
spec->valid = true;
@@ -508,6 +551,13 @@ static void emit_xlated(const char *xlated, bool force)
fprintf(stdout, "XLATED:\n=============\n%s=============\n", xlated);
}
+static void emit_jited(const char *jited, bool force)
+{
+ if (!force && env.verbosity == VERBOSE_NONE)
+ return;
+ fprintf(stdout, "JITED:\n=============\n%s=============\n", jited);
+}
+
static void validate_msgs(char *log_buf, struct expected_msgs *msgs,
void (*emit_fn)(const char *buf, bool force))
{
@@ -702,18 +752,16 @@ static int get_xlated_program_text(int prog_fd, char *text, size_t text_sz)
return err;
}
-static bool run_on_current_arch(int arch_mask)
+static int get_current_arch(void)
{
- if (arch_mask == 0)
- return true;
#if defined(__x86_64__)
- return arch_mask & ARCH_X86_64;
+ return ARCH_X86_64;
#elif defined(__aarch64__)
- return arch_mask & ARCH_ARM64;
+ return ARCH_ARM64;
#elif defined(__riscv) && __riscv_xlen == 64
- return arch_mask & ARCH_RISCV64;
+ return ARCH_RISCV64;
#endif
- return false;
+ return -1;
}
/* this function is forced noinline and has short generic name to look better
@@ -732,15 +780,16 @@ void run_subtest(struct test_loader *tester,
struct bpf_program *tprog = NULL, *tprog_iter;
struct test_spec *spec_iter;
struct cap_state caps = {};
+ int retval, err, i, arch;
struct bpf_object *tobj;
struct bpf_map *map;
- int retval, err, i;
bool should_load;
if (!test__start_subtest(subspec->name))
return;
- if (!run_on_current_arch(spec->arch_mask)) {
+ arch = get_current_arch();
+ if (spec->arch_mask && (arch < 0 || (spec->arch_mask & (1u << arch)) == 0)) {
test__skip();
return;
}
@@ -817,6 +866,21 @@ void run_subtest(struct test_loader *tester,
validate_msgs(tester->log_buf, &subspec->expect_xlated, emit_xlated);
}
+ if (arch > 0 && subspec->jited[arch].cnt) {
+ err = get_jited_program_text(bpf_program__fd(tprog),
+ tester->log_buf, tester->log_buf_sz);
+ if (err == -ENOTSUP) {
+ printf("%s:SKIP: jited programs disassembly is not supported,\n", __func__);
+ printf("%s:SKIP: tests are built w/o LLVM development libs\n", __func__);
+ test__skip();
+ goto tobj_cleanup;
+ }
+ if (!ASSERT_EQ(err, 0, "get_jited_program_text"))
+ goto tobj_cleanup;
+ emit_jited(tester->log_buf, false /*force*/);
+ validate_msgs(tester->log_buf, &subspec->jited[arch], emit_jited);
+ }
+
if (should_do_test_run(spec, subspec)) {
/* For some reason test_verifier executes programs
* with all capabilities restored. Do the same here.
--
2.45.2
next prev parent reply other threads:[~2024-08-09 1:05 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-09 1:05 [PATCH bpf-next 0/4] __jited_x86 test tag to check x86 assembly after jit Eduard Zingerman
2024-08-09 1:05 ` [PATCH bpf-next 1/4] selftests/bpf: less spam in the log for message matching Eduard Zingerman
2024-08-09 1:05 ` [PATCH bpf-next 2/4] selftests/bpf: utility function to get program disassembly after jit Eduard Zingerman
2024-08-13 16:05 ` Yonghong Song
2024-08-13 22:01 ` Eduard Zingerman
2024-08-15 19:27 ` Yonghong Song
2024-08-15 19:34 ` Eduard Zingerman
2024-08-15 21:06 ` Andrii Nakryiko
2024-08-15 21:50 ` Eduard Zingerman
2024-08-15 22:04 ` Andrii Nakryiko
2024-08-19 19:45 ` Eduard Zingerman
2024-08-19 21:05 ` Andrii Nakryiko
2024-08-09 1:05 ` Eduard Zingerman [this message]
2024-08-15 21:11 ` [PATCH bpf-next 3/4] selftests/bpf: __jited_x86 test tag to check x86 assembly " Andrii Nakryiko
2024-08-15 21:48 ` Eduard Zingerman
2024-08-09 1:05 ` [PATCH bpf-next 4/4] selftests/bpf: validate jit behaviour for tail calls Eduard Zingerman
2024-08-15 21:15 ` Andrii Nakryiko
2024-08-15 21:42 ` Eduard Zingerman
2024-08-15 22:07 ` Andrii Nakryiko
2024-08-15 22:10 ` Eduard Zingerman
2024-08-15 22:14 ` Andrii Nakryiko
2024-08-15 22:19 ` Eduard Zingerman
2024-08-15 21:32 ` Yonghong Song
2024-08-15 21:47 ` Eduard Zingerman
2024-08-15 22:09 ` Andrii Nakryiko
2024-08-15 22:16 ` Eduard Zingerman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240809010518.1137758-4-eddyz87@gmail.com \
--to=eddyz87@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=hffilwlqm@gmail.com \
--cc=kernel-team@fb.com \
--cc=martin.lau@linux.dev \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox