Skip to content

Commit c65f677

Browse files
tobias-huschleVasily Gorbik
authored andcommitted
s390/test_unwind: add kretprobe tests
Add tests to verify that s390 kretprobes maintain a correct stack chain and ensure their proper function. Reviewed-by: Vasily Gorbik <gor@linux.ibm.com> Signed-off-by: Tobias Huschle <huschle@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
1 parent 63bf38f commit c65f677

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

arch/s390/lib/test_unwind.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ static struct unwindme *unwindme;
132132
#define UWM_PGM 0x40 /* Unwind from program check handler */
133133
#define UWM_KPROBE_ON_FTRACE 0x80 /* Unwind from kprobe handler called via ftrace. */
134134
#define UWM_FTRACE 0x100 /* Unwind from ftrace handler. */
135+
#define UWM_KRETPROBE 0x200 /* Unwind kretprobe handlers. */
135136

136137
static __always_inline unsigned long get_psw_addr(void)
137138
{
@@ -143,6 +144,55 @@ static __always_inline unsigned long get_psw_addr(void)
143144
return psw_addr;
144145
}
145146

147+
static int kretprobe_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
148+
{
149+
struct unwindme *u = unwindme;
150+
151+
u->ret = test_unwind(NULL, (u->flags & UWM_REGS) ? regs : NULL,
152+
(u->flags & UWM_SP) ? u->sp : 0);
153+
154+
return 0;
155+
}
156+
157+
static noinline notrace void test_unwind_kretprobed_func(void)
158+
{
159+
asm volatile(" nop\n");
160+
}
161+
162+
static noinline void test_unwind_kretprobed_func_caller(void)
163+
{
164+
test_unwind_kretprobed_func();
165+
}
166+
167+
static int test_unwind_kretprobe(struct unwindme *u)
168+
{
169+
int ret;
170+
struct kretprobe my_kretprobe;
171+
172+
if (!IS_ENABLED(CONFIG_KPROBES))
173+
kunit_skip(current_test, "requires CONFIG_KPROBES");
174+
175+
u->ret = -1; /* make sure kprobe is called */
176+
unwindme = u;
177+
178+
memset(&my_kretprobe, 0, sizeof(my_kretprobe));
179+
my_kretprobe.handler = kretprobe_ret_handler;
180+
my_kretprobe.maxactive = 1;
181+
my_kretprobe.kp.addr = (kprobe_opcode_t *)test_unwind_kretprobed_func;
182+
183+
ret = register_kretprobe(&my_kretprobe);
184+
185+
if (ret < 0) {
186+
kunit_err(current_test, "register_kretprobe failed %d\n", ret);
187+
return -EINVAL;
188+
}
189+
190+
test_unwind_kretprobed_func_caller();
191+
unregister_kretprobe(&my_kretprobe);
192+
unwindme = NULL;
193+
return u->ret;
194+
}
195+
146196
static int kprobe_pre_handler(struct kprobe *p, struct pt_regs *regs)
147197
{
148198
struct unwindme *u = unwindme;
@@ -254,6 +304,8 @@ static noinline int unwindme_func4(struct unwindme *u)
254304
return 0;
255305
} else if (u->flags & (UWM_PGM | UWM_KPROBE_ON_FTRACE)) {
256306
return test_unwind_kprobe(u);
307+
} else if (u->flags & (UWM_KRETPROBE)) {
308+
return test_unwind_kretprobe(u);
257309
} else if (u->flags & UWM_FTRACE) {
258310
return test_unwind_ftrace(u);
259311
} else {
@@ -396,6 +448,10 @@ static const struct test_params param_list[] = {
396448
TEST_WITH_FLAGS(UWM_FTRACE | UWM_SP),
397449
TEST_WITH_FLAGS(UWM_FTRACE | UWM_REGS),
398450
TEST_WITH_FLAGS(UWM_FTRACE | UWM_SP | UWM_REGS),
451+
TEST_WITH_FLAGS(UWM_KRETPROBE),
452+
TEST_WITH_FLAGS(UWM_KRETPROBE | UWM_SP),
453+
TEST_WITH_FLAGS(UWM_KRETPROBE | UWM_REGS),
454+
TEST_WITH_FLAGS(UWM_KRETPROBE | UWM_SP | UWM_REGS),
399455
};
400456

401457
/*

0 commit comments

Comments
 (0)