10
10
#include <linux/kthread.h>
11
11
#include <linux/module.h>
12
12
#include <linux/string.h>
13
+ #include <linux/kprobes.h>
13
14
#include <linux/wait.h>
14
15
#include <asm/irq.h>
15
16
#include <asm/delay.h>
@@ -119,6 +120,7 @@ static struct unwindme *unwindme;
119
120
#define UWM_CALLER 0x8 /* Unwind starting from caller. */
120
121
#define UWM_SWITCH_STACK 0x10 /* Use CALL_ON_STACK. */
121
122
#define UWM_IRQ 0x20 /* Unwind from irq context. */
123
+ #define UWM_PGM 0x40 /* Unwind from program check handler. */
122
124
123
125
static __always_inline unsigned long get_psw_addr (void )
124
126
{
@@ -130,6 +132,17 @@ static __always_inline unsigned long get_psw_addr(void)
130
132
return psw_addr ;
131
133
}
132
134
135
+ #ifdef CONFIG_KPROBES
136
+ static int pgm_pre_handler (struct kprobe * p , struct pt_regs * regs )
137
+ {
138
+ struct unwindme * u = unwindme ;
139
+
140
+ u -> ret = test_unwind (NULL , (u -> flags & UWM_REGS ) ? regs : NULL ,
141
+ (u -> flags & UWM_SP ) ? u -> sp : 0 );
142
+ return 0 ;
143
+ }
144
+ #endif
145
+
133
146
/* This function may or may not appear in the backtrace. */
134
147
static noinline int unwindme_func4 (struct unwindme * u )
135
148
{
@@ -140,6 +153,34 @@ static noinline int unwindme_func4(struct unwindme *u)
140
153
wait_event (u -> task_wq , kthread_should_park ());
141
154
kthread_parkme ();
142
155
return 0 ;
156
+ #ifdef CONFIG_KPROBES
157
+ } else if (u -> flags & UWM_PGM ) {
158
+ struct kprobe kp ;
159
+ int ret ;
160
+
161
+ unwindme = u ;
162
+ memset (& kp , 0 , sizeof (kp ));
163
+ kp .symbol_name = "do_report_trap" ;
164
+ kp .pre_handler = pgm_pre_handler ;
165
+ ret = register_kprobe (& kp );
166
+ if (ret < 0 ) {
167
+ pr_err ("register_kprobe failed %d\n" , ret );
168
+ return - EINVAL ;
169
+ }
170
+
171
+ /*
172
+ * trigger specification exception
173
+ */
174
+ asm volatile (
175
+ " mvcl %%r1,%%r1\n"
176
+ "0: nopr %%r7\n"
177
+ EX_TABLE (0b , 0b )
178
+ :);
179
+
180
+ unregister_kprobe (& kp );
181
+ unwindme = NULL ;
182
+ return u -> ret ;
183
+ #endif
143
184
} else {
144
185
struct pt_regs regs ;
145
186
@@ -286,6 +327,12 @@ do { \
286
327
TEST (UWM_IRQ | UWM_CALLER | UWM_SP );
287
328
TEST (UWM_IRQ | UWM_CALLER | UWM_SP | UWM_REGS );
288
329
TEST (UWM_IRQ | UWM_CALLER | UWM_SP | UWM_REGS | UWM_SWITCH_STACK );
330
+ #ifdef CONFIG_KPROBES
331
+ TEST (UWM_PGM );
332
+ TEST (UWM_PGM | UWM_SP );
333
+ TEST (UWM_PGM | UWM_REGS );
334
+ TEST (UWM_PGM | UWM_SP | UWM_REGS );
335
+ #endif
289
336
#undef TEST
290
337
291
338
return ret ;
0 commit comments