]>
Commit | Line | Data |
---|---|---|
40e084a5 RB |
1 | #include <linux/highmem.h> |
2 | #include <linux/kdebug.h> | |
3 | #include <linux/types.h> | |
4 | #include <linux/notifier.h> | |
5 | #include <linux/sched.h> | |
6 | #include <linux/uprobes.h> | |
7 | ||
8 | #include <asm/branch.h> | |
9 | #include <asm/cpu-features.h> | |
10 | #include <asm/ptrace.h> | |
e3031b32 MN |
11 | |
12 | #include "probes-common.h" | |
40e084a5 RB |
13 | |
14 | static inline int insn_has_delay_slot(const union mips_instruction insn) | |
15 | { | |
e3031b32 | 16 | return __insn_has_delay_slot(insn); |
40e084a5 RB |
17 | } |
18 | ||
19 | /** | |
20 | * arch_uprobe_analyze_insn - instruction analysis including validity and fixups. | |
21 | * @mm: the probed address space. | |
22 | * @arch_uprobe: the probepoint information. | |
23 | * @addr: virtual address at which to install the probepoint | |
24 | * Return 0 on success or a -ve number on error. | |
25 | */ | |
26 | int arch_uprobe_analyze_insn(struct arch_uprobe *aup, | |
27 | struct mm_struct *mm, unsigned long addr) | |
28 | { | |
29 | union mips_instruction inst; | |
30 | ||
31 | /* | |
32 | * For the time being this also blocks attempts to use uprobes with | |
33 | * MIPS16 and microMIPS. | |
34 | */ | |
35 | if (addr & 0x03) | |
36 | return -EINVAL; | |
37 | ||
38 | inst.word = aup->insn[0]; | |
d05c5130 MN |
39 | |
40 | if (__insn_is_compact_branch(inst)) { | |
41 | pr_notice("Uprobes for compact branches are not supported\n"); | |
42 | return -EINVAL; | |
43 | } | |
44 | ||
40e084a5 RB |
45 | aup->ixol[0] = aup->insn[insn_has_delay_slot(inst)]; |
46 | aup->ixol[1] = UPROBE_BRK_UPROBE_XOL; /* NOP */ | |
47 | ||
48 | return 0; | |
49 | } | |
50 | ||
51 | /** | |
52 | * is_trap_insn - check if the instruction is a trap variant | |
53 | * @insn: instruction to be checked. | |
54 | * Returns true if @insn is a trap variant. | |
55 | * | |
56 | * This definition overrides the weak definition in kernel/events/uprobes.c. | |
57 | * and is needed for the case where an architecture has multiple trap | |
58 | * instructions (like PowerPC or MIPS). We treat BREAK just like the more | |
59 | * modern conditional trap instructions. | |
60 | */ | |
61 | bool is_trap_insn(uprobe_opcode_t *insn) | |
62 | { | |
63 | union mips_instruction inst; | |
64 | ||
65 | inst.word = *insn; | |
66 | ||
67 | switch (inst.i_format.opcode) { | |
68 | case spec_op: | |
69 | switch (inst.r_format.func) { | |
70 | case break_op: | |
71 | case teq_op: | |
72 | case tge_op: | |
73 | case tgeu_op: | |
74 | case tlt_op: | |
75 | case tltu_op: | |
76 | case tne_op: | |
77 | return 1; | |
78 | } | |
79 | break; | |
80 | ||
81 | case bcond_op: /* Yes, really ... */ | |
82 | switch (inst.u_format.rt) { | |
83 | case teqi_op: | |
84 | case tgei_op: | |
85 | case tgeiu_op: | |
86 | case tlti_op: | |
87 | case tltiu_op: | |
88 | case tnei_op: | |
89 | return 1; | |
90 | } | |
91 | break; | |
92 | } | |
93 | ||
94 | return 0; | |
95 | } | |
96 | ||
97 | #define UPROBE_TRAP_NR ULONG_MAX | |
98 | ||
99 | /* | |
100 | * arch_uprobe_pre_xol - prepare to execute out of line. | |
101 | * @auprobe: the probepoint information. | |
102 | * @regs: reflects the saved user state of current task. | |
103 | */ | |
104 | int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs) | |
105 | { | |
106 | struct uprobe_task *utask = current->utask; | |
40e084a5 RB |
107 | |
108 | /* | |
109 | * Now find the EPC where to resume after the breakpoint has been | |
110 | * dealt with. This may require emulation of a branch. | |
111 | */ | |
112 | aup->resume_epc = regs->cp0_epc + 4; | |
113 | if (insn_has_delay_slot((union mips_instruction) aup->insn[0])) { | |
114 | unsigned long epc; | |
115 | ||
116 | epc = regs->cp0_epc; | |
ca86c9ef MN |
117 | __compute_return_epc_for_insn(regs, |
118 | (union mips_instruction) aup->insn[0]); | |
40e084a5 RB |
119 | aup->resume_epc = regs->cp0_epc; |
120 | } | |
40e084a5 RB |
121 | utask->autask.saved_trap_nr = current->thread.trap_nr; |
122 | current->thread.trap_nr = UPROBE_TRAP_NR; | |
123 | regs->cp0_epc = current->utask->xol_vaddr; | |
124 | ||
125 | return 0; | |
126 | } | |
127 | ||
128 | int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs) | |
129 | { | |
130 | struct uprobe_task *utask = current->utask; | |
131 | ||
132 | current->thread.trap_nr = utask->autask.saved_trap_nr; | |
133 | regs->cp0_epc = aup->resume_epc; | |
134 | ||
135 | return 0; | |
136 | } | |
137 | ||
138 | /* | |
139 | * If xol insn itself traps and generates a signal(Say, | |
140 | * SIGILL/SIGSEGV/etc), then detect the case where a singlestepped | |
141 | * instruction jumps back to its own address. It is assumed that anything | |
142 | * like do_page_fault/do_trap/etc sets thread.trap_nr != -1. | |
143 | * | |
144 | * arch_uprobe_pre_xol/arch_uprobe_post_xol save/restore thread.trap_nr, | |
145 | * arch_uprobe_xol_was_trapped() simply checks that ->trap_nr is not equal to | |
146 | * UPROBE_TRAP_NR == -1 set by arch_uprobe_pre_xol(). | |
147 | */ | |
148 | bool arch_uprobe_xol_was_trapped(struct task_struct *tsk) | |
149 | { | |
150 | if (tsk->thread.trap_nr != UPROBE_TRAP_NR) | |
151 | return true; | |
152 | ||
153 | return false; | |
154 | } | |
155 | ||
156 | int arch_uprobe_exception_notify(struct notifier_block *self, | |
157 | unsigned long val, void *data) | |
158 | { | |
159 | struct die_args *args = data; | |
160 | struct pt_regs *regs = args->regs; | |
161 | ||
162 | /* regs == NULL is a kernel bug */ | |
163 | if (WARN_ON(!regs)) | |
164 | return NOTIFY_DONE; | |
165 | ||
166 | /* We are only interested in userspace traps */ | |
167 | if (!user_mode(regs)) | |
168 | return NOTIFY_DONE; | |
169 | ||
170 | switch (val) { | |
2809328f | 171 | case DIE_UPROBE: |
40e084a5 RB |
172 | if (uprobe_pre_sstep_notifier(regs)) |
173 | return NOTIFY_STOP; | |
174 | break; | |
175 | case DIE_UPROBE_XOL: | |
176 | if (uprobe_post_sstep_notifier(regs)) | |
177 | return NOTIFY_STOP; | |
178 | default: | |
179 | break; | |
180 | } | |
181 | ||
182 | return 0; | |
183 | } | |
184 | ||
185 | /* | |
186 | * This function gets called when XOL instruction either gets trapped or | |
187 | * the thread has a fatal signal. Reset the instruction pointer to its | |
188 | * probed address for the potential restart or for post mortem analysis. | |
189 | */ | |
190 | void arch_uprobe_abort_xol(struct arch_uprobe *aup, | |
191 | struct pt_regs *regs) | |
192 | { | |
193 | struct uprobe_task *utask = current->utask; | |
194 | ||
195 | instruction_pointer_set(regs, utask->vaddr); | |
196 | } | |
197 | ||
198 | unsigned long arch_uretprobe_hijack_return_addr( | |
199 | unsigned long trampoline_vaddr, struct pt_regs *regs) | |
200 | { | |
201 | unsigned long ra; | |
202 | ||
203 | ra = regs->regs[31]; | |
204 | ||
205 | /* Replace the return address with the trampoline address */ | |
db06068a | 206 | regs->regs[31] = trampoline_vaddr; |
40e084a5 RB |
207 | |
208 | return ra; | |
209 | } | |
210 | ||
211 | /** | |
212 | * set_swbp - store breakpoint at a given address. | |
213 | * @auprobe: arch specific probepoint information. | |
214 | * @mm: the probed process address space. | |
215 | * @vaddr: the virtual address to insert the opcode. | |
216 | * | |
217 | * For mm @mm, store the breakpoint instruction at @vaddr. | |
218 | * Return 0 (success) or a negative errno. | |
219 | * | |
220 | * This version overrides the weak version in kernel/events/uprobes.c. | |
221 | * It is required to handle MIPS16 and microMIPS. | |
222 | */ | |
223 | int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, | |
224 | unsigned long vaddr) | |
225 | { | |
226 | return uprobe_write_opcode(mm, vaddr, UPROBE_SWBP_INSN); | |
227 | } | |
228 | ||
cd854fc6 | 229 | void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, |
40e084a5 RB |
230 | void *src, unsigned long len) |
231 | { | |
d99a043a | 232 | unsigned long kaddr, kstart; |
40e084a5 RB |
233 | |
234 | /* Initialize the slot */ | |
d99a043a JH |
235 | kaddr = (unsigned long)kmap_atomic(page); |
236 | kstart = kaddr + (vaddr & ~PAGE_MASK); | |
237 | memcpy((void *)kstart, src, len); | |
238 | flush_icache_range(kstart, kstart + len); | |
239 | kunmap_atomic((void *)kaddr); | |
40e084a5 RB |
240 | } |
241 | ||
242 | /** | |
243 | * uprobe_get_swbp_addr - compute address of swbp given post-swbp regs | |
244 | * @regs: Reflects the saved state of the task after it has hit a breakpoint | |
245 | * instruction. | |
246 | * Return the address of the breakpoint instruction. | |
247 | * | |
248 | * This overrides the weak version in kernel/events/uprobes.c. | |
249 | */ | |
250 | unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) | |
251 | { | |
252 | return instruction_pointer(regs); | |
253 | } | |
254 | ||
255 | /* | |
256 | * See if the instruction can be emulated. | |
257 | * Returns true if instruction was emulated, false otherwise. | |
258 | * | |
259 | * For now we always emulate so this function just returns 0. | |
260 | */ | |
261 | bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) | |
262 | { | |
263 | return 0; | |
264 | } |