OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [x86_64/] [ia32/] [ptrace32.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * 32bit ptrace for x86-64.
3
 *
4
 * Copyright 2001,2002 Andi Kleen, SuSE Labs.
5
 * Some parts copied from arch/i386/kernel/ptrace.c. See that file for earlier
6
 * copyright.
7
 *
8
 * This allows to access 64bit processes too; but there is no way to see the extended
9
 * register contents.
10
 *
11
 * $Id: ptrace32.c,v 1.1.1.1 2004-04-15 01:36:39 phoenix Exp $
12
 */
13
 
14
#include <linux/kernel.h>
15
#include <linux/stddef.h>
16
#include <linux/sched.h>
17
#include <linux/mm.h>
18
#include <asm/ptrace.h>
19
#include <asm/uaccess.h>
20
#include <asm/user32.h>
21
#include <asm/user.h>
22
#include <asm/errno.h>
23
#include <asm/debugreg.h>
24
#include <asm/i387.h>
25
#include <asm/fpu32.h>
26
#include <linux/mm.h>
27
 
28
/* determines which flags the user has access to. */
29
/* 1 = access 0 = no access */
30
#define FLAG_MASK 0x44dd5UL
31
 
32
#define R32(l,q) \
33
        case offsetof(struct user32, regs.l): stack[offsetof(struct pt_regs, q)/8] = val; break
34
 
35
static int putreg32(struct task_struct *child, unsigned regno, u32 val)
36
{
37
        int i;
38
        __u64 *stack = (__u64 *)(child->thread.rsp0 - sizeof(struct pt_regs));
39
 
40
        switch (regno) {
41
        case offsetof(struct user32, regs.fs):
42
        if (val && (val & 3) != 3) return -EIO;
43
        child->thread.fs = val & 0xffff;
44
                break;
45
        case offsetof(struct user32, regs.gs):
46
            if (val && (val & 3) != 3) return -EIO;
47
                child->thread.gs = val & 0xffff;
48
                break;
49
        case offsetof(struct user32, regs.ds):
50
                if (val && (val & 3) != 3) return -EIO;
51
                child->thread.ds = val & 0xffff;
52
                break;
53
        case offsetof(struct user32, regs.es):
54
                child->thread.es = val & 0xffff;
55
                break;
56
    case offsetof(struct user32, regs.ss):
57
                if ((val & 3) != 3) return -EIO;
58
        stack[offsetof(struct pt_regs, ss)/8] = val & 0xffff;
59
        break;
60
        case offsetof(struct user32, regs.cs):
61
                if ((val & 3) != 3) return -EIO;
62
                stack[offsetof(struct pt_regs, cs)/8] = val & 0xffff;
63
                break;
64
 
65
        R32(ebx, rbx);
66
        R32(ecx, rcx);
67
        R32(edx, rdx);
68
        R32(edi, rdi);
69
        R32(esi, rsi);
70
        R32(ebp, rbp);
71
        R32(eax, rax);
72
        R32(orig_eax, orig_rax);
73
        R32(eip, rip);
74
        R32(esp, rsp);
75
 
76
        case offsetof(struct user32, regs.eflags): {
77
                __u64 *flags = &stack[offsetof(struct pt_regs, eflags)/8];
78
                val &= FLAG_MASK;
79
                *flags = val | (*flags & ~FLAG_MASK);
80
                break;
81
        }
82
 
83
        case offsetof(struct user32, u_debugreg[4]):
84
        case offsetof(struct user32, u_debugreg[5]):
85
                return -EIO;
86
 
87
        case offsetof(struct user32, u_debugreg[0]) ...
88
             offsetof(struct user32, u_debugreg[3]):
89
        case offsetof(struct user32, u_debugreg[6]):
90
                child->thread.debugreg
91
                        [(regno-offsetof(struct user32, u_debugreg[0]))/4]
92
                        = val;
93
                break;
94
 
95
        case offsetof(struct user32, u_debugreg[7]):
96
                val &= ~DR_CONTROL_RESERVED;
97
                /* You are not expected to understand this ... I don't neither. */
98
                for(i=0; i<4; i++)
99
                        if ((0x5454 >> ((val >> (16 + 4*i)) & 0xf)) & 1)
100
                               return -EIO;
101
                child->thread.debugreg[7] = val;
102
                break;
103
 
104
        default:
105
                if (regno > sizeof(struct user32) || (regno & 3))
106
                        return -EIO;
107
 
108
                /* Other dummy fields in the virtual user structure are ignored */
109
                break;
110
        }
111
        return 0;
112
}
113
 
114
#undef R32
115
 
116
#define R32(l,q) \
117
        case offsetof(struct user32, regs.l): *val = stack[offsetof(struct pt_regs, q)/8]; break
118
 
119
static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
120
{
121
        __u64 *stack = (__u64 *)(child->thread.rsp0 - sizeof(struct pt_regs));
122
 
123
        switch (regno) {
124
        case offsetof(struct user32, regs.fs):
125
                *val = child->thread.fs;
126
                break;
127
        case offsetof(struct user32, regs.gs):
128
                *val = child->thread.gs;
129
                break;
130
        case offsetof(struct user32, regs.ds):
131
                *val = child->thread.ds;
132
                break;
133
        case offsetof(struct user32, regs.es):
134
                *val = child->thread.es;
135
                break;
136
 
137
        R32(cs, cs);
138
        R32(ss, ss);
139
        R32(ebx, rbx);
140
        R32(ecx, rcx);
141
        R32(edx, rdx);
142
        R32(edi, rdi);
143
        R32(esi, rsi);
144
        R32(ebp, rbp);
145
        R32(eax, rax);
146
        R32(orig_eax, orig_rax);
147
        R32(eip, rip);
148
        R32(eflags, eflags);
149
        R32(esp, rsp);
150
 
151
        case offsetof(struct user32, u_debugreg[0]) ... offsetof(struct user32, u_debugreg[7]):
152
                *val = child->thread.debugreg[(regno-offsetof(struct user32, u_debugreg[0]))/4];
153
                break;
154
 
155
        default:
156
                if (regno > sizeof(struct user32) || (regno & 3))
157
                        return -EIO;
158
 
159
                /* Other dummy fields in the virtual user structure are ignored */
160
                *val = 0;
161
                break;
162
        }
163
        return 0;
164
}
165
 
166
#undef R32
167
 
168
static struct task_struct *find_target(int request, int pid, int *err)
169
{
170
        struct task_struct *child;
171
 
172
        *err = -EPERM;
173
        if (pid == 1)
174
                return NULL;
175
 
176
        *err = -ESRCH;
177
        read_lock(&tasklist_lock);
178
        child = find_task_by_pid(pid);
179
        if (child)
180
                get_task_struct(child);
181
        read_unlock(&tasklist_lock);
182
        if (child) {
183
                *err = -EPERM;
184
                if (pid == 1)
185
                        goto out;
186
                *err = ptrace_check_attach(child, request == PTRACE_KILL);
187
                if (*err < 0)
188
                                goto out;
189
                return child;
190
        }
191
 
192
 out:
193
        free_task_struct(child);
194
        return NULL;
195
 
196
}
197
 
198
extern asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, unsigned long data);
199
 
