@@ -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
136137static __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+
146196static 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