xref: /openbmc/linux/arch/sh/kernel/kprobes.c (revision 78a12934)
15933f6d2SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
2d39f5450SChris Smith /*
3d39f5450SChris Smith  * Kernel probes (kprobes) for SuperH
4d39f5450SChris Smith  *
5d39f5450SChris Smith  * Copyright (C) 2007 Chris Smith <chris.smith@st.com>
6d39f5450SChris Smith  * Copyright (C) 2006 Lineo Solutions, Inc.
7d39f5450SChris Smith  */
8d39f5450SChris Smith #include <linux/kprobes.h>
9d92280d1SPaul Gortmaker #include <linux/extable.h>
10d39f5450SChris Smith #include <linux/ptrace.h>
11d39f5450SChris Smith #include <linux/preempt.h>
12d39f5450SChris Smith #include <linux/kdebug.h>
135a0e3ad6STejun Heo #include <linux/slab.h>
14d39f5450SChris Smith #include <asm/cacheflush.h>
157c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
16d39f5450SChris Smith 
17d39f5450SChris Smith DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
18d39f5450SChris Smith DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
19d39f5450SChris Smith 
2057fcfdf9SPaul Mundt static DEFINE_PER_CPU(struct kprobe, saved_current_opcode);
2157fcfdf9SPaul Mundt static DEFINE_PER_CPU(struct kprobe, saved_next_opcode);
2257fcfdf9SPaul Mundt static DEFINE_PER_CPU(struct kprobe, saved_next_opcode2);
23d39f5450SChris Smith 
24d39f5450SChris Smith #define OPCODE_JMP(x)	(((x) & 0xF0FF) == 0x402b)
25d39f5450SChris Smith #define OPCODE_JSR(x)	(((x) & 0xF0FF) == 0x400b)
26d39f5450SChris Smith #define OPCODE_BRA(x)	(((x) & 0xF000) == 0xa000)
27d39f5450SChris Smith #define OPCODE_BRAF(x)	(((x) & 0xF0FF) == 0x0023)
28d39f5450SChris Smith #define OPCODE_BSR(x)	(((x) & 0xF000) == 0xb000)
29d39f5450SChris Smith #define OPCODE_BSRF(x)	(((x) & 0xF0FF) == 0x0003)
30d39f5450SChris Smith 
31d39f5450SChris Smith #define OPCODE_BF_S(x)	(((x) & 0xFF00) == 0x8f00)
32d39f5450SChris Smith #define OPCODE_BT_S(x)	(((x) & 0xFF00) == 0x8d00)
33d39f5450SChris Smith 
34d39f5450SChris Smith #define OPCODE_BF(x)	(((x) & 0xFF00) == 0x8b00)
35d39f5450SChris Smith #define OPCODE_BT(x)	(((x) & 0xFF00) == 0x8900)
36d39f5450SChris Smith 
37d39f5450SChris Smith #define OPCODE_RTS(x)	(((x) & 0x000F) == 0x000b)
38d39f5450SChris Smith #define OPCODE_RTE(x)	(((x) & 0xFFFF) == 0x002b)
39d39f5450SChris Smith 
arch_prepare_kprobe(struct kprobe * p)40d39f5450SChris Smith int __kprobes arch_prepare_kprobe(struct kprobe *p)
41d39f5450SChris Smith {
42d39f5450SChris Smith 	kprobe_opcode_t opcode = *(kprobe_opcode_t *) (p->addr);
43d39f5450SChris Smith 
44d39f5450SChris Smith 	if (OPCODE_RTE(opcode))
45d39f5450SChris Smith 		return -EFAULT;	/* Bad breakpoint */
46d39f5450SChris Smith 
4778a12934SGeert Uytterhoeven 	memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
48d39f5450SChris Smith 	p->opcode = opcode;
49d39f5450SChris Smith 
50d39f5450SChris Smith 	return 0;
51d39f5450SChris Smith }
52d39f5450SChris Smith 
arch_arm_kprobe(struct kprobe * p)53d39f5450SChris Smith void __kprobes arch_arm_kprobe(struct kprobe *p)
54d39f5450SChris Smith {
55d39f5450SChris Smith 	*p->addr = BREAKPOINT_INSTRUCTION;
56d39f5450SChris Smith 	flush_icache_range((unsigned long)p->addr,
57d39f5450SChris Smith 			   (unsigned long)p->addr + sizeof(kprobe_opcode_t));
58d39f5450SChris Smith }
59d39f5450SChris Smith 
arch_disarm_kprobe(struct kprobe * p)60d39f5450SChris Smith void __kprobes arch_disarm_kprobe(struct kprobe *p)
61d39f5450SChris Smith {
62d39f5450SChris Smith 	*p->addr = p->opcode;
63d39f5450SChris Smith 	flush_icache_range((unsigned long)p->addr,
64d39f5450SChris Smith 			   (unsigned long)p->addr + sizeof(kprobe_opcode_t));
65d39f5450SChris Smith }
66d39f5450SChris Smith 
arch_trampoline_kprobe(struct kprobe * p)67d39f5450SChris Smith int __kprobes arch_trampoline_kprobe(struct kprobe *p)
68d39f5450SChris Smith {
69d39f5450SChris Smith 	if (*p->addr == BREAKPOINT_INSTRUCTION)
70d39f5450SChris Smith 		return 1;
71d39f5450SChris Smith 
72d39f5450SChris Smith 	return 0;
73d39f5450SChris Smith }
74d39f5450SChris Smith 
75d39f5450SChris Smith /**
76d39f5450SChris Smith  * If an illegal slot instruction exception occurs for an address
77d39f5450SChris Smith  * containing a kprobe, remove the probe.
78d39f5450SChris Smith  *
79d39f5450SChris Smith  * Returns 0 if the exception was handled successfully, 1 otherwise.
80d39f5450SChris Smith  */
kprobe_handle_illslot(unsigned long pc)81d39f5450SChris Smith int __kprobes kprobe_handle_illslot(unsigned long pc)
82d39f5450SChris Smith {
83d39f5450SChris Smith 	struct kprobe *p = get_kprobe((kprobe_opcode_t *) pc + 1);
84d39f5450SChris Smith 
85d39f5450SChris Smith 	if (p != NULL) {
86d39f5450SChris Smith 		printk("Warning: removing kprobe from delay slot: 0x%.8x\n",
87d39f5450SChris Smith 		       (unsigned int)pc + 2);
88d39f5450SChris Smith 		unregister_kprobe(p);
89d39f5450SChris Smith 		return 0;
90d39f5450SChris Smith 	}
91d39f5450SChris Smith 
92d39f5450SChris Smith 	return 1;
93d39f5450SChris Smith }
94d39f5450SChris Smith 
arch_remove_kprobe(struct kprobe * p)95d39f5450SChris Smith void __kprobes arch_remove_kprobe(struct kprobe *p)
96d39f5450SChris Smith {
97c473b2c6SChristoph Lameter 	struct kprobe *saved = this_cpu_ptr(&saved_next_opcode);
98d39f5450SChris Smith 
9957fcfdf9SPaul Mundt 	if (saved->addr) {
10057fcfdf9SPaul Mundt 		arch_disarm_kprobe(p);
10157fcfdf9SPaul Mundt 		arch_disarm_kprobe(saved);
10257fcfdf9SPaul Mundt 
10357fcfdf9SPaul Mundt 		saved->addr = NULL;
10457fcfdf9SPaul Mundt 		saved->opcode = 0;
10557fcfdf9SPaul Mundt 
106c473b2c6SChristoph Lameter 		saved = this_cpu_ptr(&saved_next_opcode2);
10757fcfdf9SPaul Mundt 		if (saved->addr) {
10857fcfdf9SPaul Mundt 			arch_disarm_kprobe(saved);
10957fcfdf9SPaul Mundt 
11057fcfdf9SPaul Mundt 			saved->addr = NULL;
11157fcfdf9SPaul Mundt 			saved->opcode = 0;
112d39f5450SChris Smith 		}
113d39f5450SChris Smith 	}
114d39f5450SChris Smith }
115d39f5450SChris Smith 
save_previous_kprobe(struct kprobe_ctlblk * kcb)1164eb5845dSPaul Mundt static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
117d39f5450SChris Smith {
118d39f5450SChris Smith 	kcb->prev_kprobe.kp = kprobe_running();
119d39f5450SChris Smith 	kcb->prev_kprobe.status = kcb->kprobe_status;
120d39f5450SChris Smith }
121d39f5450SChris Smith 
restore_previous_kprobe(struct kprobe_ctlblk * kcb)1224eb5845dSPaul Mundt static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
123d39f5450SChris Smith {
124c473b2c6SChristoph Lameter 	__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
125d39f5450SChris Smith 	kcb->kprobe_status = kcb->prev_kprobe.status;
126d39f5450SChris Smith }
127d39f5450SChris Smith 
set_current_kprobe(struct kprobe * p,struct pt_regs * regs,struct kprobe_ctlblk * kcb)1284eb5845dSPaul Mundt static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
129d39f5450SChris Smith 					 struct kprobe_ctlblk *kcb)
130d39f5450SChris Smith {
131c473b2c6SChristoph Lameter 	__this_cpu_write(current_kprobe, p);
132d39f5450SChris Smith }
133d39f5450SChris Smith 
134d39f5450SChris Smith /*
135d39f5450SChris Smith  * Singlestep is implemented by disabling the current kprobe and setting one
136d39f5450SChris Smith  * on the next instruction, following branches. Two probes are set if the
137d39f5450SChris Smith  * branch is conditional.
138d39f5450SChris Smith  */
prepare_singlestep(struct kprobe * p,struct pt_regs * regs)1394eb5845dSPaul Mundt static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
140d39f5450SChris Smith {
141c473b2c6SChristoph Lameter 	__this_cpu_write(saved_current_opcode.addr, (kprobe_opcode_t *)regs->pc);
142d39f5450SChris Smith 
143d39f5450SChris Smith 	if (p != NULL) {
14457fcfdf9SPaul Mundt 		struct kprobe *op1, *op2;
14557fcfdf9SPaul Mundt 
146d39f5450SChris Smith 		arch_disarm_kprobe(p);
147d39f5450SChris Smith 
148c473b2c6SChristoph Lameter 		op1 = this_cpu_ptr(&saved_next_opcode);
149c473b2c6SChristoph Lameter 		op2 = this_cpu_ptr(&saved_next_opcode2);
15057fcfdf9SPaul Mundt 
151d39f5450SChris Smith 		if (OPCODE_JSR(p->opcode) || OPCODE_JMP(p->opcode)) {
152d39f5450SChris Smith 			unsigned int reg_nr = ((p->opcode >> 8) & 0x000F);
15357fcfdf9SPaul Mundt 			op1->addr = (kprobe_opcode_t *) regs->regs[reg_nr];
154d39f5450SChris Smith 		} else if (OPCODE_BRA(p->opcode) || OPCODE_BSR(p->opcode)) {
155d39f5450SChris Smith 			unsigned long disp = (p->opcode & 0x0FFF);
15657fcfdf9SPaul Mundt 			op1->addr =
157d39f5450SChris Smith 			    (kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
158d39f5450SChris Smith 
159d39f5450SChris Smith 		} else if (OPCODE_BRAF(p->opcode) || OPCODE_BSRF(p->opcode)) {
160d39f5450SChris Smith 			unsigned int reg_nr = ((p->opcode >> 8) & 0x000F);
16157fcfdf9SPaul Mundt 			op1->addr =
162d39f5450SChris Smith 			    (kprobe_opcode_t *) (regs->pc + 4 +
163d39f5450SChris Smith 						 regs->regs[reg_nr]);
164d39f5450SChris Smith 
165d39f5450SChris Smith 		} else if (OPCODE_RTS(p->opcode)) {
16657fcfdf9SPaul Mundt 			op1->addr = (kprobe_opcode_t *) regs->pr;
167d39f5450SChris Smith 
168d39f5450SChris Smith 		} else if (OPCODE_BF(p->opcode) || OPCODE_BT(p->opcode)) {
169d39f5450SChris Smith 			unsigned long disp = (p->opcode & 0x00FF);
170d39f5450SChris Smith 			/* case 1 */
17157fcfdf9SPaul Mundt 			op1->addr = p->addr + 1;
172d39f5450SChris Smith 			/* case 2 */
17357fcfdf9SPaul Mundt 			op2->addr =
174d39f5450SChris Smith 			    (kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
17557fcfdf9SPaul Mundt 			op2->opcode = *(op2->addr);
17657fcfdf9SPaul Mundt 			arch_arm_kprobe(op2);
177d39f5450SChris Smith 
178d39f5450SChris Smith 		} else if (OPCODE_BF_S(p->opcode) || OPCODE_BT_S(p->opcode)) {
179d39f5450SChris Smith 			unsigned long disp = (p->opcode & 0x00FF);
180d39f5450SChris Smith 			/* case 1 */
18157fcfdf9SPaul Mundt 			op1->addr = p->addr + 2;
182d39f5450SChris Smith 			/* case 2 */
18357fcfdf9SPaul Mundt 			op2->addr =
184d39f5450SChris Smith 			    (kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
18557fcfdf9SPaul Mundt 			op2->opcode = *(op2->addr);
18657fcfdf9SPaul Mundt 			arch_arm_kprobe(op2);
187d39f5450SChris Smith 
188d39f5450SChris Smith 		} else {
18957fcfdf9SPaul Mundt 			op1->addr = p->addr + 1;
190d39f5450SChris Smith 		}
191d39f5450SChris Smith 
19257fcfdf9SPaul Mundt 		op1->opcode = *(op1->addr);
19357fcfdf9SPaul Mundt 		arch_arm_kprobe(op1);
194d39f5450SChris Smith 	}
195d39f5450SChris Smith }
196d39f5450SChris Smith 
197d39f5450SChris Smith /* Called with kretprobe_lock held */
arch_prepare_kretprobe(struct kretprobe_instance * ri,struct pt_regs * regs)198d39f5450SChris Smith void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
199d39f5450SChris Smith 				      struct pt_regs *regs)
200d39f5450SChris Smith {
201d39f5450SChris Smith 	ri->ret_addr = (kprobe_opcode_t *) regs->pr;
2020cf0e2feSMasami Hiramatsu 	ri->fp = NULL;
203d39f5450SChris Smith 
204d39f5450SChris Smith 	/* Replace the return addr with trampoline addr */
205adf8a61aSMasami Hiramatsu 	regs->pr = (unsigned long)__kretprobe_trampoline;
206d39f5450SChris Smith }
207d39f5450SChris Smith 
kprobe_handler(struct pt_regs * regs)208d39f5450SChris Smith static int __kprobes kprobe_handler(struct pt_regs *regs)
209d39f5450SChris Smith {
210d39f5450SChris Smith 	struct kprobe *p;
211d39f5450SChris Smith 	int ret = 0;
212d39f5450SChris Smith 	kprobe_opcode_t *addr = NULL;
213d39f5450SChris Smith 	struct kprobe_ctlblk *kcb;
214d39f5450SChris Smith 
215d39f5450SChris Smith 	/*
216d39f5450SChris Smith 	 * We don't want to be preempted for the entire
217d39f5450SChris Smith 	 * duration of kprobe processing
218d39f5450SChris Smith 	 */
219d39f5450SChris Smith 	preempt_disable();
220d39f5450SChris Smith 	kcb = get_kprobe_ctlblk();
221d39f5450SChris Smith 
222d39f5450SChris Smith 	addr = (kprobe_opcode_t *) (regs->pc);
223d39f5450SChris Smith 
224d39f5450SChris Smith 	/* Check we're not actually recursing */
225d39f5450SChris Smith 	if (kprobe_running()) {
226d39f5450SChris Smith 		p = get_kprobe(addr);
227d39f5450SChris Smith 		if (p) {
228d39f5450SChris Smith 			if (kcb->kprobe_status == KPROBE_HIT_SS &&
229d39f5450SChris Smith 			    *p->ainsn.insn == BREAKPOINT_INSTRUCTION) {
230d39f5450SChris Smith 				goto no_kprobe;
231d39f5450SChris Smith 			}
232d39f5450SChris Smith 			/* We have reentered the kprobe_handler(), since
233d39f5450SChris Smith 			 * another probe was hit while within the handler.
234d39f5450SChris Smith 			 * We here save the original kprobes variables and
235d39f5450SChris Smith 			 * just single step on the instruction of the new probe
236d39f5450SChris Smith 			 * without calling any user handlers.
237d39f5450SChris Smith 			 */
238d39f5450SChris Smith 			save_previous_kprobe(kcb);
239d39f5450SChris Smith 			set_current_kprobe(p, regs, kcb);
240d39f5450SChris Smith 			kprobes_inc_nmissed_count(p);
241d39f5450SChris Smith 			prepare_singlestep(p, regs);
242d39f5450SChris Smith 			kcb->kprobe_status = KPROBE_REENTER;
243d39f5450SChris Smith 			return 1;
244d39f5450SChris Smith 		}
245d39f5450SChris Smith 		goto no_kprobe;
246d39f5450SChris Smith 	}
247d39f5450SChris Smith 
248d39f5450SChris Smith 	p = get_kprobe(addr);
249d39f5450SChris Smith 	if (!p) {
250d39f5450SChris Smith 		/* Not one of ours: let kernel handle it */
251734db377SPaul Mundt 		if (*(kprobe_opcode_t *)addr != BREAKPOINT_INSTRUCTION) {
252734db377SPaul Mundt 			/*
253734db377SPaul Mundt 			 * The breakpoint instruction was removed right
254734db377SPaul Mundt 			 * after we hit it. Another cpu has removed
255734db377SPaul Mundt 			 * either a probepoint or a debugger breakpoint
256734db377SPaul Mundt 			 * at this address. In either case, no further
257734db377SPaul Mundt 			 * handling of this interrupt is appropriate.
258734db377SPaul Mundt 			 */
259734db377SPaul Mundt 			ret = 1;
260734db377SPaul Mundt 		}
261734db377SPaul Mundt 
262d39f5450SChris Smith 		goto no_kprobe;
263d39f5450SChris Smith 	}
264d39f5450SChris Smith 
265d39f5450SChris Smith 	set_current_kprobe(p, regs, kcb);
266d39f5450SChris Smith 	kcb->kprobe_status = KPROBE_HIT_ACTIVE;
267d39f5450SChris Smith 
268cce188bdSMasami Hiramatsu 	if (p->pre_handler && p->pre_handler(p, regs)) {
269d39f5450SChris Smith 		/* handler has already set things up, so skip ss setup */
270cce188bdSMasami Hiramatsu 		reset_current_kprobe();
271cce188bdSMasami Hiramatsu 		preempt_enable_no_resched();
272d39f5450SChris Smith 		return 1;
273cce188bdSMasami Hiramatsu 	}
274d39f5450SChris Smith 
275d39f5450SChris Smith 	prepare_singlestep(p, regs);
276d39f5450SChris Smith 	kcb->kprobe_status = KPROBE_HIT_SS;
277d39f5450SChris Smith 	return 1;
278d39f5450SChris Smith 
279d39f5450SChris Smith no_kprobe:
280d39f5450SChris Smith 	preempt_enable_no_resched();
281d39f5450SChris Smith 	return ret;
282d39f5450SChris Smith }
283d39f5450SChris Smith 
284d39f5450SChris Smith /*
285d39f5450SChris Smith  * For function-return probes, init_kprobes() establishes a probepoint
286d39f5450SChris Smith  * here. When a retprobed function returns, this probe is hit and
287d39f5450SChris Smith  * trampoline_probe_handler() runs, calling the kretprobe's handler.
288d39f5450SChris Smith  */
kretprobe_trampoline_holder(void)289e7cb016eSPaul Mundt static void __used kretprobe_trampoline_holder(void)
290d39f5450SChris Smith {
291adf8a61aSMasami Hiramatsu 	asm volatile (".globl __kretprobe_trampoline\n"
292adf8a61aSMasami Hiramatsu 		      "__kretprobe_trampoline:\n\t"
2936eb2139bSPaul Mundt 		      "nop\n");
294d39f5450SChris Smith }
295d39f5450SChris Smith 
296d39f5450SChris Smith /*
297adf8a61aSMasami Hiramatsu  * Called when we hit the probe point at __kretprobe_trampoline
298d39f5450SChris Smith  */
trampoline_probe_handler(struct kprobe * p,struct pt_regs * regs)299d39f5450SChris Smith int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
300d39f5450SChris Smith {
30196fed8acSMasami Hiramatsu 	regs->pc = __kretprobe_trampoline_handler(regs, NULL);
302d39f5450SChris Smith 
3030cf0e2feSMasami Hiramatsu 	return 1;
304d39f5450SChris Smith }
305d39f5450SChris Smith 
post_kprobe_handler(struct pt_regs * regs)3064eb5845dSPaul Mundt static int __kprobes post_kprobe_handler(struct pt_regs *regs)
307d39f5450SChris Smith {
308d39f5450SChris Smith 	struct kprobe *cur = kprobe_running();
309d39f5450SChris Smith 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
310d39f5450SChris Smith 	kprobe_opcode_t *addr = NULL;
311d39f5450SChris Smith 	struct kprobe *p = NULL;
312d39f5450SChris Smith 
313d39f5450SChris Smith 	if (!cur)
314d39f5450SChris Smith 		return 0;
315d39f5450SChris Smith 
316d39f5450SChris Smith 	if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {
317d39f5450SChris Smith 		kcb->kprobe_status = KPROBE_HIT_SSDONE;
318d39f5450SChris Smith 		cur->post_handler(cur, regs, 0);
319d39f5450SChris Smith 	}
320d39f5450SChris Smith 
321c473b2c6SChristoph Lameter 	p = this_cpu_ptr(&saved_next_opcode);
32257fcfdf9SPaul Mundt 	if (p->addr) {
32357fcfdf9SPaul Mundt 		arch_disarm_kprobe(p);
32457fcfdf9SPaul Mundt 		p->addr = NULL;
32557fcfdf9SPaul Mundt 		p->opcode = 0;
326d39f5450SChris Smith 
327c473b2c6SChristoph Lameter 		addr = __this_cpu_read(saved_current_opcode.addr);
328c473b2c6SChristoph Lameter 		__this_cpu_write(saved_current_opcode.addr, NULL);
329d39f5450SChris Smith 
330d39f5450SChris Smith 		p = get_kprobe(addr);
331d39f5450SChris Smith 		arch_arm_kprobe(p);
332d39f5450SChris Smith 
333c473b2c6SChristoph Lameter 		p = this_cpu_ptr(&saved_next_opcode2);
33457fcfdf9SPaul Mundt 		if (p->addr) {
33557fcfdf9SPaul Mundt 			arch_disarm_kprobe(p);
33657fcfdf9SPaul Mundt 			p->addr = NULL;
33757fcfdf9SPaul Mundt 			p->opcode = 0;
338d39f5450SChris Smith 		}
339d39f5450SChris Smith 	}
340d39f5450SChris Smith 
341d39f5450SChris Smith 	/* Restore back the original saved kprobes variables and continue. */
342d39f5450SChris Smith 	if (kcb->kprobe_status == KPROBE_REENTER) {
343d39f5450SChris Smith 		restore_previous_kprobe(kcb);
344d39f5450SChris Smith 		goto out;
345d39f5450SChris Smith 	}
3464eb5845dSPaul Mundt 
347d39f5450SChris Smith 	reset_current_kprobe();
348d39f5450SChris Smith 
349d39f5450SChris Smith out:
350d39f5450SChris Smith 	preempt_enable_no_resched();
351d39f5450SChris Smith 
352d39f5450SChris Smith 	return 1;
353d39f5450SChris Smith }
354d39f5450SChris Smith 
kprobe_fault_handler(struct pt_regs * regs,int trapnr)355037c10a6SPaul Mundt int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
356d39f5450SChris Smith {
357d39f5450SChris Smith 	struct kprobe *cur = kprobe_running();
358d39f5450SChris Smith 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
359d39f5450SChris Smith 	const struct exception_table_entry *entry;
360d39f5450SChris Smith 
361d39f5450SChris Smith 	switch (kcb->kprobe_status) {
362d39f5450SChris Smith 	case KPROBE_HIT_SS:
363d39f5450SChris Smith 	case KPROBE_REENTER:
364d39f5450SChris Smith 		/*
365d39f5450SChris Smith 		 * We are here because the instruction being single
366d39f5450SChris Smith 		 * stepped caused a page fault. We reset the current
367d39f5450SChris Smith 		 * kprobe, point the pc back to the probe address
368d39f5450SChris Smith 		 * and allow the page fault handler to continue as a
369d39f5450SChris Smith 		 * normal page fault.
370d39f5450SChris Smith 		 */
371d39f5450SChris Smith 		regs->pc = (unsigned long)cur->addr;
372d39f5450SChris Smith 		if (kcb->kprobe_status == KPROBE_REENTER)
373d39f5450SChris Smith 			restore_previous_kprobe(kcb);
374d39f5450SChris Smith 		else
375d39f5450SChris Smith 			reset_current_kprobe();
376d39f5450SChris Smith 		preempt_enable_no_resched();
377d39f5450SChris Smith 		break;
378d39f5450SChris Smith 	case KPROBE_HIT_ACTIVE:
379d39f5450SChris Smith 	case KPROBE_HIT_SSDONE:
380d39f5450SChris Smith 		/*
381d39f5450SChris Smith 		 * In case the user-specified fault handler returned
382d39f5450SChris Smith 		 * zero, try to fix up.
383d39f5450SChris Smith 		 */
384d39f5450SChris Smith 		if ((entry = search_exception_tables(regs->pc)) != NULL) {
385d39f5450SChris Smith 			regs->pc = entry->fixup;
386d39f5450SChris Smith 			return 1;
387d39f5450SChris Smith 		}
388d39f5450SChris Smith 
389d39f5450SChris Smith 		/*
390d39f5450SChris Smith 		 * fixup_exception() could not handle it,
391d39f5450SChris Smith 		 * Let do_page_fault() fix it.
392d39f5450SChris Smith 		 */
393d39f5450SChris Smith 		break;
394d39f5450SChris Smith 	default:
395d39f5450SChris Smith 		break;
396d39f5450SChris Smith 	}
3974eb5845dSPaul Mundt 
398d39f5450SChris Smith 	return 0;
399d39f5450SChris Smith }
400d39f5450SChris Smith 
401d39f5450SChris Smith /*
402d39f5450SChris Smith  * Wrapper routine to for handling exceptions.
403d39f5450SChris Smith  */
kprobe_exceptions_notify(struct notifier_block * self,unsigned long val,void * data)404d39f5450SChris Smith int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
405d39f5450SChris Smith 				       unsigned long val, void *data)
406d39f5450SChris Smith {
407d39f5450SChris Smith 	struct kprobe *p = NULL;
408d39f5450SChris Smith 	struct die_args *args = (struct die_args *)data;
409d39f5450SChris Smith 	int ret = NOTIFY_DONE;
410d39f5450SChris Smith 	kprobe_opcode_t *addr = NULL;
411d39f5450SChris Smith 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
412d39f5450SChris Smith 
413d39f5450SChris Smith 	addr = (kprobe_opcode_t *) (args->regs->pc);
414d3023897SMichael Karcher 	if (val == DIE_TRAP &&
415d3023897SMichael Karcher 	    args->trapnr == (BREAKPOINT_INSTRUCTION & 0xff)) {
416d39f5450SChris Smith 		if (!kprobe_running()) {
417d39f5450SChris Smith 			if (kprobe_handler(args->regs)) {
418d39f5450SChris Smith 				ret = NOTIFY_STOP;
419d39f5450SChris Smith 			} else {
420d39f5450SChris Smith 				/* Not a kprobe trap */
421ee386de7SPaul Mundt 				ret = NOTIFY_DONE;
422d39f5450SChris Smith 			}
423d39f5450SChris Smith 		} else {
424d39f5450SChris Smith 			p = get_kprobe(addr);
425d39f5450SChris Smith 			if ((kcb->kprobe_status == KPROBE_HIT_SS) ||
426d39f5450SChris Smith 			    (kcb->kprobe_status == KPROBE_REENTER)) {
427d39f5450SChris Smith 				if (post_kprobe_handler(args->regs))
428d39f5450SChris Smith 					ret = NOTIFY_STOP;
429d39f5450SChris Smith 			} else {
430fa5a24b1SMasami Hiramatsu 				if (kprobe_handler(args->regs))
431d39f5450SChris Smith 					ret = NOTIFY_STOP;
432d39f5450SChris Smith 			}
433d39f5450SChris Smith 		}
434d39f5450SChris Smith 	}
435d39f5450SChris Smith 
436d39f5450SChris Smith 	return ret;
437d39f5450SChris Smith }
438d39f5450SChris Smith 
439d39f5450SChris Smith static struct kprobe trampoline_p = {
440adf8a61aSMasami Hiramatsu 	.addr = (kprobe_opcode_t *)&__kretprobe_trampoline,
441d39f5450SChris Smith 	.pre_handler = trampoline_probe_handler
442d39f5450SChris Smith };
443d39f5450SChris Smith 
arch_init_kprobes(void)444d39f5450SChris Smith int __init arch_init_kprobes(void)
445d39f5450SChris Smith {
446d39f5450SChris Smith 	return register_kprobe(&trampoline_p);
447d39f5450SChris Smith }
448