1 // TODO some minor issues 2 /* 3 * This file is subject to the terms and conditions of the GNU General Public 4 * License. See the file "COPYING" in the main directory of this archive 5 * for more details. 6 * 7 * Copyright (C) 2001 - 2005 Tensilica Inc. 8 * 9 * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> 10 * Chris Zankel <chris@zankel.net> 11 * Scott Foehner<sfoehner@yahoo.com>, 12 * Kevin Chea 13 * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca> 14 */ 15 16 #include <linux/config.h> 17 #include <linux/kernel.h> 18 #include <linux/sched.h> 19 #include <linux/mm.h> 20 #include <linux/errno.h> 21 #include <linux/ptrace.h> 22 #include <linux/smp.h> 23 #include <linux/smp_lock.h> 24 #include <linux/security.h> 25 #include <linux/signal.h> 26 27 #include <asm/pgtable.h> 28 #include <asm/page.h> 29 #include <asm/system.h> 30 #include <asm/uaccess.h> 31 #include <asm/ptrace.h> 32 #include <asm/elf.h> 33 34 #define TEST_KERNEL // verify kernel operations FIXME: remove 35 36 37 /* 38 * Called by kernel/ptrace.c when detaching.. 39 * 40 * Make sure single step bits etc are not set. 41 */ 42 43 void ptrace_disable(struct task_struct *child) 44 { 45 /* Nothing to do.. */ 46 } 47 48 long arch_ptrace(struct task_struct *child, long request, long addr, long data) 49 { 50 int ret = -EPERM; 51 52 switch (request) { 53 case PTRACE_PEEKTEXT: /* read word at location addr. */ 54 case PTRACE_PEEKDATA: 55 { 56 unsigned long tmp; 57 int copied; 58 59 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); 60 ret = -EIO; 61 if (copied != sizeof(tmp)) 62 break; 63 ret = put_user(tmp,(unsigned long *) data); 64 65 goto out; 66 } 67 68 /* Read the word at location addr in the USER area. */ 69 70 case PTRACE_PEEKUSR: 71 { 72 struct pt_regs *regs; 73 unsigned long tmp; 74 75 regs = xtensa_pt_regs(child); 76 tmp = 0; /* Default return value. */ 77 78 switch(addr) { 79 80 case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1: 81 { 82 int ar = addr - REG_AR_BASE - regs->windowbase * 4; 83 ar &= (XCHAL_NUM_AREGS - 1); 84 if (ar < 16 && ar + (regs->wmask >> 4) * 4 >= 0) 85 tmp = regs->areg[ar]; 86 else 87 ret = -EIO; 88 break; 89 } 90 case REG_A_BASE ... REG_A_BASE + 15: 91 tmp = regs->areg[addr - REG_A_BASE]; 92 break; 93 case REG_PC: 94 tmp = regs->pc; 95 break; 96 case REG_PS: 97 /* Note: PS.EXCM is not set while user task is running; 98 * its being set in regs is for exception handling 99 * convenience. */ 100 tmp = (regs->ps & ~XCHAL_PS_EXCM_MASK); 101 break; 102 case REG_WB: 103 tmp = regs->windowbase; 104 break; 105 case REG_WS: 106 tmp = regs->windowstart; 107 break; 108 case REG_LBEG: 109 tmp = regs->lbeg; 110 break; 111 case REG_LEND: 112 tmp = regs->lend; 113 break; 114 case REG_LCOUNT: 115 tmp = regs->lcount; 116 break; 117 case REG_SAR: 118 tmp = regs->sar; 119 break; 120 case REG_DEPC: 121 tmp = regs->depc; 122 break; 123 case REG_EXCCAUSE: 124 tmp = regs->exccause; 125 break; 126 case REG_EXCVADDR: 127 tmp = regs->excvaddr; 128 break; 129 case SYSCALL_NR: 130 tmp = regs->syscall; 131 break; 132 default: 133 tmp = 0; 134 ret = -EIO; 135 goto out; 136 } 137 ret = put_user(tmp, (unsigned long *) data); 138 goto out; 139 } 140 141 case PTRACE_POKETEXT: /* write the word at location addr. */ 142 case PTRACE_POKEDATA: 143 if (access_process_vm(child, addr, &data, sizeof(data), 1) 144 == sizeof(data)) 145 break; 146 ret = -EIO; 147 goto out; 148 149 case PTRACE_POKEUSR: 150 { 151 struct pt_regs *regs; 152 regs = xtensa_pt_regs(child); 153 154 switch (addr) { 155 case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1: 156 { 157 int ar = addr - REG_AR_BASE - regs->windowbase * 4; 158 if (ar < 16 && ar + (regs->wmask >> 4) * 4 >= 0) 159 regs->areg[ar & (XCHAL_NUM_AREGS - 1)] = data; 160 else 161 ret = -EIO; 162 break; 163 } 164 case REG_A_BASE ... REG_A_BASE + 15: 165 regs->areg[addr - REG_A_BASE] = data; 166 break; 167 case REG_PC: 168 regs->pc = data; 169 break; 170 case SYSCALL_NR: 171 regs->syscall = data; 172 break; 173 #ifdef TEST_KERNEL 174 case REG_WB: 175 regs->windowbase = data; 176 break; 177 case REG_WS: 178 regs->windowstart = data; 179 break; 180 #endif 181 182 default: 183 /* The rest are not allowed. */ 184 ret = -EIO; 185 break; 186 } 187 break; 188 } 189 190 /* continue and stop at next (return from) syscall */ 191 case PTRACE_SYSCALL: 192 case PTRACE_CONT: /* restart after signal. */ 193 { 194 ret = -EIO; 195 if (!valid_signal(data)) 196 break; 197 if (request == PTRACE_SYSCALL) 198 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 199 else 200 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 201 child->exit_code = data; 202 /* Make sure the single step bit is not set. */ 203 child->ptrace &= ~PT_SINGLESTEP; 204 wake_up_process(child); 205 ret = 0; 206 break; 207 } 208 209 /* 210 * make the child exit. Best I can do is send it a sigkill. 211 * perhaps it should be put in the status that it wants to 212 * exit. 213 */ 214 case PTRACE_KILL: 215 ret = 0; 216 if (child->state == EXIT_ZOMBIE) /* already dead */ 217 break; 218 child->exit_code = SIGKILL; 219 child->ptrace &= ~PT_SINGLESTEP; 220 wake_up_process(child); 221 break; 222 223 case PTRACE_SINGLESTEP: 224 ret = -EIO; 225 if (!valid_signal(data)) 226 break; 227 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 228 child->ptrace |= PT_SINGLESTEP; 229 child->exit_code = data; 230 wake_up_process(child); 231 ret = 0; 232 break; 233 234 case PTRACE_GETREGS: 235 { 236 /* 'data' points to user memory in which to write. 237 * Mainly due to the non-live register values, we 238 * reformat the register values into something more 239 * standard. For convenience, we use the handy 240 * elf_gregset_t format. */ 241 242 xtensa_gregset_t format; 243 struct pt_regs *regs = xtensa_pt_regs(child); 244 245 do_copy_regs (&format, regs, child); 246 247 /* Now, copy to user space nice and easy... */ 248 ret = 0; 249 if (copy_to_user((void *)data, &format, sizeof(elf_gregset_t))) 250 ret = -EFAULT; 251 break; 252 } 253 254 case PTRACE_SETREGS: 255 { 256 /* 'data' points to user memory that contains the new 257 * values in the elf_gregset_t format. */ 258 259 xtensa_gregset_t format; 260 struct pt_regs *regs = xtensa_pt_regs(child); 261 262 if (copy_from_user(&format,(void *)data,sizeof(elf_gregset_t))){ 263 ret = -EFAULT; 264 break; 265 } 266 267 /* FIXME: Perhaps we want some sanity checks on 268 * these user-space values? See ARM version. Are 269 * debuggers a security concern? */ 270 271 do_restore_regs (&format, regs, child); 272 273 ret = 0; 274 break; 275 } 276 277 case PTRACE_GETFPREGS: 278 { 279 /* 'data' points to user memory in which to write. 280 * For convenience, we use the handy 281 * elf_fpregset_t format. */ 282 283 elf_fpregset_t fpregs; 284 struct pt_regs *regs = xtensa_pt_regs(child); 285 286 do_save_fpregs (&fpregs, regs, child); 287 288 /* Now, copy to user space nice and easy... */ 289 ret = 0; 290 if (copy_to_user((void *)data, &fpregs, sizeof(elf_fpregset_t))) 291 ret = -EFAULT; 292 293 break; 294 } 295 296 case PTRACE_SETFPREGS: 297 { 298 /* 'data' points to user memory that contains the new 299 * values in the elf_fpregset_t format. 300 */ 301 elf_fpregset_t fpregs; 302 struct pt_regs *regs = xtensa_pt_regs(child); 303 304 ret = 0; 305 if (copy_from_user(&fpregs, (void *)data, sizeof(elf_fpregset_t))) { 306 ret = -EFAULT; 307 break; 308 } 309 310 if (do_restore_fpregs (&fpregs, regs, child)) 311 ret = -EIO; 312 break; 313 } 314 315 case PTRACE_GETFPREGSIZE: 316 /* 'data' points to 'unsigned long' set to the size 317 * of elf_fpregset_t 318 */ 319 ret = put_user(sizeof(elf_fpregset_t), (unsigned long *) data); 320 break; 321 322 case PTRACE_DETACH: /* detach a process that was attached. */ 323 ret = ptrace_detach(child, data); 324 break; 325 326 default: 327 ret = ptrace_request(child, request, addr, data); 328 goto out; 329 } 330 out: 331 return ret; 332 } 333 334 void do_syscall_trace(void) 335 { 336 if (!test_thread_flag(TIF_SYSCALL_TRACE)) 337 return; 338 339 if (!(current->ptrace & PT_PTRACED)) 340 return; 341 342 /* 343 * The 0x80 provides a way for the tracing parent to distinguish 344 * between a syscall stop and SIGTRAP delivery 345 */ 346 ptrace_notify(SIGTRAP|((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); 347 348 /* 349 * this isn't the same as continuing with a signal, but it will do 350 * for normal use. strace only continues with a signal if the 351 * stopping signal is not SIGTRAP. -brl 352 */ 353 if (current->exit_code) { 354 send_sig(current->exit_code, current, 1); 355 current->exit_code = 0; 356 } 357 } 358