Skip to content

Commit

Permalink
s390/test_unwind: fix and extend kprobes test
Browse files Browse the repository at this point in the history
Running kprobe test on a kernel built with clang 14 didn't actually
trigger pgm_pre_handler() and no unwinder code was called. Even though
do_report_trap() is a global symbol, clang inlined it in several local
functions including illegal_op() handler, so that kprobbing a global
symbol didn't have a desired effect.

To achieve the same test result (unwinding from a program check
handler) introduce a local function and probe an instruction in the
middle, so that kprobe doesn't take KPROBE_ON_FTRACE path.

While at it, add another test for KPROBE_ON_FTRACE.

Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
  • Loading branch information
Vasily Gorbik committed Mar 1, 2022
1 parent 829ec74 commit 9ba142f
Showing 1 changed file with 50 additions and 33 deletions.
83 changes: 50 additions & 33 deletions arch/s390/lib/test_unwind.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,9 @@ static struct unwindme *unwindme;
#define UWM_CALLER 0x8 /* Unwind starting from caller. */
#define UWM_SWITCH_STACK 0x10 /* Use call_on_stack. */
#define UWM_IRQ 0x20 /* Unwind from irq context. */
#define UWM_PGM 0x40 /* Unwind from program check handler. */
#define UWM_FTRACE 0x80 /* Unwind from ftrace handler. */
#define UWM_PGM 0x40 /* Unwind from program check handler */
#define UWM_KPROBE_ON_FTRACE 0x80 /* Unwind from kprobe handler called via ftrace. */
#define UWM_FTRACE 0x100 /* Unwind from ftrace handler. */

static __always_inline unsigned long get_psw_addr(void)
{
Expand All @@ -142,7 +143,7 @@ static __always_inline unsigned long get_psw_addr(void)
return psw_addr;
}

static int pgm_pre_handler(struct kprobe *p, struct pt_regs *regs)
static int kprobe_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
struct unwindme *u = unwindme;

Expand All @@ -151,6 +152,46 @@ static int pgm_pre_handler(struct kprobe *p, struct pt_regs *regs)
return 0;
}

extern const char test_unwind_kprobed_insn[];

static noinline void test_unwind_kprobed_func(void)
{
asm volatile(
" nopr %%r7\n"
"test_unwind_kprobed_insn:\n"
" nopr %%r7\n"
:);
}

static int test_unwind_kprobe(struct unwindme *u)
{
struct kprobe kp;
int ret;

if (!IS_ENABLED(CONFIG_KPROBES))
kunit_skip(current_test, "requires CONFIG_KPROBES");
if (!IS_ENABLED(CONFIG_KPROBES_ON_FTRACE) && u->flags & UWM_KPROBE_ON_FTRACE)
kunit_skip(current_test, "requires CONFIG_KPROBES_ON_FTRACE");

u->ret = -1; /* make sure kprobe is called */
unwindme = u;
memset(&kp, 0, sizeof(kp));
kp.pre_handler = kprobe_pre_handler;
kp.addr = u->flags & UWM_KPROBE_ON_FTRACE ?
(kprobe_opcode_t *)test_unwind_kprobed_func :
(kprobe_opcode_t *)test_unwind_kprobed_insn;
ret = register_kprobe(&kp);
if (ret < 0) {
kunit_err(current_test, "register_kprobe failed %d\n", ret);
return -EINVAL;
}

test_unwind_kprobed_func();
unregister_kprobe(&kp);
unwindme = NULL;
return u->ret;
}

static void notrace __used test_unwind_ftrace_handler(unsigned long ip,
unsigned long parent_ip,
struct ftrace_ops *fops,
Expand Down Expand Up @@ -212,36 +253,8 @@ static noinline int unwindme_func4(struct unwindme *u)
wait_event(u->task_wq, kthread_should_park());
kthread_parkme();
return 0;
} else if (u->flags & UWM_PGM) {
struct kprobe kp;
int ret;

if (!IS_ENABLED(CONFIG_KPROBES))
kunit_skip(current_test, "requires CONFIG_KPROBES");

unwindme = u;
memset(&kp, 0, sizeof(kp));
kp.symbol_name = "do_report_trap";
kp.pre_handler = pgm_pre_handler;
ret = register_kprobe(&kp);
if (ret < 0) {
kunit_err(current_test, "register_kprobe failed %d\n", ret);
return -EINVAL;
}

/*
* Trigger operation exception; use insn notation to bypass
* llvm's integrated assembler sanity checks.
*/
asm volatile(
" .insn e,0x0000\n" /* illegal opcode */
"0: nopr %%r7\n"
EX_TABLE(0b, 0b)
:);

unregister_kprobe(&kp);
unwindme = NULL;
return u->ret;
} else if (u->flags & (UWM_PGM | UWM_KPROBE_ON_FTRACE)) {
return test_unwind_kprobe(u);
} else if (u->flags & UWM_FTRACE) {
return test_unwind_ftrace(u);
} else {
Expand Down Expand Up @@ -376,6 +389,10 @@ static const struct test_params param_list[] = {
TEST_WITH_FLAGS(UWM_PGM | UWM_SP),
TEST_WITH_FLAGS(UWM_PGM | UWM_REGS),
TEST_WITH_FLAGS(UWM_PGM | UWM_SP | UWM_REGS),
TEST_WITH_FLAGS(UWM_KPROBE_ON_FTRACE),
TEST_WITH_FLAGS(UWM_KPROBE_ON_FTRACE | UWM_SP),
TEST_WITH_FLAGS(UWM_KPROBE_ON_FTRACE | UWM_REGS),
TEST_WITH_FLAGS(UWM_KPROBE_ON_FTRACE | UWM_SP | UWM_REGS),
TEST_WITH_FLAGS(UWM_FTRACE),
TEST_WITH_FLAGS(UWM_FTRACE | UWM_SP),
TEST_WITH_FLAGS(UWM_FTRACE | UWM_REGS),
Expand Down

0 comments on commit 9ba142f

Please sign in to comment.