xref: /openbmc/linux/arch/powerpc/kernel/uprobes.c (revision b8d312aa)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * User-space Probes (UProbes) for powerpc
4  *
5  * Copyright IBM Corporation, 2007-2012
6  *
7  * Adapted from the x86 port by Ananth N Mavinakayanahalli <ananth@in.ibm.com>
8  */
9 #include <linux/kernel.h>
10 #include <linux/sched.h>
11 #include <linux/ptrace.h>
12 #include <linux/uprobes.h>
13 #include <linux/uaccess.h>
14 #include <linux/kdebug.h>
15 
16 #include <asm/sstep.h>
17 
18 #define UPROBE_TRAP_NR	UINT_MAX
19 
20 /**
21  * is_trap_insn - check if the instruction is a trap variant
22  * @insn: instruction to be checked.
23  * Returns true if @insn is a trap variant.
24  */
25 bool is_trap_insn(uprobe_opcode_t *insn)
26 {
27 	return (is_trap(*insn));
28 }
29 
30 /**
31  * arch_uprobe_analyze_insn
32  * @mm: the probed address space.
33  * @arch_uprobe: the probepoint information.
34  * @addr: vaddr to probe.
35  * Return 0 on success or a -ve number on error.
36  */
37 int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe,
38 		struct mm_struct *mm, unsigned long addr)
39 {
40 	if (addr & 0x03)
41 		return -EINVAL;
42 
43 	return 0;
44 }
45 
46 /*
47  * arch_uprobe_pre_xol - prepare to execute out of line.
48  * @auprobe: the probepoint information.
49  * @regs: reflects the saved user state of current task.
50  */
51 int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
52 {
53 	struct arch_uprobe_task *autask = &current->utask->autask;
54 
55 	autask->saved_trap_nr = current->thread.trap_nr;
56 	current->thread.trap_nr = UPROBE_TRAP_NR;
57 	regs->nip = current->utask->xol_vaddr;
58 
59 	user_enable_single_step(current);
60 	return 0;
61 }
62 
63 /**
64  * uprobe_get_swbp_addr - compute address of swbp given post-swbp regs
65  * @regs: Reflects the saved state of the task after it has hit a breakpoint
66  * instruction.
67  * Return the address of the breakpoint instruction.
68  */
69 unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
70 {
71 	return instruction_pointer(regs);
72 }
73 
74 /*
75  * If xol insn itself traps and generates a signal (SIGILL/SIGSEGV/etc),
76  * then detect the case where a singlestepped instruction jumps back to its
77  * own address. It is assumed that anything like do_page_fault/do_trap/etc
78  * sets thread.trap_nr != UINT_MAX.
79  *
80  * arch_uprobe_pre_xol/arch_uprobe_post_xol save/restore thread.trap_nr,
81  * arch_uprobe_xol_was_trapped() simply checks that ->trap_nr is not equal to
82  * UPROBE_TRAP_NR == UINT_MAX set by arch_uprobe_pre_xol().
83  */
84 bool arch_uprobe_xol_was_trapped(struct task_struct *t)
85 {
86 	if (t->thread.trap_nr != UPROBE_TRAP_NR)
87 		return true;
88 
89 	return false;
90 }
91 
92 /*
93  * Called after single-stepping. To avoid the SMP problems that can
94  * occur when we temporarily put back the original opcode to
95  * single-step, we single-stepped a copy of the instruction.
96  *
97  * This function prepares to resume execution after the single-step.
98  */
99 int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
100 {
101 	struct uprobe_task *utask = current->utask;
102 
103 	WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR);
104 
105 	current->thread.trap_nr = utask->autask.saved_trap_nr;
106 
107 	/*
108 	 * On powerpc, except for loads and stores, most instructions
109 	 * including ones that alter code flow (branches, calls, returns)
110 	 * are emulated in the kernel. We get here only if the emulation
111 	 * support doesn't exist and have to fix-up the next instruction
112 	 * to be executed.
113 	 */
114 	regs->nip = utask->vaddr + MAX_UINSN_BYTES;
115 
116 	user_disable_single_step(current);
117 	return 0;
118 }
119 
120 /* callback routine for handling exceptions. */
121 int arch_uprobe_exception_notify(struct notifier_block *self,
122 				unsigned long val, void *data)
123 {
124 	struct die_args *args = data;
125 	struct pt_regs *regs = args->regs;
126 
127 	/* regs == NULL is a kernel bug */
128 	if (WARN_ON(!regs))
129 		return NOTIFY_DONE;
130 
131 	/* We are only interested in userspace traps */
132 	if (!user_mode(regs))
133 		return NOTIFY_DONE;
134 
135 	switch (val) {
136 	case DIE_BPT:
137 		if (uprobe_pre_sstep_notifier(regs))
138 			return NOTIFY_STOP;
139 		break;
140 	case DIE_SSTEP:
141 		if (uprobe_post_sstep_notifier(regs))
142 			return NOTIFY_STOP;
143 	default:
144 		break;
145 	}
146 	return NOTIFY_DONE;
147 }
148 
149 /*
150  * This function gets called when XOL instruction either gets trapped or
151  * the thread has a fatal signal, so reset the instruction pointer to its
152  * probed address.
153  */
154 void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
155 {
156 	struct uprobe_task *utask = current->utask;
157 
158 	current->thread.trap_nr = utask->autask.saved_trap_nr;
159 	instruction_pointer_set(regs, utask->vaddr);
160 
161 	user_disable_single_step(current);
162 }
163 
164 /*
165  * See if the instruction can be emulated.
166  * Returns true if instruction was emulated, false otherwise.
167  */
168 bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
169 {
170 	int ret;
171 
172 	/*
173 	 * emulate_step() returns 1 if the insn was successfully emulated.
174 	 * For all other cases, we need to single-step in hardware.
175 	 */
176 	ret = emulate_step(regs, auprobe->insn);
177 	if (ret > 0)
178 		return true;
179 
180 	return false;
181 }
182 
183 unsigned long
184 arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs)
185 {
186 	unsigned long orig_ret_vaddr;
187 
188 	orig_ret_vaddr = regs->link;
189 
190 	/* Replace the return addr with trampoline addr */
191 	regs->link = trampoline_vaddr;
192 
193 	return orig_ret_vaddr;
194 }
195 
196 bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
197 				struct pt_regs *regs)
198 {
199 	if (ctx == RP_CHECK_CHAIN_CALL)
200 		return regs->gpr[1] <= ret->stack;
201 	else
202 		return regs->gpr[1] < ret->stack;
203 }
204