~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to arch/m68knommu/kernel/ptrace.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *  linux/arch/m68knommu/kernel/ptrace.c
3
 
 *
4
 
 *  Copyright (C) 1994 by Hamish Macdonald
5
 
 *  Taken from linux/kernel/ptrace.c and modified for M680x0.
6
 
 *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
7
 
 *
8
 
 * This file is subject to the terms and conditions of the GNU General
9
 
 * Public License.  See the file COPYING in the main directory of
10
 
 * this archive for more details.
11
 
 */
12
 
 
13
 
#include <linux/kernel.h>
14
 
#include <linux/sched.h>
15
 
#include <linux/mm.h>
16
 
#include <linux/smp.h>
17
 
#include <linux/errno.h>
18
 
#include <linux/ptrace.h>
19
 
#include <linux/user.h>
20
 
#include <linux/signal.h>
21
 
#include <linux/tracehook.h>
22
 
 
23
 
#include <asm/uaccess.h>
24
 
#include <asm/page.h>
25
 
#include <asm/pgtable.h>
26
 
#include <asm/system.h>
27
 
#include <asm/processor.h>
28
 
 
29
 
/*
30
 
 * does not yet catch signals sent when the child dies.
31
 
 * in exit.c or in signal.c.
32
 
 */
33
 
 
34
 
/* determines which bits in the SR the user has access to. */
35
 
/* 1 = access 0 = no access */
36
 
#define SR_MASK 0x001f
37
 
 
38
 
/* sets the trace bits. */
39
 
#define TRACE_BITS 0x8000
40
 
 
41
 
/* Find the stack offset for a register, relative to thread.esp0. */
42
 
#define PT_REG(reg)     ((long)&((struct pt_regs *)0)->reg)
43
 
#define SW_REG(reg)     ((long)&((struct switch_stack *)0)->reg \
44
 
                         - sizeof(struct switch_stack))
45
 
/* Mapping from PT_xxx to the stack offset at which the register is
46
 
   saved.  Notice that usp has no stack-slot and needs to be treated
47
 
   specially (see get_reg/put_reg below). */
48
 
static int regoff[] = {
49
 
        PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4),
50
 
        PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
51
 
        PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4),
52
 
        SW_REG(a5), SW_REG(a6), PT_REG(d0), -1,
53
 
        PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
54
 
};
55
 
 
56
 
/*
57
 
 * Get contents of register REGNO in task TASK.
58
 
 */
59
 
static inline long get_reg(struct task_struct *task, int regno)
60
 
{
61
 
        unsigned long *addr;
62
 
 
63
 
        if (regno == PT_USP)
64
 
                addr = &task->thread.usp;
65
 
        else if (regno < ARRAY_SIZE(regoff))
66
 
                addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
67
 
        else
68
 
                return 0;
69
 
        return *addr;
70
 
}
71
 
 
72
 
/*
73
 
 * Write contents of register REGNO in task TASK.
74
 
 */
75
 
static inline int put_reg(struct task_struct *task, int regno,
76
 
                          unsigned long data)
77
 
{
78
 
        unsigned long *addr;
79
 
 
80
 
        if (regno == PT_USP)
81
 
                addr = &task->thread.usp;
82
 
        else if (regno < ARRAY_SIZE(regoff))
83
 
                addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
84
 
        else
85
 
                return -1;
86
 
        *addr = data;
87
 
        return 0;
88
 
}
89
 
 
90
 
void user_enable_single_step(struct task_struct *task)
91
 
{
92
 
        unsigned long srflags;
93
 
        srflags = get_reg(task, PT_SR) | (TRACE_BITS << 16);
94
 
        put_reg(task, PT_SR, srflags);
95
 
}
96
 
 
97
 
void user_disable_single_step(struct task_struct *task)
98
 
{
99
 
        unsigned long srflags;
100
 
        srflags = get_reg(task, PT_SR) & ~(TRACE_BITS << 16);
101
 
        put_reg(task, PT_SR, srflags);
102
 
}
103
 
 
104
 
/*
105
 
 * Called by kernel/ptrace.c when detaching..
106
 
 *
107
 
 * Make sure the single step bit is not set.
108
 
 */
109
 
void ptrace_disable(struct task_struct *child)
110
 
{
111
 
        /* make sure the single step bit is not set. */
112
 
        user_disable_single_step(child);
113
 
}
114
 
 
115
 
long arch_ptrace(struct task_struct *child, long request,
116
 
                 unsigned long addr, unsigned long data)
117
 
