1/* 2 * File: arch/blackfin/kernel/ptrace.c 3 * Based on: Taken from linux/kernel/ptrace.c 4 * Author: linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds 5 * 6 * Created: 1/23/92 7 * Description: 8 * 9 * Modified: 10 * Copyright 2004-2006 Analog Devices Inc. 11 * 12 * Bugs: Enter bugs at http://blackfin.uclinux.org/ 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License as published by 16 * the Free Software Foundation; either version 2 of the License, or 17 * (at your option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program; if not, see the file COPYING, or write 26 * to the Free Software Foundation, Inc., 27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 28 */ 29 30#include <linux/kernel.h> 31#include <linux/sched.h> 32#include <linux/mm.h> 33#include <linux/smp.h> 34#include <linux/smp_lock.h> 35#include <linux/errno.h> 36#include <linux/ptrace.h> 37#include <linux/user.h> 38#include <linux/signal.h> 39 40#include <asm/uaccess.h> 41#include <asm/page.h> 42#include <asm/pgtable.h> 43#include <asm/system.h> 44#include <asm/processor.h> 45#include <asm/asm-offsets.h> 46#include <asm/dma.h> 47 48#define MAX_SHARED_LIBS 3 49#define TEXT_OFFSET 0 50/* 51 * does not yet catch signals sent when the child dies. 52 * in exit.c or in signal.c. 53 */ 54 55/* determines which bits in the SYSCFG reg the user has access to. */ 56/* 1 = access 0 = no access */ 57#define SYSCFG_MASK 0x0007 /* SYSCFG reg */ 58/* sets the trace bits. */ 59#define TRACE_BITS 0x0001 60 61/* Find the stack offset for a register, relative to thread.esp0. */ 62#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) 63 64/* 65 * Get the address of the live pt_regs for the specified task. 66 * These are saved onto the top kernel stack when the process 67 * is not running. 68 * 69 * Note: if a user thread is execve'd from kernel space, the 70 * kernel stack will not be empty on entry to the kernel, so 71 * ptracing these tasks will fail. 72 */ 73static inline struct pt_regs *get_user_regs(struct task_struct *task) 74{ 75 return (struct pt_regs *) 76 ((unsigned long)task_stack_page(task) + 77 (THREAD_SIZE - sizeof(struct pt_regs))); 78} 79 80/* 81 * Get all user integer registers. 82 */ 83static inline int ptrace_getregs(struct task_struct *tsk, void __user * uregs) 84{ 85 struct pt_regs *regs = get_user_regs(tsk); 86 return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; 87} 88 89/* Mapping from PT_xxx to the stack offset at which the register is 90 * saved. Notice that usp has no stack-slot and needs to be treated 91 * specially (see get_reg/put_reg below). 92 */ 93 94/* 95 * Get contents of register REGNO in task TASK. 96 */ 97static inline long get_reg(struct task_struct *task, int regno) 98{ 99 unsigned char *reg_ptr; 100 101 struct pt_regs *regs = 102 (struct pt_regs *)((unsigned long)task_stack_page(task) + 103 (THREAD_SIZE - sizeof(struct pt_regs))); 104 reg_ptr = (char *)regs; 105 106 switch (regno) { 107 case PT_USP: 108 return task->thread.usp; 109 default: 110 if (regno <= 216) 111 return *(long *)(reg_ptr + regno); 112 } 113 /* slight mystery ... never seems to come here but kernel misbehaves without this code! */ 114 115 printk(KERN_WARNING "Request to get for unknown register %d\n", regno); 116 return 0; 117} 118 119/* 120 * Write contents of register REGNO in task TASK. 121 */ 122static inline int 123put_reg(struct task_struct *task, int regno, unsigned long data) 124{ 125 char * reg_ptr; 126 127 struct pt_regs *regs = 128 (struct pt_regs *)((unsigned long)task_stack_page(task) + 129 (THREAD_SIZE - sizeof(struct pt_regs))); 130 reg_ptr = (char *)regs; 131 132 switch (regno) { 133 case PT_PC: 134 /*********************************************************************/ 135 /* At this point the kernel is most likely in exception. */ 136 /* The RETX register will be used to populate the pc of the process. */ 137 /*********************************************************************/ 138 regs->retx = data; 139 regs->pc = data; 140 break; 141 case PT_RETX: 142 break; /* regs->retx = data; break; */ 143 case PT_USP: 144 regs->usp = data; 145 task->thread.usp = data; 146 break; 147 default: 148 if (regno <= 216) 149 *(long *)(reg_ptr + regno) = data; 150 } 151 return 0; 152} 153 154/* 155 * check that an address falls within the bounds of the target process's memory mappings 156 */ 157static inline int is_user_addr_valid(struct task_struct *child, 158 unsigned long start, unsigned long len) 159{ 160 struct vm_list_struct *vml; 161 struct sram_list_struct *sraml; 162 163 for (vml = child->mm->context.vmlist; vml; vml = vml->next) 164 if (start >= vml->vma->vm_start && start + len <= vml->vma->vm_end) 165 return 0; 166 167 for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next) 168 if (start >= (unsigned long)sraml->addr 169 && start + len <= (unsigned long)sraml->addr + sraml->length) 170 return 0; 171 172 return -EIO; 173} 174 175/* 176 * Called by kernel/ptrace.c when detaching.. 177 * 178 * Make sure the single step bit is not set. 179 */ 180void ptrace_disable(struct task_struct *child) 181{ 182 unsigned long tmp; 183 /* make sure the single step bit is not set. */ 184 tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); 185 put_reg(child, PT_SR, tmp); 186} 187 188long arch_ptrace(struct task_struct *child, long request, long addr, long data) 189{ 190 int ret; 191 int add = 0; 192 193 switch (request) { 194 /* when I and D space are separate, these will need to be fixed. */ 195 case PTRACE_PEEKDATA: 196 pr_debug("ptrace: PEEKDATA\n"); 197 add = MAX_SHARED_LIBS * 4; /* space between text and data */ 198 /* fall through */ 199 case PTRACE_PEEKTEXT: /* read word at location addr. */ 200 { 201 unsigned long tmp = 0; 202 int copied; 203 204 ret = -EIO; 205 pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + add %d %ld\n", addr, add, 206 sizeof(data)); 207 if (is_user_addr_valid(child, addr + add, sizeof(tmp)) < 0) 208 break; 209 pr_debug("ptrace: user address is valid\n"); 210 211#if L1_CODE_LENGTH != 0 212 if (addr + add >= L1_CODE_START 213 && addr + add + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) { 214 safe_dma_memcpy (&tmp, (const void *)(addr + add), sizeof(tmp)); 215 copied = sizeof(tmp); 216 } else 217#endif 218 copied = 219 access_process_vm(child, addr + add, &tmp, 220 sizeof(tmp), 0); 221 pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp); 222 if (copied != sizeof(tmp)) 223 break; 224 ret = put_user(tmp, (unsigned long *)data); 225 break; 226 } 227 228 /* read the word at location addr in the USER area. */ 229 case PTRACE_PEEKUSR: 230 { 231 unsigned long tmp; 232 ret = -EIO; 233 tmp = 0; 234 if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) { 235 printk(KERN_WARNING "ptrace error : PEEKUSR : temporarily returning " 236 "0 - %x sizeof(pt_regs) is %lx\n", 237 (int)addr, sizeof(struct pt_regs)); 238 break; 239 } 240 if (addr == sizeof(struct pt_regs)) { 241 /* PT_TEXT_ADDR */ 242 tmp = child->mm->start_code + TEXT_OFFSET; 243 } else if (addr == (sizeof(struct pt_regs) + 4)) { 244 /* PT_TEXT_END_ADDR */ 245 tmp = child->mm->end_code; 246 } else if (addr == (sizeof(struct pt_regs) + 8)) { 247 /* PT_DATA_ADDR */ 248 tmp = child->mm->start_data; 249#ifdef CONFIG_BINFMT_ELF_FDPIC 250 } else if (addr == (sizeof(struct pt_regs) + 12)) { 251 tmp = child->mm->context.exec_fdpic_loadmap; 252 } else if (addr == (sizeof(struct pt_regs) + 16)) { 253 tmp = child->mm->context.interp_fdpic_loadmap; 254#endif 255 } else { 256 tmp = get_reg(child, addr); 257 } 258 ret = put_user(tmp, (unsigned long *)data); 259 break; 260 } 261 262 /* when I and D space are separate, this will have to be fixed. */ 263 case PTRACE_POKEDATA: 264 printk(KERN_NOTICE "ptrace: PTRACE_PEEKDATA\n"); 265 /* fall through */ 266 case PTRACE_POKETEXT: /* write the word at location addr. */ 267 { 268 int copied; 269 270 ret = -EIO; 271 pr_debug("ptrace: POKETEXT at addr 0x%08lx + add %d %ld bytes %lx\n", 272 addr, add, sizeof(data), data); 273 if (is_user_addr_valid(child, addr + add, sizeof(data)) < 0) 274 break; 275 pr_debug("ptrace: user address is valid\n"); 276 277#if L1_CODE_LENGTH != 0 278 if (addr + add >= L1_CODE_START 279 && addr + add + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) { 280 safe_dma_memcpy ((void *)(addr + add), &data, sizeof(data)); 281 copied = sizeof(data); 282 } else 283#endif 284 copied = 285 access_process_vm(child, addr + add, &data, 286 sizeof(data), 1); 287 pr_debug("ptrace: copied size %d\n", copied); 288 if (copied != sizeof(data)) 289 break; 290 ret = 0; 291 break; 292 } 293 294 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ 295 ret = -EIO; 296 if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) { 297 printk(KERN_WARNING "ptrace error : POKEUSR: temporarily returning 0\n"); 298 break; 299 } 300 301 if (addr >= (sizeof(struct pt_regs))) { 302 ret = 0; 303 break; 304 } 305 if (addr == PT_SYSCFG) { 306 data &= SYSCFG_MASK; 307 data |= get_reg(child, PT_SYSCFG); 308 } 309 ret = put_reg(child, addr, data); 310 break; 311 312 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ 313 case PTRACE_CONT: 314 { /* restart after signal. */ 315 long tmp; 316 317 pr_debug("ptrace_cont\n"); 318 319 ret = -EIO; 320 if (!valid_signal(data)) 321 break; 322 if (request == PTRACE_SYSCALL) 323 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 324 else 325 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 326 327 child->exit_code = data; 328 /* make sure the single step bit is not set. */ 329 tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS); 330 put_reg(child, PT_SYSCFG, tmp); 331 pr_debug("before wake_up_process\n"); 332 wake_up_process(child); 333 ret = 0; 334 break; 335 } 336 337 /* 338 * make the child exit. Best I can do is send it a sigkill. 339 * perhaps it should be put in the status that it wants to 340 * exit. 341 */ 342 case PTRACE_KILL: 343 { 344 long tmp; 345 ret = 0; 346 if (child->exit_state == EXIT_ZOMBIE) /* already dead */ 347 break; 348 child->exit_code = SIGKILL; 349 /* make sure the single step bit is not set. */ 350 tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS); 351 put_reg(child, PT_SYSCFG, tmp); 352 wake_up_process(child); 353 break; 354 } 355 356 case PTRACE_SINGLESTEP: 357 { /* set the trap flag. */ 358 long tmp; 359 360 pr_debug("single step\n"); 361 ret = -EIO; 362 if (!valid_signal(data)) 363 break; 364 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 365 366 tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS); 367 put_reg(child, PT_SYSCFG, tmp); 368 369 child->exit_code = data; 370 /* give it a chance to run. */ 371 wake_up_process(child); 372 ret = 0; 373 break; 374 } 375 376 case PTRACE_DETACH: 377 { /* detach a process that was attached. */ 378 ret = ptrace_detach(child, data); 379 break; 380 } 381 382 case PTRACE_GETREGS: 383 { 384 385 /* Get all gp regs from the child. */ 386 ret = ptrace_getregs(child, (void __user *)data); 387 break; 388 } 389 390 case PTRACE_SETREGS: 391 { 392 printk(KERN_NOTICE 393 "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n"); 394 /* Set all gp regs in the child. */ 395 ret = 0; 396 break; 397 } 398 default: 399 ret = ptrace_request(child, request, addr, data); 400 break; 401 } 402 403 return ret; 404} 405 406asmlinkage void syscall_trace(void) 407{ 408 409 if (!test_thread_flag(TIF_SYSCALL_TRACE)) 410 return; 411 412 if (!(current->ptrace & PT_PTRACED)) 413 return; 414 415 /* the 0x80 provides a way for the tracing parent to distinguish 416 * between a syscall stop and SIGTRAP delivery 417 */ 418 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) 419 ? 0x80 : 0)); 420 421 /* 422 * this isn't the same as continuing with a signal, but it will do 423 * for normal use. strace only continues with a signal if the 424 * stopping signal is not SIGTRAP. -brl 425 */ 426 if (current->exit_code) { 427 send_sig(current->exit_code, current, 1); 428 current->exit_code = 0; 429 } 430} 431