This source file includes following definitions.
- is_trap_insn
- arch_uprobe_analyze_insn
- arch_uprobe_pre_xol
- uprobe_get_swbp_addr
- arch_uprobe_xol_was_trapped
- arch_uprobe_post_xol
- arch_uprobe_exception_notify
- arch_uprobe_abort_xol
- arch_uprobe_skip_sstep
- arch_uretprobe_hijack_return_addr
- arch_uretprobe_is_alive
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
18 #define UPROBE_TRAP_NR UINT_MAX
19
20
21
22
23
24
25 bool is_trap_insn(uprobe_opcode_t *insn)
26 {
27 return (is_trap(*insn));
28 }
29
30
31
32
33
34
35
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
48
49
50
51 int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
52 {
53 struct arch_uprobe_task *autask = ¤t->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
65
66
67
68
69 unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
70 {
71 return instruction_pointer(regs);
72 }
73
74
75
76
77
78
79
80
81
82
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
94
95
96
97
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
109
110
111
112
113
114 regs->nip = utask->vaddr + MAX_UINSN_BYTES;
115
116 user_disable_single_step(current);
117 return 0;
118 }
119
120
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
128 if (WARN_ON(!regs))
129 return NOTIFY_DONE;
130
131
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
151
152
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
166
167
168 bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
169 {
170 int ret;
171
172
173
174
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
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 }