ptrace.c revision 592201a9f154cdd5db59304d1369e94d8b551803
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/arch/arm/kernel/ptrace.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * By Ross Biro 1/23/92 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * edited by Linus Torvalds 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ARM modifications Copyright (C) 2000 Russell King 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/smp.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/user.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/security.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 207ed20e1ad521b5f5df61bf6559ae60738e393741Jesper Juhl#include <linux/signal.h> 2133fa9b13285e76fb95d940120964562e4c7081c2Russell King#include <linux/uaccess.h> 22864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon#include <linux/perf_event.h> 23864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon#include <linux/hw_breakpoint.h> 245be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin#include <linux/regset.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/traps.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define REG_PC 15 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define REG_PSR 16 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does not yet catch signals sent when the child dies. 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in exit.c or in signal.c. 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Breakpoint SWI instruction: SWI &9F0001 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_ARM 0xef9f0001 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_THUMB 0xdf00 /* fill this in later */ 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * New breakpoints - use an undefined instruction. The ARM architecture 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reference manual guarantees that the following instruction space 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will produce an undefined instruction exception on all CPUs: 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ARM: xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Thumb: 1101 1110 xxxx xxxx 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_ARM 0xe7f001f0 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_THUMB 0xde01 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconstruct pt_regs_offset { 57e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon const char *name; 58e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon int offset; 59e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon}; 60e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 61e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon#define REG_OFFSET_NAME(r) \ 62e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon {.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)} 63e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon#define REG_OFFSET_END {.name = NULL, .offset = 0} 64e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 65e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconstatic const struct pt_regs_offset regoffset_table[] = { 66e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r0), 67e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r1), 68e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r2), 69e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r3), 70e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r4), 71e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r5), 72e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r6), 73e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r7), 74e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r8), 75e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r9), 76e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r10), 77e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(fp), 78e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(ip), 79e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(sp), 80e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(lr), 81e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(pc), 82e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(cpsr), 83e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(ORIG_r0), 84e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_END, 85e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon}; 86e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 87e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon/** 88e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_query_register_offset() - query register offset from its name 89e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @name: the name of a register 90e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * 91e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_query_register_offset() returns the offset of a register in struct 92e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * pt_regs from its name. If the name is invalid, this returns -EINVAL; 93e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon */ 94e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconint regs_query_register_offset(const char *name) 95e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon{ 96e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon const struct pt_regs_offset *roff; 97e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon for (roff = regoffset_table; roff->name != NULL; roff++) 98e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon if (!strcmp(roff->name, name)) 99e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return roff->offset; 100e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return -EINVAL; 101e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon} 102e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 103e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon/** 104e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_query_register_name() - query register name from its offset 105e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @offset: the offset of a register in struct pt_regs. 106e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * 107e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_query_register_name() returns the name of a register from its 108e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * offset in struct pt_regs. If the @offset is invalid, this returns NULL; 109e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon */ 110e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconconst char *regs_query_register_name(unsigned int offset) 111e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon{ 112e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon const struct pt_regs_offset *roff; 113e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon for (roff = regoffset_table; roff->name != NULL; roff++) 114e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon if (roff->offset == offset) 115e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return roff->name; 116e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return NULL; 117e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon} 118e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 119e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon/** 120e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_within_kernel_stack() - check the address in the stack 121e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @regs: pt_regs which contains kernel stack pointer. 122e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @addr: address which is checked. 123e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * 124e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). 125e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * If @addr is within the kernel stack, it returns true. If not, returns false. 126e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon */ 127e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconbool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) 128e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon{ 129e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return ((addr & ~(THREAD_SIZE - 1)) == 130e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))); 131e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon} 132e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 133e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon/** 134e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_get_kernel_stack_nth() - get Nth entry of the stack 135e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @regs: pt_regs which contains kernel stack pointer. 136e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @n: stack entry number. 137e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * 138e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which 139e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * is specified by @regs. If the @n th entry is NOT in the kernel stack, 140e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * this returns 0. 141e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon */ 142e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconunsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) 143e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon{ 144e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); 145e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon addr += n; 146e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon if (regs_within_kernel_stack(regs, (unsigned long)addr)) 147e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return *addr; 148e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon else 149e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return 0; 150e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon} 151e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine will get a word off of the processes privileged stack. 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the offset is how far from the base addr as stored in the THREAD. 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine assumes that all the privileged stacks are in our 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data space. 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline long get_user_reg(struct task_struct *task, int offset) 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 160815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro return task_pt_regs(task)->uregs[offset]; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine will put a word on the processes privileged stack. 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the offset is how far from the base addr as stored in the THREAD. 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine assumes that all the privileged stacks are in our 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data space. 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsput_user_reg(struct task_struct *task, int offset, long data) 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 172815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro struct pt_regs newregs, *regs = task_pt_regs(task); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -EINVAL; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newregs = *regs; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newregs.uregs[offset] = data; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (valid_user_regs(&newregs)) { 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->uregs[offset] = data; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by kernel/ptrace.c when detaching.. 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_disable(struct task_struct *child) 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 191425fc47adb5bb69f76285be77a09a3341a30799eWill Deacon /* Nothing to do. */ 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle hitting a breakpoint. 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_break(struct task_struct *tsk, struct pt_regs *regs) 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds siginfo_t info; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_signo = SIGTRAP; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_errno = 0; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_code = TRAP_BRKPT; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_addr = (void __user *)instruction_pointer(regs); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds force_sig_info(SIGTRAP, &info, tsk); 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int break_trap(struct pt_regs *regs, unsigned int instr) 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_break(current, regs); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct undef_hook arm_break_hook = { 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_mask = 0x0fffffff, 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_val = 0x07f001f0, 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_mask = PSR_T_BIT, 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_val = 0, 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fn = break_trap, 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct undef_hook thumb_break_hook = { 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_mask = 0xffff, 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_val = 0xde01, 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_mask = PSR_T_BIT, 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_val = PSR_T_BIT, 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fn = break_trap, 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitzstatic struct undef_hook thumb2_break_hook = { 232592201a9f154cdd5db59304d1369e94d8b551803Jon Medhurst .instr_mask = 0xffffffff, 233592201a9f154cdd5db59304d1369e94d8b551803Jon Medhurst .instr_val = 0xf7f0a000, 234d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz .cpsr_mask = PSR_T_BIT, 235d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz .cpsr_val = PSR_T_BIT, 236592201a9f154cdd5db59304d1369e94d8b551803Jon Medhurst .fn = break_trap, 237d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz}; 238d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ptrace_break_init(void) 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_undef_hook(&arm_break_hook); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_undef_hook(&thumb_break_hook); 243d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz register_undef_hook(&thumb2_break_hook); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscore_initcall(ptrace_break_init); 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read the word at offset "off" into the "struct user". We 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * actually access the pt_regs stored on the kernel stack. 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_read_user(struct task_struct *tsk, unsigned long off, 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long __user *ret) 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long tmp; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off & 3 || off >= sizeof(struct user)) 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = 0; 26268b7f7153fa58df710924fbb79722717d2d16094Paul Brook if (off == PT_TEXT_ADDR) 26368b7f7153fa58df710924fbb79722717d2d16094Paul Brook tmp = tsk->mm->start_code; 26468b7f7153fa58df710924fbb79722717d2d16094Paul Brook else if (off == PT_DATA_ADDR) 26568b7f7153fa58df710924fbb79722717d2d16094Paul Brook tmp = tsk->mm->start_data; 26668b7f7153fa58df710924fbb79722717d2d16094Paul Brook else if (off == PT_TEXT_END_ADDR) 26768b7f7153fa58df710924fbb79722717d2d16094Paul Brook tmp = tsk->mm->end_code; 26868b7f7153fa58df710924fbb79722717d2d16094Paul Brook else if (off < sizeof(struct pt_regs)) 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = get_user_reg(tsk, off >> 2); 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user(tmp, ret); 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write the word at offset "off" into "struct user". We 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * actually access the pt_regs stored on the kernel stack. 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_write_user(struct task_struct *tsk, unsigned long off, 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val) 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off & 3 || off >= sizeof(struct user)) 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off >= sizeof(struct pt_regs)) 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user_reg(tsk, off >> 2, val); 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IWMMXT 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get the child iWMMXt state. 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_getwmmxregs(struct task_struct *tsk, void __user *ufp) 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 297e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro struct thread_info *thread = task_thread_info(tsk); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT)) 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODATA; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwmmxt_task_disable(thread); /* force it to ram */ 302cdaabbd74b15296acf09215355a7f3b07b92b83eRussell King return copy_to_user(ufp, &thread->fpstate.iwmmxt, IWMMXT_SIZE) 303cdaabbd74b15296acf09215355a7f3b07b92b83eRussell King ? -EFAULT : 0; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the child iWMMXt state. 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_setwmmxregs(struct task_struct *tsk, void __user *ufp) 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 311e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro struct thread_info *thread = task_thread_info(tsk); 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT)) 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EACCES; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwmmxt_task_release(thread); /* force a reload */ 31617320a9644a45ccac51ce4ff4333276844abf72dRussell King return copy_from_user(&thread->fpstate.iwmmxt, ufp, IWMMXT_SIZE) 317cdaabbd74b15296acf09215355a7f3b07b92b83eRussell King ? -EFAULT : 0; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3225429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#ifdef CONFIG_CRUNCH 3235429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek/* 3245429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek * Get the child Crunch state. 3255429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek */ 3265429b060df6d556f396b78364ad017686015bc34Lennert Buytenhekstatic int ptrace_getcrunchregs(struct task_struct *tsk, void __user *ufp) 3275429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek{ 3285429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek struct thread_info *thread = task_thread_info(tsk); 3295429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 3305429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek crunch_task_disable(thread); /* force it to ram */ 3315429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek return copy_to_user(ufp, &thread->crunchstate, CRUNCH_SIZE) 3325429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek ? -EFAULT : 0; 3335429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek} 3345429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 3355429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek/* 3365429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek * Set the child Crunch state. 3375429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek */ 3385429b060df6d556f396b78364ad017686015bc34Lennert Buytenhekstatic int ptrace_setcrunchregs(struct task_struct *tsk, void __user *ufp) 3395429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek{ 3405429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek struct thread_info *thread = task_thread_info(tsk); 3415429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 3425429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek crunch_task_release(thread); /* force a reload */ 3435429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek return copy_from_user(&thread->crunchstate, ufp, CRUNCH_SIZE) 3445429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek ? -EFAULT : 0; 3455429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek} 3465429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#endif 3475429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 348864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon#ifdef CONFIG_HAVE_HW_BREAKPOINT 349864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon/* 350864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * Convert a virtual register number into an index for a thread_info 351864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * breakpoint array. Breakpoints are identified using positive numbers 352864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * whilst watchpoints are negative. The registers are laid out as pairs 353864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * of (address, control), each pair mapping to a unique hw_breakpoint struct. 354864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * Register 0 is reserved for describing resource information. 355864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon */ 356864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconstatic int ptrace_hbp_num_to_idx(long num) 357864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 358864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (num < 0) 359864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon num = (ARM_MAX_BRP << 1) - num; 360864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon return (num - 1) >> 1; 361864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 362864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 363864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon/* 364864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * Returns the virtual register number for the address of the 365864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * breakpoint at index idx. 366864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon */ 367864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconstatic long ptrace_hbp_idx_to_num(int idx) 368864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 369864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon long mid = ARM_MAX_BRP << 1; 370864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon long num = (idx << 1) + 1; 371864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon return num > mid ? mid - num : num; 372864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 373864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 374864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon/* 375864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * Handle hitting a HW-breakpoint. 376864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon */ 377864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconstatic void ptrace_hbptriggered(struct perf_event *bp, int unused, 378864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct perf_sample_data *data, 379864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct pt_regs *regs) 380864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 381864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp); 382864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon long num; 383864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon int i; 384864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon siginfo_t info; 385864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 386864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon for (i = 0; i < ARM_MAX_HBP_SLOTS; ++i) 387864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (current->thread.debug.hbp[i] == bp) 388864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon break; 389864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 390864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon num = (i == ARM_MAX_HBP_SLOTS) ? 0 : ptrace_hbp_idx_to_num(i); 391864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 392864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon info.si_signo = SIGTRAP; 393864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon info.si_errno = (int)num; 394864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon info.si_code = TRAP_HWBKPT; 395864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon info.si_addr = (void __user *)(bkpt->trigger); 396864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 397864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon force_sig_info(SIGTRAP, &info, current); 398864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 399864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 400864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon/* 401864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * Set ptrace breakpoint pointers to zero for this task. 402864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * This is required in order to prevent child processes from unregistering 403864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * breakpoints held by their parent. 404864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon */ 405864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconvoid clear_ptrace_hw_breakpoint(struct task_struct *tsk) 406864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 407864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon memset(tsk->thread.debug.hbp, 0, sizeof(tsk->thread.debug.hbp)); 408864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 409864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 410864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon/* 411864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * Unregister breakpoints from this task and reset the pointers in 412864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * the thread_struct. 413864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon */ 414864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconvoid flush_ptrace_hw_breakpoint(struct task_struct *tsk) 415864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 416864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon int i; 417864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct thread_struct *t = &tsk->thread; 418864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 419864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon for (i = 0; i < ARM_MAX_HBP_SLOTS; i++) { 420864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (t->debug.hbp[i]) { 421864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon unregister_hw_breakpoint(t->debug.hbp[i]); 422864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon t->debug.hbp[i] = NULL; 423864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 424864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 425864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 426864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 427864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconstatic u32 ptrace_get_hbp_resource_info(void) 428864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 429864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon u8 num_brps, num_wrps, debug_arch, wp_len; 430864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon u32 reg = 0; 431864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 432864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon num_brps = hw_breakpoint_slots(TYPE_INST); 433864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon num_wrps = hw_breakpoint_slots(TYPE_DATA); 434864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon debug_arch = arch_get_debug_arch(); 435864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon wp_len = arch_get_max_wp_len(); 436864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 437864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg |= debug_arch; 438864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg <<= 8; 439864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg |= wp_len; 440864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg <<= 8; 441864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg |= num_wrps; 442864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg <<= 8; 443864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg |= num_brps; 444864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 445864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon return reg; 446864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 447864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 448864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconstatic struct perf_event *ptrace_hbp_create(struct task_struct *tsk, int type) 449864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 450864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct perf_event_attr attr; 451864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 452864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ptrace_breakpoint_init(&attr); 453864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 454864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon /* Initialise fields to sane defaults. */ 455864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.bp_addr = 0; 456864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.bp_len = HW_BREAKPOINT_LEN_4; 457864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.bp_type = type; 458864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.disabled = 1; 459864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 460864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon return register_user_hw_breakpoint(&attr, ptrace_hbptriggered, tsk); 461864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 462864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 463864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconstatic int ptrace_gethbpregs(struct task_struct *tsk, long num, 464864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon unsigned long __user *data) 465864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 466864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon u32 reg; 467864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon int idx, ret = 0; 468864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct perf_event *bp; 469864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct arch_hw_breakpoint_ctrl arch_ctrl; 470864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 471864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (num == 0) { 472864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg = ptrace_get_hbp_resource_info(); 473864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } else { 474864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon idx = ptrace_hbp_num_to_idx(num); 475864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) { 476864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = -EINVAL; 477864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon goto out; 478864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 479864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 480864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon bp = tsk->thread.debug.hbp[idx]; 481864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (!bp) { 482864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg = 0; 483864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon goto put; 484864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 485864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 486864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon arch_ctrl = counter_arch_bp(bp)->ctrl; 487864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 488864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon /* 489864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * Fix up the len because we may have adjusted it 490864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * to compensate for an unaligned address. 491864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon */ 492864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon while (!(arch_ctrl.len & 0x1)) 493864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon arch_ctrl.len >>= 1; 494864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 495ba55d3db9bb59a52fe45dbc5d62776adbb289e54Will Deacon if (num & 0x1) 496864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg = bp->attr.bp_addr; 497ba55d3db9bb59a52fe45dbc5d62776adbb289e54Will Deacon else 498ba55d3db9bb59a52fe45dbc5d62776adbb289e54Will Deacon reg = encode_ctrl_reg(arch_ctrl); 499864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 500864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 501864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconput: 502864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (put_user(reg, data)) 503864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = -EFAULT; 504864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 505864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconout: 506864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon return ret; 507864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 508864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 509864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconstatic int ptrace_sethbpregs(struct task_struct *tsk, long num, 510864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon unsigned long __user *data) 511864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 512864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon int idx, gen_len, gen_type, implied_type, ret = 0; 513864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon u32 user_val; 514864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct perf_event *bp; 515864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct arch_hw_breakpoint_ctrl ctrl; 516864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct perf_event_attr attr; 517864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 518864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (num == 0) 519864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon goto out; 520864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon else if (num < 0) 521864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon implied_type = HW_BREAKPOINT_RW; 522864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon else 523864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon implied_type = HW_BREAKPOINT_X; 524864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 525864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon idx = ptrace_hbp_num_to_idx(num); 526864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) { 527864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = -EINVAL; 528864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon goto out; 529864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 530864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 531864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (get_user(user_val, data)) { 532864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = -EFAULT; 533864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon goto out; 534864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 535864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 536864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon bp = tsk->thread.debug.hbp[idx]; 537864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (!bp) { 538864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon bp = ptrace_hbp_create(tsk, implied_type); 539864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (IS_ERR(bp)) { 540864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = PTR_ERR(bp); 541864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon goto out; 542864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 543864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon tsk->thread.debug.hbp[idx] = bp; 544864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 545864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 546864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr = bp->attr; 547864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 548864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (num & 0x1) { 549864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon /* Address */ 550864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.bp_addr = user_val; 551864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } else { 552864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon /* Control */ 553864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon decode_ctrl_reg(user_val, &ctrl); 554864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = arch_bp_generic_fields(ctrl, &gen_len, &gen_type); 555864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (ret) 556864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon goto out; 557864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 558864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if ((gen_type & implied_type) != gen_type) { 559ce9b1b09520789223f72a9fefd5f0e329f8d89d0Will Deacon ret = -EINVAL; 560ce9b1b09520789223f72a9fefd5f0e329f8d89d0Will Deacon goto out; 561864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 562864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 563864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.bp_len = gen_len; 564864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.bp_type = gen_type; 565864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.disabled = !ctrl.enabled; 566864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 567864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 568864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = modify_user_hw_breakpoint(bp, &attr); 569864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconout: 570864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon return ret; 571864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 572864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon#endif 573864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 5745be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin/* regset get/set implementations */ 5755be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 5765be6f62b0059a3344437b4c2877152c58cb3fdebDave Martinstatic int gpr_get(struct task_struct *target, 5775be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin const struct user_regset *regset, 5785be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin unsigned int pos, unsigned int count, 5795be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin void *kbuf, void __user *ubuf) 5805be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin{ 5815be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin struct pt_regs *regs = task_pt_regs(target); 5825be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 5835be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 5845be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin regs, 5855be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 0, sizeof(*regs)); 5865be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin} 5875be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 5885be6f62b0059a3344437b4c2877152c58cb3fdebDave Martinstatic int gpr_set(struct task_struct *target, 5895be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin const struct user_regset *regset, 5905be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin unsigned int pos, unsigned int count, 5915be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin const void *kbuf, const void __user *ubuf) 5925be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin{ 5935be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin int ret; 5945be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin struct pt_regs newregs; 5955be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 5965be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 5975be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin &newregs, 5985be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 0, sizeof(newregs)); 5995be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin if (ret) 6005be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin return ret; 6015be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 6025be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin if (!valid_user_regs(&newregs)) 6035be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin return -EINVAL; 6045be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 6055be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin *task_pt_regs(target) = newregs; 6065be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin return 0; 6075be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin} 6085be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 6095be6f62b0059a3344437b4c2877152c58cb3fdebDave Martinstatic int fpa_get(struct task_struct *target, 6105be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin const struct user_regset *regset, 6115be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin unsigned int pos, unsigned int count, 6125be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin void *kbuf, void __user *ubuf) 6135be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin{ 6145be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 6155be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin &task_thread_info(target)->fpstate, 6165be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 0, sizeof(struct user_fp)); 6175be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin} 6185be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 6195be6f62b0059a3344437b4c2877152c58cb3fdebDave Martinstatic int fpa_set(struct task_struct *target, 6205be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin const struct user_regset *regset, 6215be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin unsigned int pos, unsigned int count, 6225be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin const void *kbuf, const void __user *ubuf) 6235be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin{ 6245be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin struct thread_info *thread = task_thread_info(target); 6255be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 6265be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin thread->used_cp[1] = thread->used_cp[2] = 1; 6275be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 6285be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 6295be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin &thread->fpstate, 6305be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 0, sizeof(struct user_fp)); 6315be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin} 6325be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 6335be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin#ifdef CONFIG_VFP 6345be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin/* 6355be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * VFP register get/set implementations. 6365be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * 6375be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * With respect to the kernel, struct user_fp is divided into three chunks: 6385be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * 16 or 32 real VFP registers (d0-d15 or d0-31) 6395be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * These are transferred to/from the real registers in the task's 6405be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * vfp_hard_struct. The number of registers depends on the kernel 6415be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * configuration. 6425be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * 6435be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * 16 or 0 fake VFP registers (d16-d31 or empty) 6445be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * i.e., the user_vfp structure has space for 32 registers even if 6455be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * the kernel doesn't have them all. 6465be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * 6475be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * vfp_get() reads this chunk as zero where applicable 6485be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * vfp_set() ignores this chunk 6495be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * 6505be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * 1 word for the FPSCR 6515be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * 6525be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * The bounds-checking logic built into user_regset_copyout and friends 6535be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * means that we can make a simple sequence of calls to map the relevant data 6545be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * to/from the specified slice of the user regset structure. 6555be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin */ 6565be6f62b0059a3344437b4c2877152c58cb3fdebDave Martinstatic int vfp_get(struct task_struct *target, 6575be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin const struct user_regset *regset, 6585be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin unsigned int pos, unsigned int count, 6595be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin void *kbuf, void __user *ubuf) 6605be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin{ 6615be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin int ret; 6625be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin struct thread_info *thread = task_thread_info(target); 6635be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin struct vfp_hard_struct const *vfp = &thread->vfpstate.hard; 6645be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs); 6655be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr); 6665be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 6675be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin vfp_sync_hwstate(thread); 6685be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 6695be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 6705be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin &vfp->fpregs, 6715be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin user_fpregs_offset, 6725be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin user_fpregs_offset + sizeof(vfp->fpregs)); 6735be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin if (ret) 6745be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin return ret; 6755be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 6765be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 6775be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin user_fpregs_offset + sizeof(vfp->fpregs), 6785be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin user_fpscr_offset); 6795be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin if (ret) 6805be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin return ret; 6815be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 6825be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 6835be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin &vfp->fpscr, 6845be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin user_fpscr_offset, 6855be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin user_fpscr_offset + sizeof(vfp->fpscr)); 6865be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin} 6875be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 6885be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin/* 6895be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * For vfp_set() a read-modify-write is done on the VFP registers, 6905be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * in order to avoid writing back a half-modified set of registers on 6915be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * failure. 6925be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin */ 6935be6f62b0059a3344437b4c2877152c58cb3fdebDave Martinstatic int vfp_set(struct task_struct *target, 6945be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin const struct user_regset *regset, 6955be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin unsigned int pos, unsigned int count, 6965be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin const void *kbuf, const void __user *ubuf) 6975be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin{ 6985be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin int ret; 6995be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin struct thread_info *thread = task_thread_info(target); 7005be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin struct vfp_hard_struct new_vfp = thread->vfpstate.hard; 7015be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs); 7025be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr); 7035be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 7045be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 7055be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin &new_vfp.fpregs, 7065be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin user_fpregs_offset, 7075be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin user_fpregs_offset + sizeof(new_vfp.fpregs)); 7085be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin if (ret) 7095be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin return ret; 7105be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 7115be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 7125be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin user_fpregs_offset + sizeof(new_vfp.fpregs), 7135be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin user_fpscr_offset); 7145be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin if (ret) 7155be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin return ret; 7165be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 7175be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 7185be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin &new_vfp.fpscr, 7195be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin user_fpscr_offset, 7205be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin user_fpscr_offset + sizeof(new_vfp.fpscr)); 7215be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin if (ret) 7225be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin return ret; 7235be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 7245be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin vfp_sync_hwstate(thread); 7255be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin thread->vfpstate.hard = new_vfp; 7265be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin vfp_flush_hwstate(thread); 7275be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 7285be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin return 0; 7295be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin} 7305be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin#endif /* CONFIG_VFP */ 7315be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 7325be6f62b0059a3344437b4c2877152c58cb3fdebDave Martinenum arm_regset { 7335be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin REGSET_GPR, 7345be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin REGSET_FPR, 7355be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin#ifdef CONFIG_VFP 7365be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin REGSET_VFP, 7375be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin#endif 7385be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin}; 7395be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 7405be6f62b0059a3344437b4c2877152c58cb3fdebDave Martinstatic const struct user_regset arm_regsets[] = { 7415be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin [REGSET_GPR] = { 7425be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .core_note_type = NT_PRSTATUS, 7435be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .n = ELF_NGREG, 7445be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .size = sizeof(u32), 7455be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .align = sizeof(u32), 7465be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .get = gpr_get, 7475be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .set = gpr_set 7485be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin }, 7495be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin [REGSET_FPR] = { 7505be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin /* 7515be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * For the FPA regs in fpstate, the real fields are a mixture 7525be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * of sizes, so pretend that the registers are word-sized: 7535be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin */ 7545be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .core_note_type = NT_PRFPREG, 7555be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .n = sizeof(struct user_fp) / sizeof(u32), 7565be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .size = sizeof(u32), 7575be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .align = sizeof(u32), 7585be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .get = fpa_get, 7595be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .set = fpa_set 7605be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin }, 7615be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin#ifdef CONFIG_VFP 7625be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin [REGSET_VFP] = { 7635be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin /* 7645be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * Pretend that the VFP regs are word-sized, since the FPSCR is 7655be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin * a single word dangling at the end of struct user_vfp: 7665be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin */ 7675be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .core_note_type = NT_ARM_VFP, 7685be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .n = ARM_VFPREGS_SIZE / sizeof(u32), 7695be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .size = sizeof(u32), 7705be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .align = sizeof(u32), 7715be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .get = vfp_get, 7725be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .set = vfp_set 7735be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin }, 7745be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin#endif /* CONFIG_VFP */ 7755be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin}; 7765be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 7775be6f62b0059a3344437b4c2877152c58cb3fdebDave Martinstatic const struct user_regset_view user_arm_view = { 7785be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .name = "arm", .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI, 7795be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin .regsets = arm_regsets, .n = ARRAY_SIZE(arm_regsets) 7805be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin}; 7815be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 7825be6f62b0059a3344437b4c2877152c58cb3fdebDave Martinconst struct user_regset_view *task_user_regset_view(struct task_struct *task) 7835be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin{ 7845be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin return &user_arm_view; 7855be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin} 7865be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 7879b05a69e0534ec70bc94921936ffa05b330507cbNamhyung Kimlong arch_ptrace(struct task_struct *child, long request, 7889b05a69e0534ec70bc94921936ffa05b330507cbNamhyung Kim unsigned long addr, unsigned long data) 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 791b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim unsigned long __user *datap = (unsigned long __user *) data; 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (request) { 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_PEEKUSR: 795b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_read_user(child, addr, datap); 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_POKEUSR: 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_write_user(child, addr, data); 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GETREGS: 8035be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin ret = copy_regset_to_user(child, 8045be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin &user_arm_view, REGSET_GPR, 8055be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 0, sizeof(struct pt_regs), 8065be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin datap); 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SETREGS: 8105be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin ret = copy_regset_from_user(child, 8115be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin &user_arm_view, REGSET_GPR, 8125be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 0, sizeof(struct pt_regs), 8135be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin datap); 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GETFPREGS: 8175be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin ret = copy_regset_to_user(child, 8185be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin &user_arm_view, REGSET_FPR, 8195be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 0, sizeof(union fp_state), 8205be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin datap); 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8225be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SETFPREGS: 8245be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin ret = copy_regset_from_user(child, 8255be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin &user_arm_view, REGSET_FPR, 8265be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 0, sizeof(union fp_state), 8275be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin datap); 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IWMMXT 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GETWMMXREGS: 832b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_getwmmxregs(child, datap); 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SETWMMXREGS: 836b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_setwmmxregs(child, datap); 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GET_THREAD_AREA: 841e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro ret = put_user(task_thread_info(child)->tp_value, 842b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim datap); 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8453f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre case PTRACE_SET_SYSCALL: 8465ba6d3febd4978f31b2c523d64d381603923a709Russell King task_thread_info(child)->syscall = data; 8473f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre ret = 0; 8483f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre break; 8493f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre 8505429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#ifdef CONFIG_CRUNCH 8515429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek case PTRACE_GETCRUNCHREGS: 852b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_getcrunchregs(child, datap); 8535429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek break; 8545429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 8555429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek case PTRACE_SETCRUNCHREGS: 856b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_setcrunchregs(child, datap); 8575429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek break; 8585429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#endif 8595429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 8603d1228ead618b88e8606015cbabc49019981805dCatalin Marinas#ifdef CONFIG_VFP 8613d1228ead618b88e8606015cbabc49019981805dCatalin Marinas case PTRACE_GETVFPREGS: 8625be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin ret = copy_regset_to_user(child, 8635be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin &user_arm_view, REGSET_VFP, 8645be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 0, ARM_VFPREGS_SIZE, 8655be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin datap); 8663d1228ead618b88e8606015cbabc49019981805dCatalin Marinas break; 8673d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 8683d1228ead618b88e8606015cbabc49019981805dCatalin Marinas case PTRACE_SETVFPREGS: 8695be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin ret = copy_regset_from_user(child, 8705be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin &user_arm_view, REGSET_VFP, 8715be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin 0, ARM_VFPREGS_SIZE, 8725be6f62b0059a3344437b4c2877152c58cb3fdebDave Martin datap); 8733d1228ead618b88e8606015cbabc49019981805dCatalin Marinas break; 8743d1228ead618b88e8606015cbabc49019981805dCatalin Marinas#endif 8753d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 876864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon#ifdef CONFIG_HAVE_HW_BREAKPOINT 877864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon case PTRACE_GETHBPREGS: 878bf0b8f4b55e591ba417c2dbaff42769e1fc773b0Frederic Weisbecker if (ptrace_get_breakpoints(child) < 0) 879bf0b8f4b55e591ba417c2dbaff42769e1fc773b0Frederic Weisbecker return -ESRCH; 880bf0b8f4b55e591ba417c2dbaff42769e1fc773b0Frederic Weisbecker 881864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = ptrace_gethbpregs(child, addr, 882864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon (unsigned long __user *)data); 883bf0b8f4b55e591ba417c2dbaff42769e1fc773b0Frederic Weisbecker ptrace_put_breakpoints(child); 884864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon break; 885864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon case PTRACE_SETHBPREGS: 886bf0b8f4b55e591ba417c2dbaff42769e1fc773b0Frederic Weisbecker if (ptrace_get_breakpoints(child) < 0) 887bf0b8f4b55e591ba417c2dbaff42769e1fc773b0Frederic Weisbecker return -ESRCH; 888bf0b8f4b55e591ba417c2dbaff42769e1fc773b0Frederic Weisbecker 889864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = ptrace_sethbpregs(child, addr, 890864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon (unsigned long __user *)data); 891bf0b8f4b55e591ba417c2dbaff42769e1fc773b0Frederic Weisbecker ptrace_put_breakpoints(child); 892864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon break; 893864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon#endif 894864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_request(child, request, addr, data); 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9033f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitreasmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long ip; 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_thread_flag(TIF_SYSCALL_TRACE)) 9083f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre return scno; 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(current->ptrace & PT_PTRACED)) 9103f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre return scno; 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Save IP. IP is used to denote syscall entry/exit: 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IP = 0 -> entry, = 1 -> exit 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip = regs->ARM_ip; 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->ARM_ip = why; 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9195ba6d3febd4978f31b2c523d64d381603923a709Russell King current_thread_info()->syscall = scno; 9203f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* the 0x80 provides a way for the tracing parent to distinguish 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds between a syscall stop and SIGTRAP delivery */ 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? 0x80 : 0)); 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this isn't the same as continuing with a signal, but it will do 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for normal use. strace only continues with a signal if the 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stopping signal is not SIGTRAP. -brl 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (current->exit_code) { 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_sig(current->exit_code, current, 1); 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current->exit_code = 0; 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->ARM_ip = ip; 9353f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre 9365ba6d3febd4978f31b2c523d64d381603923a709Russell King return current_thread_info()->syscall; 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 938