@@ -132,36 +132,50 @@ 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. */
135+ #define UWM_KRETPROBE 0x200 /* Unwind through kretprobed function. */
136+ #define UWM_KRETPROBE_HANDLER 0x400 /* Unwind from kretprobe handler. */
136137
137- static __always_inline unsigned long get_psw_addr (void )
138+ static __always_inline struct pt_regs fake_pt_regs (void )
138139{
139- unsigned long psw_addr ;
140+ struct pt_regs regs ;
141+
142+ memset (& regs , 0 , sizeof (regs ));
143+ regs .gprs [15 ] = current_stack_pointer ();
140144
141145 asm volatile (
142146 "basr %[psw_addr],0\n"
143- : [psw_addr ] "=d" (psw_addr ));
144- return psw_addr ;
147+ : [psw_addr ] "=d" (regs . psw . addr ));
148+ return regs ;
145149}
146150
147151static int kretprobe_ret_handler (struct kretprobe_instance * ri , struct pt_regs * regs )
148152{
149153 struct unwindme * u = unwindme ;
150154
155+ if (!(u -> flags & UWM_KRETPROBE_HANDLER ))
156+ return 0 ;
157+
151158 u -> ret = test_unwind (NULL , (u -> flags & UWM_REGS ) ? regs : NULL ,
152159 (u -> flags & UWM_SP ) ? u -> sp : 0 );
153160
154161 return 0 ;
155162}
156163
157- static noinline notrace void test_unwind_kretprobed_func (void )
164+ static noinline notrace int test_unwind_kretprobed_func (struct unwindme * u )
158165{
159- asm volatile (" nop\n" );
166+ struct pt_regs regs ;
167+
168+ if (!(u -> flags & UWM_KRETPROBE ))
169+ return 0 ;
170+
171+ regs = fake_pt_regs ();
172+ return test_unwind (NULL , (u -> flags & UWM_REGS ) ? & regs : NULL ,
173+ (u -> flags & UWM_SP ) ? u -> sp : 0 );
160174}
161175
162- static noinline void test_unwind_kretprobed_func_caller (void )
176+ static noinline int test_unwind_kretprobed_func_caller (struct unwindme * u )
163177{
164- test_unwind_kretprobed_func ();
178+ return test_unwind_kretprobed_func (u );
165179}
166180
167181static int test_unwind_kretprobe (struct unwindme * u )
@@ -187,10 +201,12 @@ static int test_unwind_kretprobe(struct unwindme *u)
187201 return - EINVAL ;
188202 }
189203
190- test_unwind_kretprobed_func_caller ();
204+ ret = test_unwind_kretprobed_func_caller (u );
191205 unregister_kretprobe (& my_kretprobe );
192206 unwindme = NULL ;
193- return u -> ret ;
207+ if (u -> flags & UWM_KRETPROBE_HANDLER )
208+ ret = u -> ret ;
209+ return ret ;
194210}
195211
196212static int kprobe_pre_handler (struct kprobe * p , struct pt_regs * regs )
@@ -304,16 +320,13 @@ static noinline int unwindme_func4(struct unwindme *u)
304320 return 0 ;
305321 } else if (u -> flags & (UWM_PGM | UWM_KPROBE_ON_FTRACE )) {
306322 return test_unwind_kprobe (u );
307- } else if (u -> flags & (UWM_KRETPROBE )) {
323+ } else if (u -> flags & (UWM_KRETPROBE | UWM_KRETPROBE_HANDLER )) {
308324 return test_unwind_kretprobe (u );
309325 } else if (u -> flags & UWM_FTRACE ) {
310326 return test_unwind_ftrace (u );
311327 } else {
312- struct pt_regs regs ;
328+ struct pt_regs regs = fake_pt_regs () ;
313329
314- memset (& regs , 0 , sizeof (regs ));
315- regs .psw .addr = get_psw_addr ();
316- regs .gprs [15 ] = current_stack_pointer ();
317330 return test_unwind (NULL ,
318331 (u -> flags & UWM_REGS ) ? & regs : NULL ,
319332 (u -> flags & UWM_SP ) ? u -> sp : 0 );
@@ -452,6 +465,10 @@ static const struct test_params param_list[] = {
452465 TEST_WITH_FLAGS (UWM_KRETPROBE | UWM_SP ),
453466 TEST_WITH_FLAGS (UWM_KRETPROBE | UWM_REGS ),
454467 TEST_WITH_FLAGS (UWM_KRETPROBE | UWM_SP | UWM_REGS ),
468+ TEST_WITH_FLAGS (UWM_KRETPROBE_HANDLER ),
469+ TEST_WITH_FLAGS (UWM_KRETPROBE_HANDLER | UWM_SP ),
470+ TEST_WITH_FLAGS (UWM_KRETPROBE_HANDLER | UWM_REGS ),
471+ TEST_WITH_FLAGS (UWM_KRETPROBE_HANDLER | UWM_SP | UWM_REGS ),
455472};
456473
457474/*
0 commit comments