1
2
3
4
5
6
7
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#include <asm/inst.h>
18
19#define UPROBE_TRAP_NR UINT_MAX
20
21
22
23
24
25
26bool is_trap_insn(uprobe_opcode_t *insn)
27{
28 return (is_trap(*insn));
29}
30
31
32
33
34
35
36
37
38int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe,
39 struct mm_struct *mm, unsigned long addr)
40{
41 if (addr & 0x03)
42 return -EINVAL;
43
44 if (cpu_has_feature(CPU_FTR_ARCH_31) &&
45 ppc_inst_prefixed(ppc_inst_read(auprobe->insn)) &&
46 (addr & 0x3f) == 60) {
47 pr_info_ratelimited("Cannot register a uprobe on 64 byte unaligned prefixed instruction\n");
48 return -EINVAL;
49 }
50
51 return 0;
52}
53
54
55
56
57
58
59int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
60{
61 struct arch_uprobe_task *autask = ¤t->utask->autask;
62
63 autask->saved_trap_nr = current->thread.trap_nr;
64 current->thread.trap_nr = UPROBE_TRAP_NR;
65 regs_set_return_ip(regs, current->utask->xol_vaddr);
66
67 user_enable_single_step(current);
68 return 0;
69}
70
71
72
73
74
75
76
77unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
78{
79 return instruction_pointer(regs);
80}
81
82
83
84
85
86
87
88
89
90
91
92bool arch_uprobe_xol_was_trapped(struct task_struct *t)
93{
94 if (t->thread.trap_nr != UPROBE_TRAP_NR)
95 return true;
96
97 return false;
98}
99
100
101
102
103
104
105
106
107int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
108{
109 struct uprobe_task *utask = current->utask;
110
111 WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR);
112
113 current->thread.trap_nr = utask->autask.saved_trap_nr;
114
115
116
117
118
119
120
121
122 regs_set_return_ip(regs, (unsigned long)ppc_inst_next((void *)utask->vaddr, auprobe->insn));
123
124 user_disable_single_step(current);
125 return 0;
126}
127
128
129int arch_uprobe_exception_notify(struct notifier_block *self,
130 unsigned long val, void *data)
131{
132 struct die_args *args = data;
133 struct pt_regs *regs = args->regs;
134
135
136 if (WARN_ON(!regs))
137 return NOTIFY_DONE;
138
139
140 if (!user_mode(regs))
141 return NOTIFY_DONE;
142
143 switch (val) {
144 case DIE_BPT:
145 if (uprobe_pre_sstep_notifier(regs))
146 return NOTIFY_STOP;
147 break;
148 case DIE_SSTEP:
149 if (uprobe_post_sstep_notifier(regs))
150 return NOTIFY_STOP;
151 break;
152 default:
153 break;
154 }
155 return NOTIFY_DONE;
156}
157
158
159
160
161
162
163void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
164{
165 struct uprobe_task *utask = current->utask;
166
167 current->thread.trap_nr = utask->autask.saved_trap_nr;
168 instruction_pointer_set(regs, utask->vaddr);
169
170 user_disable_single_step(current);
171}
172
173
174
175
176
177bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
178{
179 int ret;
180
181
182
183
184
185 ret = emulate_step(regs, ppc_inst_read(auprobe->insn));
186 if (ret > 0)
187 return true;
188
189 return false;
190}
191
192unsigned long
193arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs)
194{
195 unsigned long orig_ret_vaddr;
196
197 orig_ret_vaddr = regs->link;
198
199
200 regs->link = trampoline_vaddr;
201
202 return orig_ret_vaddr;
203}
204
205bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
206 struct pt_regs *regs)
207{
208 if (ctx == RP_CHECK_CHAIN_CALL)
209 return regs->gpr[1] <= ret->stack;
210 else
211 return regs->gpr[1] < ret->stack;
212}
213