1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/kernel.h>
18#include <linux/ptrace.h>
19#include <linux/kprobes.h>
20#include <linux/compat.h>
21#include <linux/uaccess.h>
22#include <asm/traps.h>
23
24void user_enable_single_step(struct task_struct *child)
25{
26 set_tsk_thread_flag(child, TIF_SINGLESTEP);
27}
28
29void user_disable_single_step(struct task_struct *child)
30{
31 clear_tsk_thread_flag(child, TIF_SINGLESTEP);
32}
33
34
35
36
37void ptrace_disable(struct task_struct *child)
38{
39 clear_tsk_thread_flag(child, TIF_SINGLESTEP);
40
41
42
43
44
45 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
46}
47
48long arch_ptrace(struct task_struct *child, long request,
49 unsigned long addr, unsigned long data)
50{
51 unsigned long __user *datap = (long __user __force *)data;
52 unsigned long tmp;
53 long ret = -EIO;
54 char *childreg;
55 struct pt_regs copyregs;
56 int ex1_offset;
57
58 switch (request) {
59
60 case PTRACE_PEEKUSR:
61 if (addr >= PTREGS_SIZE)
62 break;
63 childreg = (char *)task_pt_regs(child) + addr;
64#ifdef CONFIG_COMPAT
65 if (is_compat_task()) {
66 if (addr & (sizeof(compat_long_t)-1))
67 break;
68 ret = put_user(*(compat_long_t *)childreg,
69 (compat_long_t __user *)datap);
70 } else
71#endif
72 {
73 if (addr & (sizeof(long)-1))
74 break;
75 ret = put_user(*(long *)childreg, datap);
76 }
77 break;
78
79 case PTRACE_POKEUSR:
80 if (addr >= PTREGS_SIZE)
81 break;
82 childreg = (char *)task_pt_regs(child) + addr;
83
84
85 ex1_offset = PTREGS_OFFSET_EX1;
86#if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN)
87 if (is_compat_task())
88 ex1_offset += sizeof(compat_long_t);
89#endif
90 if (addr == ex1_offset)
91 data = PL_ICS_EX1(USER_PL, EX1_ICS(data));
92
93#ifdef CONFIG_COMPAT
94 if (is_compat_task()) {
95 if (addr & (sizeof(compat_long_t)-1))
96 break;
97 *(compat_long_t *)childreg = data;
98 } else
99#endif
100 {
101 if (addr & (sizeof(long)-1))
102 break;
103 *(long *)childreg = data;
104 }
105 ret = 0;
106 break;
107
108 case PTRACE_GETREGS:
109 if (copy_to_user(datap, task_pt_regs(child),
110 sizeof(struct pt_regs)) == 0) {
111 ret = 0;
112 }
113 break;
114
115 case PTRACE_SETREGS:
116 if (copy_from_user(©regs, datap,
117 sizeof(struct pt_regs)) == 0) {
118 copyregs.ex1 =
119 PL_ICS_EX1(USER_PL, EX1_ICS(copyregs.ex1));
120 *task_pt_regs(child) = copyregs;
121 ret = 0;
122 }
123 break;
124
125 case PTRACE_GETFPREGS:
126 case PTRACE_SETFPREGS:
127 break;
128
129 case PTRACE_SETOPTIONS:
130
131 child->ptrace &= ~PT_TRACE_MASK_TILE;
132 tmp = data & PTRACE_O_MASK_TILE;
133 data &= ~PTRACE_O_MASK_TILE;
134 ret = ptrace_request(child, request, addr, data);
135 if (tmp & PTRACE_O_TRACEMIGRATE)
136 child->ptrace |= PT_TRACE_MIGRATE;
137 break;
138
139 default:
140#ifdef CONFIG_COMPAT
141 if (task_thread_info(current)->status & TS_COMPAT) {
142 ret = compat_ptrace_request(child, request,
143 addr, data);
144 break;
145 }
146#endif
147 ret = ptrace_request(child, request, addr, data);
148 break;
149 }
150
151 return ret;
152}
153
154#ifdef CONFIG_COMPAT
155
156long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
157 compat_ulong_t addr, compat_ulong_t data)
158{
159 BUG();
160}
161#endif
162
163void do_syscall_trace(void)
164{
165 if (!test_thread_flag(TIF_SYSCALL_TRACE))
166 return;
167
168 if (!(current->ptrace & PT_PTRACED))
169 return;
170
171
172
173
174
175 ptrace_notify(SIGTRAP|((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
176
177
178
179
180
181
182 if (current->exit_code) {
183 send_sig(current->exit_code, current, 1);
184 current->exit_code = 0;
185 }
186}
187
188void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
189{
190 struct siginfo info;
191
192 memset(&info, 0, sizeof(info));
193 info.si_signo = SIGTRAP;
194 info.si_code = TRAP_BRKPT;
195 info.si_addr = (void __user *) regs->pc;
196
197
198 force_sig_info(SIGTRAP, &info, tsk);
199}
200
201
202void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num)
203{
204 send_sigtrap(current, regs, fault_num);
205}
206