{
118
 
        int ret;
119
 
        int regno = addr >> 2;
120
 
        unsigned long __user *datap = (unsigned long __user *) data;
121
 
 
122
 
        switch (request) {
123
 
                /* read the word at location addr in the USER area. */
124
 
                case PTRACE_PEEKUSR: {
125
 
                        unsigned long tmp;
126
 
                        
127
 
                        ret = -EIO;
128
 
                        if ((addr & 3) || addr > sizeof(struct user) - 3)
129
 
                                break;
130
 
                        
131
 
                        tmp = 0;  /* Default return condition */
132
 
                        ret = -EIO;
133
 
                        if (regno < 19) {
134
 
                                tmp = get_reg(child, regno);
135
 
                                if (regno == PT_SR)
136
 
                                        tmp >>= 16;
137
 
                        } else if (regno >= 21 && regno < 49) {
138
 
                                tmp = child->thread.fp[regno - 21];
139
 
                        } else if (regno == 49) {
140
 
                                tmp = child->mm->start_code;
141
 
                        } else if (regno == 50) {
142
 
                                tmp = child->mm->start_data;
143
 
                        } else if (regno == 51) {
144
 
                                tmp = child->mm->end_code;
145
 
                        } else
146
 
                                break;
147
 
                        ret = put_user(tmp, datap);
148
 
                        break;
149
 
                }
150
 
 
151
 
                case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
152
 
                        ret = -EIO;
153
 
                        if ((addr & 3) || addr > sizeof(struct user) - 3)
154
 
                                break;
155
 
 
156
 
                        if (regno == PT_SR) {
157
 
                                data &= SR_MASK;
158
 
                                data <<= 16;
159
 
                                data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
160
 
                        }
161
 
                        if (regno < 19) {
162
 
                                if (put_reg(child, regno, data))
163
 
                                        break;
164
 
                                ret = 0;
165
 
                                break;
166
 
                        }
167
 
                        if (regno >= 21 && regno < 48)
168
 
                        {
169
 
                                child->thread.fp[regno - 21] = data;
170
 
                                ret = 0;
171
 
                        }
172
 
                        break;
173
 
 
174
 
                case PTRACE_GETREGS: { /* Get all gp regs from the child. */
175
 
                        int i;
176
 
                        unsigned long tmp;
177
 
                        for (i = 0; i < 19; i++) {
178
 
                            tmp = get_reg(child, i);
179
 
                            if (i == PT_SR)
180
 
                                tmp >>= 16;
181
 
                            if (put_user(tmp, datap)) {
182
 
                                ret = -EFAULT;
183
 
                                break;
184
 
                            }
185
 
                            datap++;
186
 
                        }
187
 
                        ret = 0;
188
 
                        break;
189
 
                }
190
 
 
191
 
                case PTRACE_SETREGS: { /* Set all gp regs in the child. */
192
 
                        int i;
193
 
                        unsigned long tmp;
194
 
                        for (i = 0; i < 19; i++) {
195
 
                            if (get_user(tmp, datap)) {
196
 
                                ret = -EFAULT;
197
 
                                break;
198
 
                            }
199
 
                            if (i == PT_SR) {
200
 
                                tmp &= SR_MASK;
201
 
                                tmp <<= 16;
202
 
                                tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
203
 
                            }
204
 
                            put_reg(child, i, tmp);
205
 
                            datap++;
206
 
                        }
207
 
                        ret = 0;
208
 
                        break;
209
 
                }
210
 
 
211
 
#ifdef PTRACE_GETFPREGS
212
 
                case PTRACE_GETFPREGS: { /* Get the child FPU state. */
213
 
                        ret = 0;
214
 
                        if (copy_to_user(datap, &child->thread.fp,
215
 
                                         sizeof(struct user_m68kfp_struct)))
216
 
                                ret = -EFAULT;
217
 
                        break;
218
 
                }
219
 
#endif
220
 
 
221
 
#ifdef PTRACE_SETFPREGS
222
 
                case PTRACE_SETFPREGS: { /* Set the child FPU state. */
223
 
                        ret = 0;
224
 
                        if (copy_from_user(&child->thread.fp, datap,
225
 
                                           sizeof(struct user_m68kfp_struct)))
226
 
                                ret = -EFAULT;
227
 
                        break;
228
 
                }
229
 
#endif
230
 
 
231
 
        case PTRACE_GET_THREAD_AREA:
232
 
                ret = put_user(task_thread_info(child)->tp_value, datap);
233
 
                break;
234
 
 
235
 
                default:
236
 
                        ret = ptrace_request(child, request, addr, data);
237
 
                        break;
238
 
        }
239
 
        return ret;
240
 
}
241
 
 
242
 
asmlinkage int syscall_trace_enter(void)
243
 
{
244
 
        int ret = 0;
245
 
 
246
 
        if (test_thread_flag(TIF_SYSCALL_TRACE))
247
 
                ret = tracehook_report_syscall_entry(task_pt_regs(current));
248
 
        return ret;
249
 
}
250
 
 
251
 
asmlinkage void syscall_trace_leave(void)
252
 
{
253
 
        if (test_thread_flag(TIF_SYSCALL_TRACE))
254
 
                tracehook_report_syscall_exit(task_pt_regs(current), 0);
255
 
}