1/* 2 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds 3 * these modifications are Copyright 2004-2010 Analog Devices Inc. 4 * 5 * Licensed under the GPL-2 6 */ 7 8#include <linux/kernel.h> 9#include <linux/sched.h> 10#include <linux/mm.h> 11#include <linux/smp.h> 12#include <linux/elf.h> 13#include <linux/errno.h> 14#include <linux/ptrace.h> 15#include <linux/user.h> 16#include <linux/regset.h> 17#include <linux/signal.h> 18#include <linux/tracehook.h> 19#include <linux/uaccess.h> 20 21#include <asm/page.h> 22#include <asm/pgtable.h> 23#include <asm/processor.h> 24#include <asm/asm-offsets.h> 25#include <asm/dma.h> 26#include <asm/fixed_code.h> 27#include <asm/cacheflush.h> 28#include <asm/mem_map.h> 29#include <asm/mmu_context.h> 30 31/* 32 * does not yet catch signals sent when the child dies. 33 * in exit.c or in signal.c. 34 */ 35 36/* 37 * Get contents of register REGNO in task TASK. 38 */ 39static inline long 40get_reg(struct task_struct *task, unsigned long regno, 41 unsigned long __user *datap) 42{ 43 long tmp; 44 struct pt_regs *regs = task_pt_regs(task); 45 46 if (regno & 3 || regno > PT_LAST_PSEUDO) 47 return -EIO; 48 49 switch (regno) { 50 case PT_TEXT_ADDR: 51 tmp = task->mm->start_code; 52 break; 53 case PT_TEXT_END_ADDR: 54 tmp = task->mm->end_code; 55 break; 56 case PT_DATA_ADDR: 57 tmp = task->mm->start_data; 58 break; 59 case PT_USP: 60 tmp = task->thread.usp; 61 break; 62 default: 63 if (regno < sizeof(*regs)) { 64 void *reg_ptr = regs; 65 tmp = *(long *)(reg_ptr + regno); 66 } else 67 return -EIO; 68 } 69 70 return put_user(tmp, datap); 71} 72 73/* 74 * Write contents of register REGNO in task TASK. 75 */ 76static inline int 77put_reg(struct task_struct *task, unsigned long regno, unsigned long data) 78{ 79 struct pt_regs *regs = task_pt_regs(task); 80 81 if (regno & 3 || regno > PT_LAST_PSEUDO) 82 return -EIO; 83 84 switch (regno) { 85 case PT_PC: 86 /*********************************************************************/ 87 /* At this point the kernel is most likely in exception. */ 88 /* The RETX register will be used to populate the pc of the process. */ 89 /*********************************************************************/ 90 regs->retx = data; 91 regs->pc = data; 92 break; 93 case PT_RETX: 94 break; /* regs->retx = data; break; */ 95 case PT_USP: 96 regs->usp = data; 97 task->thread.usp = data; 98 break; 99 case PT_SYSCFG: /* don't let userspace screw with this */ 100 if ((data & ~1) != 0x6) 101 pr_warning("ptrace: ignore syscfg write of %#lx\n", data); 102 break; /* regs->syscfg = data; break; */ 103 default: 104 if (regno < sizeof(*regs)) { 105 void *reg_offset = regs; 106 *(long *)(reg_offset + regno) = data; 107 } 108 /* Ignore writes to pseudo registers */ 109 } 110 111 return 0; 112} 113 114/* 115 * check that an address falls within the bounds of the target process's memory mappings 116 */ 117int 118is_user_addr_valid(struct task_struct *child, unsigned long start, unsigned long len) 119{ 120 bool valid; 121 struct vm_area_struct *vma; 122 struct sram_list_struct *sraml; 123 124 /* overflow */ 125 if (start + len < start) 126 return -EIO; 127 128 down_read(&child->mm->mmap_sem); 129 vma = find_vma(child->mm, start); 130 valid = vma && start >= vma->vm_start && start + len <= vma->vm_end; 131 up_read(&child->mm->mmap_sem); 132 if (valid) 133 return 0; 134 135 for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next) 136 if (start >= (unsigned long)sraml->addr 137 && start + len < (unsigned long)sraml->addr + sraml->length) 138 return 0; 139 140 if (start >= FIXED_CODE_START && start + len < FIXED_CODE_END) 141 return 0; 142 143#ifdef CONFIG_APP_STACK_L1 144 if (child->mm->context.l1_stack_save) 145 if (start >= (unsigned long)l1_stack_base && 146 start + len < (unsigned long)l1_stack_base + l1_stack_len) 147 return 0; 148#endif 149 150 return -EIO; 151} 152 153/* 154 * retrieve the contents of Blackfin userspace general registers 155 */ 156static int genregs_get(struct task_struct *target, 157 const struct user_regset *regset, 158 unsigned int pos, unsigned int count, 159 void *kbuf, void __user *ubuf) 160{ 161 struct pt_regs *regs = task_pt_regs(target); 162 int ret; 163 164 /* This sucks ... */ 165 regs->usp = target->thread.usp; 166 167 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 168 regs, 0, sizeof(*regs)); 169 if (ret < 0) 170 return ret; 171 172 return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 173 sizeof(*regs), -1); 174} 175 176/* 177 * update the contents of the Blackfin userspace general registers 178 */ 179static int genregs_set(struct task_struct *target, 180 const struct user_regset *regset, 181 unsigned int pos, unsigned int count, 182 const void *kbuf, const void __user *ubuf) 183{ 184 struct pt_regs *regs = task_pt_regs(target); 185 int ret; 186 187 /* Don't let people set SYSCFG (it's at the end of pt_regs) */ 188 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 189 regs, 0, PT_SYSCFG); 190 if (ret < 0) 191 return ret; 192 193 /* This sucks ... */ 194 target->thread.usp = regs->usp; 195 /* regs->retx = regs->pc; */ 196 197 return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 198 PT_SYSCFG, -1); 199} 200 201/* 202 * Define the register sets available on the Blackfin under Linux 203 */ 204enum bfin_regset { 205 REGSET_GENERAL, 206}; 207 208static const struct user_regset bfin_regsets[] = { 209 [REGSET_GENERAL] = { 210 .core_note_type = NT_PRSTATUS, 211 .n = sizeof(struct pt_regs) / sizeof(long), 212 .size = sizeof(long), 213 .align = sizeof(long), 214 .get = genregs_get, 215 .set = genregs_set, 216 }, 217}; 218 219static const struct user_regset_view user_bfin_native_view = { 220 .name = "Blackfin", 221 .e_machine = EM_BLACKFIN, 222 .regsets = bfin_regsets, 223 .n = ARRAY_SIZE(bfin_regsets), 224}; 225 226const struct user_regset_view *task_user_regset_view(struct task_struct *task) 227{ 228 return &user_bfin_native_view; 229} 230 231void user_enable_single_step(struct task_struct *child) 232{ 233 struct pt_regs *regs = task_pt_regs(child); 234 regs->syscfg |= SYSCFG_SSSTEP; 235 236 set_tsk_thread_flag(child, TIF_SINGLESTEP); 237} 238 239void user_disable_single_step(struct task_struct *child) 240{ 241 struct pt_regs *regs = task_pt_regs(child); 242 regs->syscfg &= ~SYSCFG_SSSTEP; 243 244 clear_tsk_thread_flag(child, TIF_SINGLESTEP); 245} 246 247long arch_ptrace(struct task_struct *child, long request, 248 unsigned long addr, unsigned long data) 249{ 250 int ret; 251 unsigned long __user *datap = (unsigned long __user *)data; 252 void *paddr = (void *)addr; 253 254 switch (request) { 255 /* when I and D space are separate, these will need to be fixed. */ 256 case PTRACE_PEEKDATA: 257 pr_debug("ptrace: PEEKDATA\n"); 258 /* fall through */ 259 case PTRACE_PEEKTEXT: /* read word at location addr. */ 260 { 261 unsigned long tmp = 0; 262 int copied = 0, to_copy = sizeof(tmp); 263 264 ret = -EIO; 265 pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + %i\n", addr, to_copy); 266 if (is_user_addr_valid(child, addr, to_copy) < 0) 267 break; 268 pr_debug("ptrace: user address is valid\n"); 269 270 switch (bfin_mem_access_type(addr, to_copy)) { 271 case BFIN_MEM_ACCESS_CORE: 272 case BFIN_MEM_ACCESS_CORE_ONLY: 273 copied = access_process_vm(child, addr, &tmp, 274 to_copy, 0); 275 if (copied) 276 break; 277 278 /* hrm, why didn't that work ... maybe no mapping */ 279 if (addr >= FIXED_CODE_START && 280 addr + to_copy <= FIXED_CODE_END) { 281 copy_from_user_page(0, 0, 0, &tmp, paddr, to_copy); 282 copied = to_copy; 283 } else if (addr >= BOOT_ROM_START) { 284 memcpy(&tmp, paddr, to_copy); 285 copied = to_copy; 286 } 287 288 break; 289 case BFIN_MEM_ACCESS_DMA: 290 if (safe_dma_memcpy(&tmp, paddr, to_copy)) 291 copied = to_copy; 292 break; 293 case BFIN_MEM_ACCESS_ITEST: 294 if (isram_memcpy(&tmp, paddr, to_copy)) 295 copied = to_copy; 296 break; 297 default: 298 copied = 0; 299 break; 300 } 301 302 pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp); 303 if (copied == to_copy) 304 ret = put_user(tmp, datap); 305 break; 306 } 307 308 /* when I and D space are separate, this will have to be fixed. */ 309 case PTRACE_POKEDATA: 310 pr_debug("ptrace: PTRACE_PEEKDATA\n"); 311 /* fall through */ 312 case PTRACE_POKETEXT: /* write the word at location addr. */ 313 { 314 int copied = 0, to_copy = sizeof(data); 315 316 ret = -EIO; 317 pr_debug("ptrace: POKETEXT at addr 0x%08lx + %i bytes %lx\n", 318 addr, to_copy, data); 319 if (is_user_addr_valid(child, addr, to_copy) < 0) 320 break; 321 pr_debug("ptrace: user address is valid\n"); 322 323 switch (bfin_mem_access_type(addr, to_copy)) { 324 case BFIN_MEM_ACCESS_CORE: 325 case BFIN_MEM_ACCESS_CORE_ONLY: 326 copied = access_process_vm(child, addr, &data, 327 to_copy, 1); 328 break; 329 case BFIN_MEM_ACCESS_DMA: 330 if (safe_dma_memcpy(paddr, &data, to_copy)) 331 copied = to_copy; 332 break; 333 case BFIN_MEM_ACCESS_ITEST: 334 if (isram_memcpy(paddr, &data, to_copy)) 335 copied = to_copy; 336 break; 337 default: 338 copied = 0; 339 break; 340 } 341 342 pr_debug("ptrace: copied size %d\n", copied); 343 if (copied == to_copy) 344 ret = 0; 345 break; 346 } 347 348 case PTRACE_PEEKUSR: 349 switch (addr) { 350#ifdef CONFIG_BINFMT_ELF_FDPIC /* backwards compat */ 351 case PT_FDPIC_EXEC: 352 request = PTRACE_GETFDPIC; 353 addr = PTRACE_GETFDPIC_EXEC; 354 goto case_default; 355 case PT_FDPIC_INTERP: 356 request = PTRACE_GETFDPIC; 357 addr = PTRACE_GETFDPIC_INTERP; 358 goto case_default; 359#endif 360 default: 361 ret = get_reg(child, addr, datap); 362 } 363 pr_debug("ptrace: PEEKUSR reg %li with %#lx = %i\n", addr, data, ret); 364 break; 365 366 case PTRACE_POKEUSR: 367 ret = put_reg(child, addr, data); 368 pr_debug("ptrace: POKEUSR reg %li with %li = %i\n", addr, data, ret); 369 break; 370 371 case PTRACE_GETREGS: 372 pr_debug("ptrace: PTRACE_GETREGS\n"); 373 return copy_regset_to_user(child, &user_bfin_native_view, 374 REGSET_GENERAL, 375 0, sizeof(struct pt_regs), 376 datap); 377 378 case PTRACE_SETREGS: 379 pr_debug("ptrace: PTRACE_SETREGS\n"); 380 return copy_regset_from_user(child, &user_bfin_native_view, 381 REGSET_GENERAL, 382 0, sizeof(struct pt_regs), 383 datap); 384 385 case_default: 386 default: 387 ret = ptrace_request(child, request, addr, data); 388 break; 389 } 390 391 return ret; 392} 393 394asmlinkage int syscall_trace_enter(struct pt_regs *regs) 395{ 396 int ret = 0; 397 398 if (test_thread_flag(TIF_SYSCALL_TRACE)) 399 ret = tracehook_report_syscall_entry(regs); 400 401 return ret; 402} 403 404asmlinkage void syscall_trace_leave(struct pt_regs *regs) 405{ 406 int step; 407 408 step = test_thread_flag(TIF_SINGLESTEP); 409 if (step || test_thread_flag(TIF_SYSCALL_TRACE)) 410 tracehook_report_syscall_exit(regs, step); 411} 412