1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30#include <linux/config.h>
31#include <linux/kprobes.h>
32#include <linux/ptrace.h>
33#include <linux/spinlock.h>
34#include <linux/preempt.h>
35#include <asm/kdebug.h>
36#include <asm/sstep.h>
37
38
39#define KPROBE_HIT_ACTIVE 0x00000001
40#define KPROBE_HIT_SS 0x00000002
41
42static struct kprobe *current_kprobe;
43static unsigned long kprobe_status, kprobe_saved_msr;
44static struct pt_regs jprobe_saved_regs;
45
46int arch_prepare_kprobe(struct kprobe *p)
47{
48 kprobe_opcode_t insn = *p->addr;
49
50 if (IS_MTMSRD(insn) || IS_RFID(insn))
51
52 return 1;
53 return 0;
54}
55
56void arch_copy_kprobe(struct kprobe *p)
57{
58 memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
59}
60
61void arch_remove_kprobe(struct kprobe *p)
62{
63}
64
65static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
66{
67 *p->addr = p->opcode;
68 regs->nip = (unsigned long)p->addr;
69}
70
71static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
72{
73 regs->msr |= MSR_SE;
74 regs->nip = (unsigned long)&p->ainsn.insn;
75}
76
77static inline int kprobe_handler(struct pt_regs *regs)
78{
79 struct kprobe *p;
80 int ret = 0;
81 unsigned int *addr = (unsigned int *)regs->nip;
82
83
84 preempt_disable();
85
86
87 if (kprobe_running()) {
88
89
90 p = get_kprobe(addr);
91 if (p) {
92 disarm_kprobe(p, regs);
93 ret = 1;
94 } else {
95 p = current_kprobe;
96 if (p->break_handler && p->break_handler(p, regs)) {
97 goto ss_probe;
98 }
99 }
100
101 goto no_kprobe;
102 }
103
104 lock_kprobes();
105 p = get_kprobe(addr);
106 if (!p) {
107 unlock_kprobes();
108#if 0
109 if (*addr != BREAKPOINT_INSTRUCTION) {
110
111
112
113
114
115
116
117 ret = 1;
118 }
119#endif
120
121 goto no_kprobe;
122 }
123
124 kprobe_status = KPROBE_HIT_ACTIVE;
125 current_kprobe = p;
126 kprobe_saved_msr = regs->msr;
127 if (p->pre_handler(p, regs)) {
128
129 return 1;
130 }
131
132ss_probe:
133 prepare_singlestep(p, regs);
134 kprobe_status = KPROBE_HIT_SS;
135 return 1;
136
137no_kprobe:
138 preempt_enable_no_resched();
139 return ret;
140}
141
142
143
144
145
146
147
148
149
150static void resume_execution(struct kprobe *p, struct pt_regs *regs)
151{
152 int ret;
153
154 regs->nip = (unsigned long)p->addr;
155 ret = emulate_step(regs, p->ainsn.insn[0]);
156 if (ret == 0)
157 regs->nip = (unsigned long)p->addr + 4;
158
159 regs->msr &= ~MSR_SE;
160}
161
162static inline int post_kprobe_handler(struct pt_regs *regs)
163{
164 if (!kprobe_running())
165 return 0;
166
167 if (current_kprobe->post_handler)
168 current_kprobe->post_handler(current_kprobe, regs, 0);
169
170 resume_execution(current_kprobe, regs);
171 regs->msr |= kprobe_saved_msr;
172
173 unlock_kprobes();
174 preempt_enable_no_resched();
175
176
177
178
179
180
181 if (regs->msr & MSR_SE)
182 return 0;
183
184 return 1;
185}
186
187
188static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
189{
190 if (current_kprobe->fault_handler
191 && current_kprobe->fault_handler(current_kprobe, regs, trapnr))
192 return 1;
193
194 if (kprobe_status & KPROBE_HIT_SS) {
195 resume_execution(current_kprobe, regs);
196 regs->msr |= kprobe_saved_msr;
197
198 unlock_kprobes();
199 preempt_enable_no_resched();
200 }
201 return 0;
202}
203
204
205
206
207int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
208 void *data)
209{
210 struct die_args *args = (struct die_args *)data;
211 switch (val) {
212 case DIE_IABR_MATCH:
213 case DIE_DABR_MATCH:
214 case DIE_BPT:
215 if (kprobe_handler(args->regs))
216 return NOTIFY_STOP;
217 break;
218 case DIE_SSTEP:
219 if (post_kprobe_handler(args->regs))
220 return NOTIFY_STOP;
221 break;
222 case DIE_GPF:
223 case DIE_PAGE_FAULT:
224 if (kprobe_running() &&
225 kprobe_fault_handler(args->regs, args->trapnr))
226 return NOTIFY_STOP;
227 break;
228 default:
229 break;
230 }
231 return NOTIFY_DONE;
232}
233
234int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
235{
236 struct jprobe *jp = container_of(p, struct jprobe, kp);
237
238 memcpy(&jprobe_saved_regs, regs, sizeof(struct pt_regs));
239
240
241 regs->nip = (unsigned long)(((func_descr_t *)jp->entry)->entry);
242 regs->gpr[2] = (unsigned long)(((func_descr_t *)jp->entry)->toc);
243
244 return 1;
245}
246
247void jprobe_return(void)
248{
249 preempt_enable_no_resched();
250 asm volatile("trap" ::: "memory");
251}
252
253void jprobe_return_end(void)
254{
255};
256
257int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
258{
259
260
261
262
263
264 memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs));
265 return 1;
266}
267