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