200
asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
201
{
202
        struct task_struct *child;
203
        struct pt_regs *childregs;
204
        int ret;
205
        __u32 val;
206
 
207
        switch (request) {
208
        case PTRACE_TRACEME:
209
        case PTRACE_ATTACH:
210
        case PTRACE_SYSCALL:
211
        case PTRACE_CONT:
212
        case PTRACE_KILL:
213
        case PTRACE_SINGLESTEP:
214
        case PTRACE_DETACH:
215
        case PTRACE_SETOPTIONS:
216
                ret = sys_ptrace(request, pid, addr, data);
217
                return ret;
218
 
219
        case PTRACE_PEEKTEXT:
220
        case PTRACE_PEEKDATA:
221
        case PTRACE_POKEDATA:
222
        case PTRACE_POKETEXT:
223
        case PTRACE_POKEUSR:
224
        case PTRACE_PEEKUSR:
225
        case PTRACE_GETREGS:
226
        case PTRACE_SETREGS:
227
        case PTRACE_SETFPREGS:
228
        case PTRACE_GETFPREGS:
229
        case PTRACE_SETFPXREGS:
230
        case PTRACE_GETFPXREGS:
231
                break;
232
 
233
        default:
234
                return -EIO;
235
        }
236
 
237
        child = find_target(request, pid, &ret);
238
        if (!child)
239
                return ret;
240
 
241
        childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs));
