Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/um/ptrace_32.c
26439 views
1
/*
2
* Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3
* Licensed under the GPL
4
*/
5
6
#include <linux/mm.h>
7
#include <linux/sched.h>
8
#include <linux/uaccess.h>
9
#include <linux/regset.h>
10
#include <asm/ptrace-abi.h>
11
#include <registers.h>
12
#include <skas.h>
13
14
void arch_switch_to(struct task_struct *to)
15
{
16
int err = arch_switch_tls(to);
17
if (!err)
18
return;
19
20
if (err != -EINVAL)
21
printk(KERN_WARNING "arch_switch_tls failed, errno %d, "
22
"not EINVAL\n", -err);
23
else
24
printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n");
25
}
26
27
/* determines which flags the user has access to. */
28
/* 1 = access 0 = no access */
29
#define FLAG_MASK 0x00044dd5
30
31
static const int reg_offsets[] = {
32
[EBX] = HOST_BX,
33
[ECX] = HOST_CX,
34
[EDX] = HOST_DX,
35
[ESI] = HOST_SI,
36
[EDI] = HOST_DI,
37
[EBP] = HOST_BP,
38
[EAX] = HOST_AX,
39
[DS] = HOST_DS,
40
[ES] = HOST_ES,
41
[FS] = HOST_FS,
42
[GS] = HOST_GS,
43
[EIP] = HOST_IP,
44
[CS] = HOST_CS,
45
[EFL] = HOST_EFLAGS,
46
[UESP] = HOST_SP,
47
[SS] = HOST_SS,
48
[ORIG_EAX] = HOST_ORIG_AX,
49
};
50
51
int putreg(struct task_struct *child, int regno, unsigned long value)
52
{
53
regno >>= 2;
54
switch (regno) {
55
case EBX:
56
case ECX:
57
case EDX:
58
case ESI:
59
case EDI:
60
case EBP:
61
case EAX:
62
case EIP:
63
case UESP:
64
break;
65
case ORIG_EAX:
66
/* Update the syscall number. */
67
UPT_SYSCALL_NR(&child->thread.regs.regs) = value;
68
break;
69
case FS:
70
if (value && (value & 3) != 3)
71
return -EIO;
72
break;
73
case GS:
74
if (value && (value & 3) != 3)
75
return -EIO;
76
break;
77
case DS:
78
case ES:
79
if (value && (value & 3) != 3)
80
return -EIO;
81
value &= 0xffff;
82
break;
83
case SS:
84
case CS:
85
if ((value & 3) != 3)
86
return -EIO;
87
value &= 0xffff;
88
break;
89
case EFL:
90
value &= FLAG_MASK;
91
child->thread.regs.regs.gp[HOST_EFLAGS] |= value;
92
return 0;
93
default :
94
panic("Bad register in putreg() : %d\n", regno);
95
}
96
child->thread.regs.regs.gp[reg_offsets[regno]] = value;
97
return 0;
98
}
99
100
int poke_user(struct task_struct *child, long addr, long data)
101
{
102
if ((addr & 3) || addr < 0)
103
return -EIO;
104
105
if (addr < MAX_REG_OFFSET)
106
return putreg(child, addr, data);
107
else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
108
(addr <= offsetof(struct user, u_debugreg[7]))) {
109
addr -= offsetof(struct user, u_debugreg[0]);
110
addr = addr >> 2;
111
if ((addr == 4) || (addr == 5))
112
return -EIO;
113
child->thread.arch.debugregs[addr] = data;
114
return 0;
115
}
116
return -EIO;
117
}
118
119
unsigned long getreg(struct task_struct *child, int regno)
120
{
121
unsigned long mask = ~0UL;
122
123
regno >>= 2;
124
switch (regno) {
125
case FS:
126
case GS:
127
case DS:
128
case ES:
129
case SS:
130
case CS:
131
mask = 0xffff;
132
break;
133
case EIP:
134
case UESP:
135
case EAX:
136
case EBX:
137
case ECX:
138
case EDX:
139
case ESI:
140
case EDI:
141
case EBP:
142
case EFL:
143
case ORIG_EAX:
144
break;
145
default:
146
panic("Bad register in getreg() : %d\n", regno);
147
}
148
return mask & child->thread.regs.regs.gp[reg_offsets[regno]];
149
}
150
151
/* read the word at location addr in the USER area. */
152
int peek_user(struct task_struct *child, long addr, long data)
153
{
154
unsigned long tmp;
155
156
if ((addr & 3) || addr < 0)
157
return -EIO;
158
159
tmp = 0; /* Default return condition */
160
if (addr < MAX_REG_OFFSET) {
161
tmp = getreg(child, addr);
162
}
163
else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
164
(addr <= offsetof(struct user, u_debugreg[7]))) {
165
addr -= offsetof(struct user, u_debugreg[0]);
166
addr = addr >> 2;
167
tmp = child->thread.arch.debugregs[addr];
168
}
169
return put_user(tmp, (unsigned long __user *) data);
170
}
171
172
long subarch_ptrace(struct task_struct *child, long request,
173
unsigned long addr, unsigned long data)
174
{
175
int ret = -EIO;
176
void __user *datap = (void __user *) data;
177
switch (request) {
178
case PTRACE_GETFPREGS: /* Get the child FPU state. */
179
return copy_regset_to_user(child, task_user_regset_view(child),
180
REGSET_FP_LEGACY,
181
0, sizeof(struct user_i387_struct),
182
datap);
183
case PTRACE_SETFPREGS: /* Set the child FPU state. */
184
return copy_regset_from_user(child, task_user_regset_view(child),
185
REGSET_FP_LEGACY,
186
0, sizeof(struct user_i387_struct),
187
datap);
188
case PTRACE_GETFPXREGS: /* Get the child FPU state. */
189
return copy_regset_to_user(child, task_user_regset_view(child),
190
REGSET_FP,
191
0, sizeof(struct user_fxsr_struct),
192
datap);
193
case PTRACE_SETFPXREGS: /* Set the child FPU state. */
194
return copy_regset_from_user(child, task_user_regset_view(child),
195
REGSET_FP,
196
0, sizeof(struct user_fxsr_struct),
197
datap);
198
default:
199
ret = -EIO;
200
}
201
return ret;
202
}
203
204