Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/tile/kernel/ptrace.c
10817 views
1
/*
2
* Copyright 2010 Tilera Corporation. All Rights Reserved.
3
*
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License
6
* as published by the Free Software Foundation, version 2.
7
*
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11
* NON INFRINGEMENT. See the GNU General Public License for
12
* more details.
13
*
14
* Copied from i386: Ross Biro 1/23/92
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
24
void user_enable_single_step(struct task_struct *child)
25
{
26
set_tsk_thread_flag(child, TIF_SINGLESTEP);
27
}
28
29
void user_disable_single_step(struct task_struct *child)
30
{
31
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
32
}
33
34
/*
35
* Called by kernel/ptrace.c when detaching..
36
*/
37
void ptrace_disable(struct task_struct *child)
38
{
39
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
40
41
/*
42
* These two are currently unused, but will be set by arch_ptrace()
43
* and used in the syscall assembly when we do support them.
44
*/
45
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
46
}
47
48
long 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: /* Read register from pt_regs. */
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: /* Write register in pt_regs. */
80
if (addr >= PTREGS_SIZE)
81
break;
82
childreg = (char *)task_pt_regs(child) + addr;
83
84
/* Guard against overwrites of the privilege level. */
85
ex1_offset = PTREGS_OFFSET_EX1;
86
#if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN)
87
if (is_compat_task()) /* point at low word */
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: /* Get all registers from the child. */
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: /* Set all registers in the child. */
116
if (copy_from_user(&copyregs, 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: /* Get the child FPU state. */
126
case PTRACE_SETFPREGS: /* Set the child FPU state. */
127
break;
128
129
case PTRACE_SETOPTIONS:
130
/* Support TILE-specific ptrace options. */
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
/* Not used; we handle compat issues in arch_ptrace() directly. */
156
long 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
163
void 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
* The 0x80 provides a way for the tracing parent to distinguish
173
* between a syscall stop and SIGTRAP delivery
174
*/
175
ptrace_notify(SIGTRAP|((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
176
177
/*
178
* this isn't the same as continuing with a signal, but it will do
179
* for normal use. strace only continues with a signal if the
180
* stopping signal is not SIGTRAP. -brl
181
*/
182
if (current->exit_code) {
183
send_sig(current->exit_code, current, 1);
184
current->exit_code = 0;
185
}
186
}
187
188
void 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
/* Send us the fakey SIGTRAP */
198
force_sig_info(SIGTRAP, &info, tsk);
199
}
200
201
/* Handle synthetic interrupt delivered only by the simulator. */
202
void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num)
203
{
204
send_sigtrap(current, regs, fault_num);
205
}
206
207