~ubuntu-branches/ubuntu/saucy/linux-n900/saucy

« back to all changes in this revision

Viewing changes to arch/um/sys-x86_64/ptrace.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathieu Poirier
  • Date: 2011-02-18 09:43:31 UTC
  • Revision ID: james.westby@ubuntu.com-20110218094331-eyubsja4f9k0yhmq
Tags: 2.6.35-1.1
Initial release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2003 PathScale, Inc.
 
3
 * Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
 
4
 *
 
5
 * Licensed under the GPL
 
6
 */
 
7
 
 
8
#include <linux/mm.h>
 
9
#include <linux/sched.h>
 
10
#include <linux/errno.h>
 
11
#define __FRAME_OFFSETS
 
12
#include <asm/ptrace.h>
 
13
#include <asm/uaccess.h>
 
14
 
 
15
/*
 
16
 * determines which flags the user has access to.
 
17
 * 1 = access 0 = no access
 
18
 */
 
19
#define FLAG_MASK 0x44dd5UL
 
20
 
 
21
int putreg(struct task_struct *child, int regno, unsigned long value)
 
22
{
 
23
        unsigned long tmp;
 
24
 
 
25
#ifdef TIF_IA32
 
26
        /*
 
27
         * Some code in the 64bit emulation may not be 64bit clean.
 
28
         * Don't take any chances.
 
29
         */
 
30
        if (test_tsk_thread_flag(child, TIF_IA32))
 
31
                value &= 0xffffffff;
 
32
#endif
 
33
        switch (regno) {
 
34
        case FS:
 
35
        case GS:
 
36
        case DS:
 
37
        case ES:
 
38
        case SS:
 
39
        case CS:
 
40
                if (value && (value & 3) != 3)
 
41
                        return -EIO;
 
42
                value &= 0xffff;
 
43
                break;
 
44
 
 
45
        case FS_BASE:
 
46
        case GS_BASE:
 
47
                if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
 
48
                        return -EIO;
 
49
                break;
 
50
 
 
51
        case EFLAGS:
 
52
                value &= FLAG_MASK;
 
53
                tmp = PT_REGS_EFLAGS(&child->thread.regs) & ~FLAG_MASK;
 
54
                value |= tmp;
 
55
                break;
 
56
        }
 
57
 
 
58
        PT_REGS_SET(&child->thread.regs, regno, value);
 
59
        return 0;
 
60
}
 
61
 
 
62
int poke_user(struct task_struct *child, long addr, long data)
 
63
{
 
64
        if ((addr & 3) || addr < 0)
 
65
                return -EIO;
 
66
 
 
67
        if (addr < MAX_REG_OFFSET)
 
68
                return putreg(child, addr, data);
 
69
        else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
 
70
                (addr <= offsetof(struct user, u_debugreg[7]))) {
 
71
                addr -= offsetof(struct user, u_debugreg[0]);
 
72
                addr = addr >> 2;
 
73
                if ((addr == 4) || (addr == 5))
 
74
                        return -EIO;
 
75
                child->thread.arch.debugregs[addr] = data;
 
76
                return 0;
 
77
        }
 
78
        return -EIO;
 
79
}
 
80
 
 
81
unsigned long getreg(struct task_struct *child, int regno)
 
82
{
 
83
        unsigned long retval = ~0UL;
 
84
        switch (regno) {
 
85
        case FS:
 
86
        case GS:
 
87
        case DS:
 
88
        case ES:
 
89
        case SS:
 
90
        case CS:
 
91
                retval = 0xffff;
 
92
                /* fall through */
 
93
        default:
 
94
                retval &= PT_REG(&child->thread.regs, regno);
 
95
#ifdef TIF_IA32
 
96
                if (test_tsk_thread_flag(child, TIF_IA32))
 
97
                        retval &= 0xffffffff;
 
98
#endif
 
99
        }
 
100
        return retval;
 
101
}
 
102
 
 
103
int peek_user(struct task_struct *child, long addr, long data)
 
104
{
 
105
        /* read the word at location addr in the USER area. */
 
106
        unsigned long tmp;
 
107
 
 
108
        if ((addr & 3) || addr < 0)
 
109
                return -EIO;
 
110
 
 
111
        tmp = 0;  /* Default return condition */
 
112
        if (addr < MAX_REG_OFFSET)
 
113
                tmp = getreg(child, addr);
 
114
        else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
 
115
                (addr <= offsetof(struct user, u_debugreg[7]))) {
 
116
                addr -= offsetof(struct user, u_debugreg[0]);
 
117
                addr = addr >> 2;
 
118
                tmp = child->thread.arch.debugregs[addr];
 
119
        }
 
120
        return put_user(tmp, (unsigned long *) data);
 
121
}
 
122
 
 
123
/* XXX Mostly copied from sys-i386 */
 
124
int is_syscall(unsigned long addr)
 
125
{
 
126
        unsigned short instr;
 
127
        int n;
 
128
 
 
129
        n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
 
130
        if (n) {
 
131
                /*
 
132
                 * access_process_vm() grants access to vsyscall and stub,
 
133
                 * while copy_from_user doesn't. Maybe access_process_vm is
 
134
                 * slow, but that doesn't matter, since it will be called only
 
135
                 * in case of singlestepping, if copy_from_user failed.
 
136
                 */
 
137
                n = access_process_vm(current, addr, &instr, sizeof(instr), 0);
 
138
                if (n != sizeof(instr)) {
 
139
                        printk("is_syscall : failed to read instruction from "
 
140
                               "0x%lx\n", addr);
 
141
                        return 1;
 
142
                }
 
143
        }
 
144
        /* sysenter */
 
145
        return instr == 0x050f;
 
146
}
 
147
 
 
148
int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
 
149
{
 
150
        int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
 
151
        long fpregs[HOST_FP_SIZE];
 
152
 
 
153
        BUG_ON(sizeof(*buf) != sizeof(fpregs));
 
154
        err = save_fp_registers(userspace_pid[cpu], fpregs);
 
155
        if (err)
 
156
                return err;
 
157
 
 
158
        n = copy_to_user(buf, fpregs, sizeof(fpregs));
 
159
        if (n > 0)
 
160
                return -EFAULT;
 
161
 
 
162
        return n;
 
163
}
 
164
 
 
165
int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
 
166
{
 
167
        int n, cpu = ((struct thread_info *) child->stack)->cpu;
 
168
        long fpregs[HOST_FP_SIZE];
 
169
 
 
170
        BUG_ON(sizeof(*buf) != sizeof(fpregs));
 
171
        n = copy_from_user(fpregs, buf, sizeof(fpregs));
 
172
        if (n > 0)
 
173
                return -EFAULT;
 
174
 
 
175
        return restore_fp_registers(userspace_pid[cpu], fpregs);
 
176
}
 
177
 
 
178
long subarch_ptrace(struct task_struct *child, long request, long addr,
 
179
                    long data)
 
180
{
 
181
        int ret = -EIO;
 
182
 
 
183
        switch (request) {
 
184
        case PTRACE_GETFPXREGS: /* Get the child FPU state. */
 
185
                ret = get_fpregs((struct user_i387_struct __user *) data,
 
186
                                 child);
 
187
                break;
 
188
        case PTRACE_SETFPXREGS: /* Set the child FPU state. */
 
189
                ret = set_fpregs((struct user_i387_struct __user *) data,
 
190
                                 child);
 
191
                break;
 
192
        }
 
193
 
 
194
        return ret;
 
195
}