1873e65bcSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c1bf207dSDavid Daney /*
3c1bf207dSDavid Daney * Kernel Probes (KProbes)
4c1bf207dSDavid Daney * arch/mips/kernel/kprobes.c
5c1bf207dSDavid Daney *
6c1bf207dSDavid Daney * Copyright 2006 Sony Corp.
7c1bf207dSDavid Daney * Copyright 2010 Cavium Networks
8c1bf207dSDavid Daney *
9c1bf207dSDavid Daney * Some portions copied from the powerpc version.
10c1bf207dSDavid Daney *
11c1bf207dSDavid Daney * Copyright (C) IBM Corporation, 2002, 2004
12c1bf207dSDavid Daney */
13c1bf207dSDavid Daney
149c89bb8eSMasami Hiramatsu #define pr_fmt(fmt) "kprobes: " fmt
159c89bb8eSMasami Hiramatsu
16c1bf207dSDavid Daney #include <linux/kprobes.h>
17c1bf207dSDavid Daney #include <linux/preempt.h>
1841dde781SManeesh Soni #include <linux/uaccess.h>
19c1bf207dSDavid Daney #include <linux/kdebug.h>
20c1bf207dSDavid Daney #include <linux/slab.h>
21c1bf207dSDavid Daney
22c1bf207dSDavid Daney #include <asm/ptrace.h>
236457a396SManeesh Soni #include <asm/branch.h>
24c1bf207dSDavid Daney #include <asm/break.h>
25e3031b32SMarcin Nowakowski
26e3031b32SMarcin Nowakowski #include "probes-common.h"
27c1bf207dSDavid Daney
28c1bf207dSDavid Daney static const union mips_instruction breakpoint_insn = {
29c1bf207dSDavid Daney .b_format = {
30c1bf207dSDavid Daney .opcode = spec_op,
31c1bf207dSDavid Daney .code = BRK_KPROBE_BP,
32c1bf207dSDavid Daney .func = break_op
33c1bf207dSDavid Daney }
34c1bf207dSDavid Daney };
35c1bf207dSDavid Daney
36c1bf207dSDavid Daney static const union mips_instruction breakpoint2_insn = {
37c1bf207dSDavid Daney .b_format = {
38c1bf207dSDavid Daney .opcode = spec_op,
39c1bf207dSDavid Daney .code = BRK_KPROBE_SSTEPBP,
40c1bf207dSDavid Daney .func = break_op
41c1bf207dSDavid Daney }
42c1bf207dSDavid Daney };
43c1bf207dSDavid Daney
44c1bf207dSDavid Daney DEFINE_PER_CPU(struct kprobe *, current_kprobe);
45c1bf207dSDavid Daney DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
46c1bf207dSDavid Daney
insn_has_delayslot(union mips_instruction insn)47*f5e2d818STiezhu Yang static int insn_has_delayslot(union mips_instruction insn)
48c1bf207dSDavid Daney {
49e3031b32SMarcin Nowakowski return __insn_has_delay_slot(insn);
50c1bf207dSDavid Daney }
51*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(insn_has_delayslot);
52c1bf207dSDavid Daney
539233c1eeSManeesh Soni /*
549233c1eeSManeesh Soni * insn_has_ll_or_sc function checks whether instruction is ll or sc
559233c1eeSManeesh Soni * one; putting breakpoint on top of atomic ll/sc pair is bad idea;
569233c1eeSManeesh Soni * so we need to prevent it and refuse kprobes insertion for such
579233c1eeSManeesh Soni * instructions; cannot do much about breakpoint in the middle of
589233c1eeSManeesh Soni * ll/sc pair; it is upto user to avoid those places
599233c1eeSManeesh Soni */
insn_has_ll_or_sc(union mips_instruction insn)60*f5e2d818STiezhu Yang static int insn_has_ll_or_sc(union mips_instruction insn)
619233c1eeSManeesh Soni {
629233c1eeSManeesh Soni int ret = 0;
639233c1eeSManeesh Soni
649233c1eeSManeesh Soni switch (insn.i_format.opcode) {
659233c1eeSManeesh Soni case ll_op:
669233c1eeSManeesh Soni case lld_op:
679233c1eeSManeesh Soni case sc_op:
689233c1eeSManeesh Soni case scd_op:
699233c1eeSManeesh Soni ret = 1;
709233c1eeSManeesh Soni break;
719233c1eeSManeesh Soni default:
729233c1eeSManeesh Soni break;
739233c1eeSManeesh Soni }
749233c1eeSManeesh Soni return ret;
759233c1eeSManeesh Soni }
76*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(insn_has_ll_or_sc);
779233c1eeSManeesh Soni
arch_prepare_kprobe(struct kprobe * p)78*f5e2d818STiezhu Yang int arch_prepare_kprobe(struct kprobe *p)
79c1bf207dSDavid Daney {
80c1bf207dSDavid Daney union mips_instruction insn;
81c1bf207dSDavid Daney union mips_instruction prev_insn;
82c1bf207dSDavid Daney int ret = 0;
83c1bf207dSDavid Daney
84c1bf207dSDavid Daney insn = p->addr[0];
85c1bf207dSDavid Daney
869233c1eeSManeesh Soni if (insn_has_ll_or_sc(insn)) {
879c89bb8eSMasami Hiramatsu pr_notice("Kprobes for ll and sc instructions are not supported\n");
889233c1eeSManeesh Soni ret = -EINVAL;
899233c1eeSManeesh Soni goto out;
909233c1eeSManeesh Soni }
919233c1eeSManeesh Soni
92fe557319SChristoph Hellwig if (copy_from_kernel_nofault(&prev_insn, p->addr - 1,
93fe557319SChristoph Hellwig sizeof(mips_instruction)) == 0 &&
9441dde781SManeesh Soni insn_has_delayslot(prev_insn)) {
9541dde781SManeesh Soni pr_notice("Kprobes for branch delayslot are not supported\n");
96c1bf207dSDavid Daney ret = -EINVAL;
97c1bf207dSDavid Daney goto out;
98c1bf207dSDavid Daney }
99c1bf207dSDavid Daney
100d05c5130SMarcin Nowakowski if (__insn_is_compact_branch(insn)) {
101d05c5130SMarcin Nowakowski pr_notice("Kprobes for compact branches are not supported\n");
102d05c5130SMarcin Nowakowski ret = -EINVAL;
103d05c5130SMarcin Nowakowski goto out;
104d05c5130SMarcin Nowakowski }
105d05c5130SMarcin Nowakowski
106c1bf207dSDavid Daney /* insn: must be on special executable page on mips. */
107c1bf207dSDavid Daney p->ainsn.insn = get_insn_slot();
108c1bf207dSDavid Daney if (!p->ainsn.insn) {
109c1bf207dSDavid Daney ret = -ENOMEM;
110c1bf207dSDavid Daney goto out;
111c1bf207dSDavid Daney }
112c1bf207dSDavid Daney
113c1bf207dSDavid Daney /*
114c1bf207dSDavid Daney * In the kprobe->ainsn.insn[] array we store the original
115c1bf207dSDavid Daney * instruction at index zero and a break trap instruction at
116c1bf207dSDavid Daney * index one.
1176457a396SManeesh Soni *
1186457a396SManeesh Soni * On MIPS arch if the instruction at probed address is a
1196457a396SManeesh Soni * branch instruction, we need to execute the instruction at
1206457a396SManeesh Soni * Branch Delayslot (BD) at the time of probe hit. As MIPS also
1216457a396SManeesh Soni * doesn't have single stepping support, the BD instruction can
1226457a396SManeesh Soni * not be executed in-line and it would be executed on SSOL slot
1236457a396SManeesh Soni * using a normal breakpoint instruction in the next slot.
1246457a396SManeesh Soni * So, read the instruction and save it for later execution.
125c1bf207dSDavid Daney */
1266457a396SManeesh Soni if (insn_has_delayslot(insn))
1276457a396SManeesh Soni memcpy(&p->ainsn.insn[0], p->addr + 1, sizeof(kprobe_opcode_t));
1286457a396SManeesh Soni else
129c1bf207dSDavid Daney memcpy(&p->ainsn.insn[0], p->addr, sizeof(kprobe_opcode_t));
1306457a396SManeesh Soni
131c1bf207dSDavid Daney p->ainsn.insn[1] = breakpoint2_insn;
132c1bf207dSDavid Daney p->opcode = *p->addr;
133c1bf207dSDavid Daney
134c1bf207dSDavid Daney out:
135c1bf207dSDavid Daney return ret;
136c1bf207dSDavid Daney }
137*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(arch_prepare_kprobe);
138c1bf207dSDavid Daney
arch_arm_kprobe(struct kprobe * p)139*f5e2d818STiezhu Yang void arch_arm_kprobe(struct kprobe *p)
140c1bf207dSDavid Daney {
141c1bf207dSDavid Daney *p->addr = breakpoint_insn;
142c1bf207dSDavid Daney flush_insn_slot(p);
143c1bf207dSDavid Daney }
144*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(arch_arm_kprobe);
145c1bf207dSDavid Daney
arch_disarm_kprobe(struct kprobe * p)146*f5e2d818STiezhu Yang void arch_disarm_kprobe(struct kprobe *p)
147c1bf207dSDavid Daney {
148c1bf207dSDavid Daney *p->addr = p->opcode;
149c1bf207dSDavid Daney flush_insn_slot(p);
150c1bf207dSDavid Daney }
151*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(arch_disarm_kprobe);
152c1bf207dSDavid Daney
arch_remove_kprobe(struct kprobe * p)153*f5e2d818STiezhu Yang void arch_remove_kprobe(struct kprobe *p)
154c1bf207dSDavid Daney {
15522047b85SMasami Hiramatsu if (p->ainsn.insn) {
156c1bf207dSDavid Daney free_insn_slot(p->ainsn.insn, 0);
15722047b85SMasami Hiramatsu p->ainsn.insn = NULL;
15822047b85SMasami Hiramatsu }
159c1bf207dSDavid Daney }
160*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(arch_remove_kprobe);
161c1bf207dSDavid Daney
save_previous_kprobe(struct kprobe_ctlblk * kcb)162c1bf207dSDavid Daney static void save_previous_kprobe(struct kprobe_ctlblk *kcb)
163c1bf207dSDavid Daney {
164c1bf207dSDavid Daney kcb->prev_kprobe.kp = kprobe_running();
165c1bf207dSDavid Daney kcb->prev_kprobe.status = kcb->kprobe_status;
166c1bf207dSDavid Daney kcb->prev_kprobe.old_SR = kcb->kprobe_old_SR;
167c1bf207dSDavid Daney kcb->prev_kprobe.saved_SR = kcb->kprobe_saved_SR;
168c1bf207dSDavid Daney kcb->prev_kprobe.saved_epc = kcb->kprobe_saved_epc;
169c1bf207dSDavid Daney }
170c1bf207dSDavid Daney
restore_previous_kprobe(struct kprobe_ctlblk * kcb)171c1bf207dSDavid Daney static void restore_previous_kprobe(struct kprobe_ctlblk *kcb)
172c1bf207dSDavid Daney {
17335898716SChristoph Lameter __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
174c1bf207dSDavid Daney kcb->kprobe_status = kcb->prev_kprobe.status;
175c1bf207dSDavid Daney kcb->kprobe_old_SR = kcb->prev_kprobe.old_SR;
176c1bf207dSDavid Daney kcb->kprobe_saved_SR = kcb->prev_kprobe.saved_SR;
177c1bf207dSDavid Daney kcb->kprobe_saved_epc = kcb->prev_kprobe.saved_epc;
178c1bf207dSDavid Daney }
179c1bf207dSDavid Daney
set_current_kprobe(struct kprobe * p,struct pt_regs * regs,struct kprobe_ctlblk * kcb)180c1bf207dSDavid Daney static void set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
181c1bf207dSDavid Daney struct kprobe_ctlblk *kcb)
182c1bf207dSDavid Daney {
18335898716SChristoph Lameter __this_cpu_write(current_kprobe, p);
184c1bf207dSDavid Daney kcb->kprobe_saved_SR = kcb->kprobe_old_SR = (regs->cp0_status & ST0_IE);
185c1bf207dSDavid Daney kcb->kprobe_saved_epc = regs->cp0_epc;
186c1bf207dSDavid Daney }
187c1bf207dSDavid Daney
1886457a396SManeesh Soni /**
1896457a396SManeesh Soni * evaluate_branch_instrucion -
1906457a396SManeesh Soni *
1916457a396SManeesh Soni * Evaluate the branch instruction at probed address during probe hit. The
1926457a396SManeesh Soni * result of evaluation would be the updated epc. The insturction in delayslot
1936457a396SManeesh Soni * would actually be single stepped using a normal breakpoint) on SSOL slot.
1946457a396SManeesh Soni *
1956457a396SManeesh Soni * The result is also saved in the kprobe control block for later use,
1966457a396SManeesh Soni * in case we need to execute the delayslot instruction. The latter will be
1976457a396SManeesh Soni * false for NOP instruction in dealyslot and the branch-likely instructions
1986457a396SManeesh Soni * when the branch is taken. And for those cases we set a flag as
1996457a396SManeesh Soni * SKIP_DELAYSLOT in the kprobe control block
2006457a396SManeesh Soni */
evaluate_branch_instruction(struct kprobe * p,struct pt_regs * regs,struct kprobe_ctlblk * kcb)2016457a396SManeesh Soni static int evaluate_branch_instruction(struct kprobe *p, struct pt_regs *regs,
2026457a396SManeesh Soni struct kprobe_ctlblk *kcb)
203c1bf207dSDavid Daney {
2046457a396SManeesh Soni union mips_instruction insn = p->opcode;
2056457a396SManeesh Soni long epc;
2066457a396SManeesh Soni int ret = 0;
2076457a396SManeesh Soni
2086457a396SManeesh Soni epc = regs->cp0_epc;
2096457a396SManeesh Soni if (epc & 3)
2106457a396SManeesh Soni goto unaligned;
2116457a396SManeesh Soni
2126457a396SManeesh Soni if (p->ainsn.insn->word == 0)
2136457a396SManeesh Soni kcb->flags |= SKIP_DELAYSLOT;
2146457a396SManeesh Soni else
2156457a396SManeesh Soni kcb->flags &= ~SKIP_DELAYSLOT;
2166457a396SManeesh Soni
2176457a396SManeesh Soni ret = __compute_return_epc_for_insn(regs, insn);
2186457a396SManeesh Soni if (ret < 0)
2196457a396SManeesh Soni return ret;
2206457a396SManeesh Soni
2216457a396SManeesh Soni if (ret == BRANCH_LIKELY_TAKEN)
2226457a396SManeesh Soni kcb->flags |= SKIP_DELAYSLOT;
2236457a396SManeesh Soni
2246457a396SManeesh Soni kcb->target_epc = regs->cp0_epc;
2256457a396SManeesh Soni
2266457a396SManeesh Soni return 0;
2276457a396SManeesh Soni
2286457a396SManeesh Soni unaligned:
2299c89bb8eSMasami Hiramatsu pr_notice("Failed to emulate branch instruction because of unaligned epc - sending SIGBUS to %s.\n", current->comm);
2303cf5d076SEric W. Biederman force_sig(SIGBUS);
2316457a396SManeesh Soni return -EFAULT;
2326457a396SManeesh Soni
2336457a396SManeesh Soni }
2346457a396SManeesh Soni
prepare_singlestep(struct kprobe * p,struct pt_regs * regs,struct kprobe_ctlblk * kcb)2356457a396SManeesh Soni static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs,
2366457a396SManeesh Soni struct kprobe_ctlblk *kcb)
2376457a396SManeesh Soni {
2386457a396SManeesh Soni int ret = 0;
2396457a396SManeesh Soni
240c1bf207dSDavid Daney regs->cp0_status &= ~ST0_IE;
241c1bf207dSDavid Daney
242c1bf207dSDavid Daney /* single step inline if the instruction is a break */
243c1bf207dSDavid Daney if (p->opcode.word == breakpoint_insn.word ||
244c1bf207dSDavid Daney p->opcode.word == breakpoint2_insn.word)
245c1bf207dSDavid Daney regs->cp0_epc = (unsigned long)p->addr;
2466457a396SManeesh Soni else if (insn_has_delayslot(p->opcode)) {
2476457a396SManeesh Soni ret = evaluate_branch_instruction(p, regs, kcb);
2489c89bb8eSMasami Hiramatsu if (ret < 0)
2496457a396SManeesh Soni return;
2506457a396SManeesh Soni }
251c1bf207dSDavid Daney regs->cp0_epc = (unsigned long)&p->ainsn.insn[0];
252c1bf207dSDavid Daney }
253c1bf207dSDavid Daney
2546457a396SManeesh Soni /*
2556457a396SManeesh Soni * Called after single-stepping. p->addr is the address of the
2566457a396SManeesh Soni * instruction whose first byte has been replaced by the "break 0"
2576457a396SManeesh Soni * instruction. To avoid the SMP problems that can occur when we
2586457a396SManeesh Soni * temporarily put back the original opcode to single-step, we
2596457a396SManeesh Soni * single-stepped a copy of the instruction. The address of this
2606457a396SManeesh Soni * copy is p->ainsn.insn.
2616457a396SManeesh Soni *
2626457a396SManeesh Soni * This function prepares to return from the post-single-step
2636457a396SManeesh Soni * breakpoint trap. In case of branch instructions, the target
2646457a396SManeesh Soni * epc to be restored.
2656457a396SManeesh Soni */
resume_execution(struct kprobe * p,struct pt_regs * regs,struct kprobe_ctlblk * kcb)266*f5e2d818STiezhu Yang static void resume_execution(struct kprobe *p,
2676457a396SManeesh Soni struct pt_regs *regs,
2686457a396SManeesh Soni struct kprobe_ctlblk *kcb)
2696457a396SManeesh Soni {
2706457a396SManeesh Soni if (insn_has_delayslot(p->opcode))
2716457a396SManeesh Soni regs->cp0_epc = kcb->target_epc;
2726457a396SManeesh Soni else {
2736457a396SManeesh Soni unsigned long orig_epc = kcb->kprobe_saved_epc;
2746457a396SManeesh Soni regs->cp0_epc = orig_epc + 4;
2756457a396SManeesh Soni }
2766457a396SManeesh Soni }
277*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(resume_execution);
2786457a396SManeesh Soni
kprobe_handler(struct pt_regs * regs)279*f5e2d818STiezhu Yang static int kprobe_handler(struct pt_regs *regs)
280c1bf207dSDavid Daney {
281c1bf207dSDavid Daney struct kprobe *p;
282c1bf207dSDavid Daney int ret = 0;
283c1bf207dSDavid Daney kprobe_opcode_t *addr;
284c1bf207dSDavid Daney struct kprobe_ctlblk *kcb;
285c1bf207dSDavid Daney
286c1bf207dSDavid Daney addr = (kprobe_opcode_t *) regs->cp0_epc;
287c1bf207dSDavid Daney
288c1bf207dSDavid Daney /*
289c1bf207dSDavid Daney * We don't want to be preempted for the entire
290c1bf207dSDavid Daney * duration of kprobe processing
291c1bf207dSDavid Daney */
292c1bf207dSDavid Daney preempt_disable();
293c1bf207dSDavid Daney kcb = get_kprobe_ctlblk();
294c1bf207dSDavid Daney
295c1bf207dSDavid Daney /* Check we're not actually recursing */
296c1bf207dSDavid Daney if (kprobe_running()) {
297c1bf207dSDavid Daney p = get_kprobe(addr);
298c1bf207dSDavid Daney if (p) {
299c1bf207dSDavid Daney if (kcb->kprobe_status == KPROBE_HIT_SS &&
300c1bf207dSDavid Daney p->ainsn.insn->word == breakpoint_insn.word) {
301c1bf207dSDavid Daney regs->cp0_status &= ~ST0_IE;
302c1bf207dSDavid Daney regs->cp0_status |= kcb->kprobe_saved_SR;
303c1bf207dSDavid Daney goto no_kprobe;
304c1bf207dSDavid Daney }
305c1bf207dSDavid Daney /*
306c1bf207dSDavid Daney * We have reentered the kprobe_handler(), since
307c1bf207dSDavid Daney * another probe was hit while within the handler.
308c1bf207dSDavid Daney * We here save the original kprobes variables and
309c1bf207dSDavid Daney * just single step on the instruction of the new probe
310c1bf207dSDavid Daney * without calling any user handlers.
311c1bf207dSDavid Daney */
312c1bf207dSDavid Daney save_previous_kprobe(kcb);
313c1bf207dSDavid Daney set_current_kprobe(p, regs, kcb);
314c1bf207dSDavid Daney kprobes_inc_nmissed_count(p);
3156457a396SManeesh Soni prepare_singlestep(p, regs, kcb);
316c1bf207dSDavid Daney kcb->kprobe_status = KPROBE_REENTER;
3176457a396SManeesh Soni if (kcb->flags & SKIP_DELAYSLOT) {
3186457a396SManeesh Soni resume_execution(p, regs, kcb);
3196457a396SManeesh Soni restore_previous_kprobe(kcb);
3206457a396SManeesh Soni preempt_enable_no_resched();
3216457a396SManeesh Soni }
322c1bf207dSDavid Daney return 1;
3239b85753dSMasami Hiramatsu } else if (addr->word != breakpoint_insn.word) {
324c1bf207dSDavid Daney /*
325c1bf207dSDavid Daney * The breakpoint instruction was removed by
326c1bf207dSDavid Daney * another cpu right after we hit, no further
327c1bf207dSDavid Daney * handling of this interrupt is appropriate
328c1bf207dSDavid Daney */
329c1bf207dSDavid Daney ret = 1;
330c1bf207dSDavid Daney }
331c1bf207dSDavid Daney goto no_kprobe;
332c1bf207dSDavid Daney }
333c1bf207dSDavid Daney
334c1bf207dSDavid Daney p = get_kprobe(addr);
335c1bf207dSDavid Daney if (!p) {
336c1bf207dSDavid Daney if (addr->word != breakpoint_insn.word) {
337c1bf207dSDavid Daney /*
338c1bf207dSDavid Daney * The breakpoint instruction was removed right
339c1bf207dSDavid Daney * after we hit it. Another cpu has removed
340c1bf207dSDavid Daney * either a probepoint or a debugger breakpoint
341c1bf207dSDavid Daney * at this address. In either case, no further
342c1bf207dSDavid Daney * handling of this interrupt is appropriate.
343c1bf207dSDavid Daney */
344c1bf207dSDavid Daney ret = 1;
345c1bf207dSDavid Daney }
346c1bf207dSDavid Daney /* Not one of ours: let kernel handle it */
347c1bf207dSDavid Daney goto no_kprobe;
348c1bf207dSDavid Daney }
349c1bf207dSDavid Daney
350c1bf207dSDavid Daney set_current_kprobe(p, regs, kcb);
351c1bf207dSDavid Daney kcb->kprobe_status = KPROBE_HIT_ACTIVE;
352c1bf207dSDavid Daney
353c1bf207dSDavid Daney if (p->pre_handler && p->pre_handler(p, regs)) {
354c1bf207dSDavid Daney /* handler has already set things up, so skip ss setup */
355cce188bdSMasami Hiramatsu reset_current_kprobe();
356cce188bdSMasami Hiramatsu preempt_enable_no_resched();
357c1bf207dSDavid Daney return 1;
358c1bf207dSDavid Daney }
359c1bf207dSDavid Daney
3606457a396SManeesh Soni prepare_singlestep(p, regs, kcb);
3616457a396SManeesh Soni if (kcb->flags & SKIP_DELAYSLOT) {
3626457a396SManeesh Soni kcb->kprobe_status = KPROBE_HIT_SSDONE;
3636457a396SManeesh Soni if (p->post_handler)
3646457a396SManeesh Soni p->post_handler(p, regs, 0);
3656457a396SManeesh Soni resume_execution(p, regs, kcb);
3666457a396SManeesh Soni preempt_enable_no_resched();
3676457a396SManeesh Soni } else
368c1bf207dSDavid Daney kcb->kprobe_status = KPROBE_HIT_SS;
3696457a396SManeesh Soni
370c1bf207dSDavid Daney return 1;
371c1bf207dSDavid Daney
372c1bf207dSDavid Daney no_kprobe:
373c1bf207dSDavid Daney preempt_enable_no_resched();
374c1bf207dSDavid Daney return ret;
375c1bf207dSDavid Daney
376c1bf207dSDavid Daney }
377*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(kprobe_handler);
378c1bf207dSDavid Daney
post_kprobe_handler(struct pt_regs * regs)379c1bf207dSDavid Daney static inline int post_kprobe_handler(struct pt_regs *regs)
380c1bf207dSDavid Daney {
381c1bf207dSDavid Daney struct kprobe *cur = kprobe_running();
382c1bf207dSDavid Daney struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
383c1bf207dSDavid Daney
384c1bf207dSDavid Daney if (!cur)
385c1bf207dSDavid Daney return 0;
386c1bf207dSDavid Daney
387c1bf207dSDavid Daney if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {
388c1bf207dSDavid Daney kcb->kprobe_status = KPROBE_HIT_SSDONE;
389c1bf207dSDavid Daney cur->post_handler(cur, regs, 0);
390c1bf207dSDavid Daney }
391c1bf207dSDavid Daney
392c1bf207dSDavid Daney resume_execution(cur, regs, kcb);
393c1bf207dSDavid Daney
394c1bf207dSDavid Daney regs->cp0_status |= kcb->kprobe_saved_SR;
395c1bf207dSDavid Daney
396c1bf207dSDavid Daney /* Restore back the original saved kprobes variables and continue. */
397c1bf207dSDavid Daney if (kcb->kprobe_status == KPROBE_REENTER) {
398c1bf207dSDavid Daney restore_previous_kprobe(kcb);
399c1bf207dSDavid Daney goto out;
400c1bf207dSDavid Daney }
401c1bf207dSDavid Daney reset_current_kprobe();
402c1bf207dSDavid Daney out:
403c1bf207dSDavid Daney preempt_enable_no_resched();
404c1bf207dSDavid Daney
405c1bf207dSDavid Daney return 1;
406c1bf207dSDavid Daney }
407c1bf207dSDavid Daney
kprobe_fault_handler(struct pt_regs * regs,int trapnr)408b98cca44SAnshuman Khandual int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
409c1bf207dSDavid Daney {
410c1bf207dSDavid Daney struct kprobe *cur = kprobe_running();
411c1bf207dSDavid Daney struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
412c1bf207dSDavid Daney
413c1bf207dSDavid Daney if (kcb->kprobe_status & KPROBE_HIT_SS) {
414c1bf207dSDavid Daney resume_execution(cur, regs, kcb);
415c1bf207dSDavid Daney regs->cp0_status |= kcb->kprobe_old_SR;
416c1bf207dSDavid Daney
417c1bf207dSDavid Daney reset_current_kprobe();
418c1bf207dSDavid Daney preempt_enable_no_resched();
419c1bf207dSDavid Daney }
420c1bf207dSDavid Daney return 0;
421c1bf207dSDavid Daney }
422c1bf207dSDavid Daney
423c1bf207dSDavid Daney /*
424c1bf207dSDavid Daney * Wrapper routine for handling exceptions.
425c1bf207dSDavid Daney */
kprobe_exceptions_notify(struct notifier_block * self,unsigned long val,void * data)426*f5e2d818STiezhu Yang int kprobe_exceptions_notify(struct notifier_block *self,
427c1bf207dSDavid Daney unsigned long val, void *data)
428c1bf207dSDavid Daney {
429c1bf207dSDavid Daney
430c1bf207dSDavid Daney struct die_args *args = (struct die_args *)data;
431c1bf207dSDavid Daney int ret = NOTIFY_DONE;
432c1bf207dSDavid Daney
433c1bf207dSDavid Daney switch (val) {
434c1bf207dSDavid Daney case DIE_BREAK:
435c1bf207dSDavid Daney if (kprobe_handler(args->regs))
436c1bf207dSDavid Daney ret = NOTIFY_STOP;
437c1bf207dSDavid Daney break;
438c1bf207dSDavid Daney case DIE_SSTEPBP:
439c1bf207dSDavid Daney if (post_kprobe_handler(args->regs))
440c1bf207dSDavid Daney ret = NOTIFY_STOP;
441c1bf207dSDavid Daney break;
442c1bf207dSDavid Daney
443c1bf207dSDavid Daney case DIE_PAGE_FAULT:
444c1bf207dSDavid Daney /* kprobe_running() needs smp_processor_id() */
445c1bf207dSDavid Daney preempt_disable();
446c1bf207dSDavid Daney
447c1bf207dSDavid Daney if (kprobe_running()
448c1bf207dSDavid Daney && kprobe_fault_handler(args->regs, args->trapnr))
449c1bf207dSDavid Daney ret = NOTIFY_STOP;
450c1bf207dSDavid Daney preempt_enable();
451c1bf207dSDavid Daney break;
452c1bf207dSDavid Daney default:
453c1bf207dSDavid Daney break;
454c1bf207dSDavid Daney }
455c1bf207dSDavid Daney return ret;
456c1bf207dSDavid Daney }
457*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(kprobe_exceptions_notify);
458c1bf207dSDavid Daney
459c1bf207dSDavid Daney /*
460c1bf207dSDavid Daney * Function return probe trampoline:
461c1bf207dSDavid Daney * - init_kprobes() establishes a probepoint here
462c1bf207dSDavid Daney * - When the probed function returns, this probe causes the
463c1bf207dSDavid Daney * handlers to fire
464c1bf207dSDavid Daney */
kretprobe_trampoline_holder(void)465c1bf207dSDavid Daney static void __used kretprobe_trampoline_holder(void)
466c1bf207dSDavid Daney {
467c1bf207dSDavid Daney asm volatile(
468c1bf207dSDavid Daney ".set push\n\t"
469c1bf207dSDavid Daney /* Keep the assembler from reordering and placing JR here. */
470c1bf207dSDavid Daney ".set noreorder\n\t"
471c1bf207dSDavid Daney "nop\n\t"
472adf8a61aSMasami Hiramatsu ".global __kretprobe_trampoline\n"
473adf8a61aSMasami Hiramatsu "__kretprobe_trampoline:\n\t"
474c1bf207dSDavid Daney "nop\n\t"
475c1bf207dSDavid Daney ".set pop"
476c1bf207dSDavid Daney : : : "memory");
477c1bf207dSDavid Daney }
478c1bf207dSDavid Daney
479adf8a61aSMasami Hiramatsu void __kretprobe_trampoline(void);
480c1bf207dSDavid Daney
arch_prepare_kretprobe(struct kretprobe_instance * ri,struct pt_regs * regs)481*f5e2d818STiezhu Yang void arch_prepare_kretprobe(struct kretprobe_instance *ri,
482c1bf207dSDavid Daney struct pt_regs *regs)
483c1bf207dSDavid Daney {
484c1bf207dSDavid Daney ri->ret_addr = (kprobe_opcode_t *) regs->regs[31];
4852ef12450SMasami Hiramatsu ri->fp = NULL;
486c1bf207dSDavid Daney
487c1bf207dSDavid Daney /* Replace the return addr with trampoline addr */
488adf8a61aSMasami Hiramatsu regs->regs[31] = (unsigned long)__kretprobe_trampoline;
489c1bf207dSDavid Daney }
490*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(arch_prepare_kretprobe);
491c1bf207dSDavid Daney
492c1bf207dSDavid Daney /*
493c1bf207dSDavid Daney * Called when the probe at kretprobe trampoline is hit
494c1bf207dSDavid Daney */
trampoline_probe_handler(struct kprobe * p,struct pt_regs * regs)495*f5e2d818STiezhu Yang static int trampoline_probe_handler(struct kprobe *p,
496c1bf207dSDavid Daney struct pt_regs *regs)
497c1bf207dSDavid Daney {
49896fed8acSMasami Hiramatsu instruction_pointer(regs) = __kretprobe_trampoline_handler(regs, NULL);
499c1bf207dSDavid Daney /*
500c1bf207dSDavid Daney * By returning a non-zero value, we are telling
501c1bf207dSDavid Daney * kprobe_handler() that we don't want the post_handler
502c1bf207dSDavid Daney * to run (and have re-enabled preemption)
503c1bf207dSDavid Daney */
504c1bf207dSDavid Daney return 1;
505c1bf207dSDavid Daney }
506*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(trampoline_probe_handler);
507c1bf207dSDavid Daney
arch_trampoline_kprobe(struct kprobe * p)508*f5e2d818STiezhu Yang int arch_trampoline_kprobe(struct kprobe *p)
509c1bf207dSDavid Daney {
510adf8a61aSMasami Hiramatsu if (p->addr == (kprobe_opcode_t *)__kretprobe_trampoline)
511c1bf207dSDavid Daney return 1;
512c1bf207dSDavid Daney
513c1bf207dSDavid Daney return 0;
514c1bf207dSDavid Daney }
515*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(arch_trampoline_kprobe);
516c1bf207dSDavid Daney
517c1bf207dSDavid Daney static struct kprobe trampoline_p = {
518adf8a61aSMasami Hiramatsu .addr = (kprobe_opcode_t *)__kretprobe_trampoline,
519c1bf207dSDavid Daney .pre_handler = trampoline_probe_handler
520c1bf207dSDavid Daney };
521c1bf207dSDavid Daney
arch_init_kprobes(void)522c1bf207dSDavid Daney int __init arch_init_kprobes(void)
523c1bf207dSDavid Daney {
524c1bf207dSDavid Daney return register_kprobe(&trampoline_p);
525c1bf207dSDavid Daney }
526