242
 
243
        switch (request) {
244
        case PTRACE_PEEKDATA:
245
        case PTRACE_PEEKTEXT:
246
                ret = 0;
247
                if (access_process_vm(child, addr, &val, sizeof(u32), 0)!=sizeof(u32))
248
                        ret = -EIO;
249
                else
250
                        ret = put_user(val, (unsigned int *)(u64)data);
251
                break;
252
 
253
        case PTRACE_POKEDATA:
254
        case PTRACE_POKETEXT:
255
                ret = 0;
256
                if (access_process_vm(child, addr, &data, sizeof(u32), 1)!=sizeof(u32))
257
                        ret = -EIO;
258
                break;
259
 
260
        case PTRACE_PEEKUSR:
261
                ret = getreg32(child, addr, &val);
262
                if (ret == 0)
263
                        ret = put_user(val, (__u32 *)(unsigned long) data);
264
                break;
265
 
266
        case PTRACE_POKEUSR:
267
                ret = putreg32(child, addr, data);
268
                break;
269
 
270
        case PTRACE_GETREGS: { /* Get all gp regs from the child. */
271
                int i;
272
                if (!access_ok(VERIFY_WRITE, (unsigned *)(unsigned long)data, 16*4)) {
273
                        ret = -EIO;
274
                        break;
275
                }
276
                ret = 0;
277
                for ( i = 0; i <= 16*4 ; i += sizeof(__u32) ) {
278
                        getreg32(child, i, &val);
279
                        ret |= __put_user(val,(u32 *) (unsigned long) data);
280
                        data += sizeof(u32);
281
                }
282
                break;
283
        }
284
 
285
        case PTRACE_SETREGS: { /* Set all gp regs in the child. */
286
                unsigned long tmp;
287
                int i;
288
                if (!access_ok(VERIFY_READ, (unsigned *)(unsigned long)data, 16*4)) {
289
                        ret = -EIO;
290
                        break;
291
                }
292
                ret = 0;
293
                for ( i = 0; i <= 16*4; i += sizeof(u32) ) {
294
                        ret |= __get_user(tmp, (u32 *) (unsigned long) data);
295
                        putreg32(child, i, tmp);
296
                        data += sizeof(u32);
297
                }
298
                break;
299
        }
300
 
301
        case PTRACE_GETFPREGS:
302
                ret = -EIO;
303
                if (!access_ok(VERIFY_READ, (void *)(u64)data,
304
                               sizeof(struct user_i387_struct)))
305
                        break;
306
                save_i387_ia32(child, (void *)(u64)data, childregs, 1);
307
                ret = 0;
308
                break;
309
 
310
        case PTRACE_SETFPREGS:
311
                ret = -EIO;
312
                if (!access_ok(VERIFY_WRITE, (void *)(u64)data,
313
                               sizeof(struct user_i387_struct)))
314
                        break;
315
                ret = 0;
316
                /* don't check EFAULT to be bug-to-bug compatible to i386 */
317
                restore_i387_ia32(child, (void *)(u64)data, 1);
318
                break;
319
 
320
        case PTRACE_GETFPXREGS: {
321
                struct user32_fxsr_struct *u = (void *)(u64)data;
322
                init_fpu(child);
323
                ret = -EIO;
324
                if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
325
                        break;
326
                        ret = -EFAULT;
327
                if (__copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u)))
328
                        break;
329
                ret = __put_user(childregs->cs, &u->fcs);
330
                ret |= __put_user(child->thread.ds, &u->fos);
331
                break;
332
        }
333
        case PTRACE_SETFPXREGS: {
334
                struct user32_fxsr_struct *u = (void *)(u64)data;
335
                unlazy_fpu(child);
336
                ret = -EIO;
337
                if (!access_ok(VERIFY_READ, u, sizeof(*u)))
338
                        break;
339
                /* no checking to be bug-to-bug compatible with i386 */
340
                __copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u));
341
                child->used_math = 1;
342
                child->thread.i387.fxsave.mxcsr &= 0xffbf;
343
                ret = 0;
344
                break;
345
        }
346
 
347
        default:
348
                ret = -EINVAL;
349
                break;
350
        }
351
 
352
        free_task_struct(child);
353
        return ret;
354
}
355
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.