ptrace.c revision e513f8bf240d34bd6e732ba2f74df9ab84686ce6
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> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/traps.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ptrace.h" 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define REG_PC 15 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define REG_PSR 16 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does not yet catch signals sent when the child dies. 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in exit.c or in signal.c. 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Breakpoint SWI instruction: SWI &9F0001 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_ARM 0xef9f0001 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_THUMB 0xdf00 /* fill this in later */ 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * New breakpoints - use an undefined instruction. The ARM architecture 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reference manual guarantees that the following instruction space 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will produce an undefined instruction exception on all CPUs: 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ARM: xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Thumb: 1101 1110 xxxx xxxx 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_ARM 0xe7f001f0 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_THUMB 0xde01 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconstruct pt_regs_offset { 56e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon const char *name; 57e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon int offset; 58e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon}; 59e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 60e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon#define REG_OFFSET_NAME(r) \ 61e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon {.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)} 62e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon#define REG_OFFSET_END {.name = NULL, .offset = 0} 63e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 64e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconstatic const struct pt_regs_offset regoffset_table[] = { 65e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r0), 66e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r1), 67e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r2), 68e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r3), 69e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r4), 70e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r5), 71e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r6), 72e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r7), 73e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r8), 74e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r9), 75e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r10), 76e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(fp), 77e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(ip), 78e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(sp), 79e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(lr), 80e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(pc), 81e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(cpsr), 82e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(ORIG_r0), 83e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_END, 84e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon}; 85e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 86e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon/** 87e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_query_register_offset() - query register offset from its name 88e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @name: the name of a register 89e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * 90e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_query_register_offset() returns the offset of a register in struct 91e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * pt_regs from its name. If the name is invalid, this returns -EINVAL; 92e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon */ 93e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconint regs_query_register_offset(const char *name) 94e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon{ 95e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon const struct pt_regs_offset *roff; 96e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon for (roff = regoffset_table; roff->name != NULL; roff++) 97e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon if (!strcmp(roff->name, name)) 98e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return roff->offset; 99e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return -EINVAL; 100e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon} 101e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 102e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon/** 103e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_query_register_name() - query register name from its offset 104e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @offset: the offset of a register in struct pt_regs. 105e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * 106e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_query_register_name() returns the name of a register from its 107e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * offset in struct pt_regs. If the @offset is invalid, this returns NULL; 108e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon */ 109e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconconst char *regs_query_register_name(unsigned int offset) 110e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon{ 111e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon const struct pt_regs_offset *roff; 112e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon for (roff = regoffset_table; roff->name != NULL; roff++) 113e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon if (roff->offset == offset) 114e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return roff->name; 115e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return NULL; 116e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon} 117e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 118e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon/** 119e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_within_kernel_stack() - check the address in the stack 120e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @regs: pt_regs which contains kernel stack pointer. 121e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @addr: address which is checked. 122e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * 123e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). 124e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * If @addr is within the kernel stack, it returns true. If not, returns false. 125e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon */ 126e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconbool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) 127e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon{ 128e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return ((addr & ~(THREAD_SIZE - 1)) == 129e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))); 130e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon} 131e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 132e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon/** 133e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_get_kernel_stack_nth() - get Nth entry of the stack 134e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @regs: pt_regs which contains kernel stack pointer. 135e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @n: stack entry number. 136e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * 137e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which 138e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * is specified by @regs. If the @n th entry is NOT in the kernel stack, 139e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * this returns 0. 140e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon */ 141e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconunsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) 142e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon{ 143e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); 144e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon addr += n; 145e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon if (regs_within_kernel_stack(regs, (unsigned long)addr)) 146e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return *addr; 147e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon else 148e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return 0; 149e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon} 150e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine will get a word off of the processes privileged stack. 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the offset is how far from the base addr as stored in the THREAD. 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine assumes that all the privileged stacks are in our 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data space. 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline long get_user_reg(struct task_struct *task, int offset) 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 159815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro return task_pt_regs(task)->uregs[offset]; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine will put a word on the processes privileged stack. 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the offset is how far from the base addr as stored in the THREAD. 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine assumes that all the privileged stacks are in our 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data space. 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsput_user_reg(struct task_struct *task, int offset, long data) 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 171815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro struct pt_regs newregs, *regs = task_pt_regs(task); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -EINVAL; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newregs = *regs; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newregs.uregs[offset] = data; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (valid_user_regs(&newregs)) { 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->uregs[offset] = data; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsread_u32(struct task_struct *task, unsigned long addr, u32 *res) 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr, res, sizeof(*res), 0); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret == sizeof(*res) ? 0 : -EIO; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsread_instr(struct task_struct *task, unsigned long addr, u32 *res) 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (addr & 1) { 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 val; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr & ~1, &val, sizeof(val), 0); 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ret == sizeof(val) ? 0 : -EIO; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *res = val; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr & ~3, &val, sizeof(val), 0); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ret == sizeof(val) ? 0 : -EIO; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *res = val; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get value of register `rn' (in the instruction) 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsptrace_getrn(struct task_struct *child, unsigned long insn) 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int reg = (insn >> 16) & 15; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = get_user_reg(child, reg); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reg == 15) 2251de765c1e940e23d83ec57035769e8af003f8796Russell King val += 8; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get value of operand 2 (in an ALU instruction) 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsptrace_getaluop2(struct task_struct *child, unsigned long insn) 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int shift; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int type; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 1 << 25) { 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = insn & 255; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (insn >> 8) & 15; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = 3; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = get_user_reg (child, insn & 15); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & (1 << 4)) 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (int)get_user_reg (child, (insn >> 8) & 15); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (insn >> 7) & 31; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = (insn >> 5) & 3; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: val <<= shift; break; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: val >>= shift; break; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (((signed long)val) >> shift); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (val >> shift) | (val << (32 - shift)); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get value of operand 2 (in a LDR instruction) 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsptrace_getldrop2(struct task_struct *child, unsigned long insn) 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int shift; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int type; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = get_user_reg(child, insn & 15); 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (insn >> 7) & 31; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = (insn >> 5) & 3; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: val <<= shift; break; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: val >>= shift; break; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (((signed long)val) >> shift); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (val >> shift) | (val << (32 - shift)); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_MASK 0x01e00000 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_AND 0x00000000 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_EOR 0x00200000 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_SUB 0x00400000 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_RSB 0x00600000 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_ADD 0x00800000 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_ADC 0x00a00000 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_SBC 0x00c00000 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_RSC 0x00e00000 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_ORR 0x01800000 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_MOV 0x01a00000 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_BIC 0x01c00000 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_MVN 0x01e00000 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsget_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn) 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 alt = 0; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (insn & 0x0e000000) { 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x00000000: 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x02000000: { 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data processing 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long aluop1, aluop2, ccbit; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32222f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev if ((insn & 0x0fffffd0) == 0x012fff10) { 32322f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev /* 32422f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev * bx or blx 32522f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev */ 32622f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev alt = get_user_reg(child, insn & 15); 32722f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev break; 32822f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev } 32922f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev 33022f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((insn & 0xf000) != 0xf000) 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop1 = ptrace_getrn(child, insn); 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop2 = ptrace_getaluop2(child, insn); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccbit = get_user_reg(child, REG_PSR) & PSR_C_BIT ? 1 : 0; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (insn & OP_MASK) { 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_AND: alt = aluop1 & aluop2; break; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_EOR: alt = aluop1 ^ aluop2; break; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_SUB: alt = aluop1 - aluop2; break; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_RSB: alt = aluop2 - aluop1; break; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_ADD: alt = aluop1 + aluop2; break; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_ADC: alt = aluop1 + aluop2 + ccbit; break; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_SBC: alt = aluop1 - aluop2 + ccbit; break; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_RSC: alt = aluop2 - aluop1 + ccbit; break; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_ORR: alt = aluop1 | aluop2; break; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_MOV: alt = aluop2; break; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_BIC: alt = aluop1 & ~aluop2; break; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_MVN: alt = ~aluop2; break; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x04000000: 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x06000000: 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ldr 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((insn & 0x0010f000) == 0x0010f000) { 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long base; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base = ptrace_getrn(child, insn); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 1 << 24) { 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long aluop2; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 0x02000000) 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop2 = ptrace_getldrop2(child, insn); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop2 = insn & 0xfff; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 1 << 23) 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base += aluop2; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base -= aluop2; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3771de765c1e940e23d83ec57035769e8af003f8796Russell King read_u32(child, base, &alt); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x08000000: 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ldm 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((insn & 0x00108000) == 0x00108000) { 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long base; 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int nr_regs; 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & (1 << 23)) { 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs = hweight16(insn & 65535) << 2; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(insn & (1 << 24))) 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs -= 4; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & (1 << 24)) 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs = -4; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs = 0; 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base = ptrace_getrn(child, insn); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4031de765c1e940e23d83ec57035769e8af003f8796Russell King read_u32(child, base + nr_regs, &alt); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x0a000000: { 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bl or b 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds signed long displ; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* It's a branch/branch link: instead of trying to 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * figure out whether the branch will be taken or not, 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we'll put a breakpoint at both locations. This is 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * simpler, more reliable, and probably not a whole lot 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slower than the alternative approach of emulating the 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * branch. 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds displ = (insn & 0x00ffffff) << 8; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds displ = (displ >> 6) + 8; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (displ != 0 && displ != 4) 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alt = pc + displ; 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return alt; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsswap_insn(struct task_struct *task, unsigned long addr, 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *old_insn, void *new_insn, int size) 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr, old_insn, size, 0); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret == size) 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr, new_insn, size, 1); 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsadd_breakpoint(struct task_struct *task, struct debug_info *dbg, unsigned long addr) 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int nr = dbg->nsaved; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nr < 2) { 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 new_insn = BREAKINST_ARM; 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = swap_insn(task, addr, &dbg->bp[nr].insn, &new_insn, 4); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res == 4) { 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg->bp[nr].address = addr; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg->nsaved += 1; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "ptrace: too many breakpoints\n"); 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear one breakpoint in the user program. We copy what the hardware 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does and use bit 0 of the address to indicate whether this is a Thumb 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * breakpoint or an ARM breakpoint. 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void clear_breakpoint(struct task_struct *task, struct debug_entry *bp) 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long addr = bp->address; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union debug_insn old_insn; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (addr & 1) { 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = swap_insn(task, addr & ~1, &old_insn.thumb, 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bp->insn.thumb, 2); 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != 2 || old_insn.thumb != BREAKINST_THUMB) 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s:%d: corrupted Thumb breakpoint at " 47919c5870c0eefd27c6d09d867465e0571262e05d0Alexey Dobriyan "0x%08lx (0x%04x)\n", task->comm, 48019c5870c0eefd27c6d09d867465e0571262e05d0Alexey Dobriyan task_pid_nr(task), addr, old_insn.thumb); 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = swap_insn(task, addr & ~3, &old_insn.arm, 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bp->insn.arm, 4); 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != 4 || old_insn.arm != BREAKINST_ARM) 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s:%d: corrupted ARM breakpoint at " 48719c5870c0eefd27c6d09d867465e0571262e05d0Alexey Dobriyan "0x%08lx (0x%08x)\n", task->comm, 48819c5870c0eefd27c6d09d867465e0571262e05d0Alexey Dobriyan task_pid_nr(task), addr, old_insn.arm); 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_set_bpt(struct task_struct *child) 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pt_regs *regs; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long pc; 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 insn; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 499815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro regs = task_pt_regs(child); 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc = instruction_pointer(regs); 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (thumb_mode(regs)) { 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "ptrace: can't handle thumb mode\n"); 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = read_instr(child, pc, &insn); 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) { 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct debug_info *dbg = &child->thread.debug; 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long alt; 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg->nsaved = 0; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alt = get_branch_address(child, pc, insn); 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (alt) 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_breakpoint(child, dbg, alt); 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that we ignore the result of setting the above 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * breakpoint since it may fail. When it does, this is 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not so much an error, but a forewarning that we may 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be receiving a prefetch abort shortly. 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we don't set this breakpoint here, then we can 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lose control of the thread during single stepping. 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!alt || predicate(insn) != PREDICATE_ALWAYS) 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_breakpoint(child, dbg, pc + 4); 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ensure no single-step breakpoint is pending. Returns non-zero 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * value if child was being single-stepped. 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_cancel_bpt(struct task_struct *child) 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, nsaved = child->thread.debug.nsaved; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child->thread.debug.nsaved = 0; 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nsaved > 2) { 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nsaved = 2; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < nsaved; i++) 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_breakpoint(child, &child->thread.debug.bp[i]); 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwigvoid user_disable_single_step(struct task_struct *task) 552440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig{ 553440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig task->ptrace &= ~PT_SINGLESTEP; 554440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig ptrace_cancel_bpt(task); 555440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig} 556440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig 557440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwigvoid user_enable_single_step(struct task_struct *task) 558440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig{ 559440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig task->ptrace |= PT_SINGLESTEP; 560440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig} 561440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by kernel/ptrace.c when detaching.. 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_disable(struct task_struct *child) 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 567440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig user_disable_single_step(child); 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle hitting a breakpoint. 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_break(struct task_struct *tsk, struct pt_regs *regs) 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds siginfo_t info; 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_cancel_bpt(tsk); 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_signo = SIGTRAP; 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_errno = 0; 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_code = TRAP_BRKPT; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_addr = (void __user *)instruction_pointer(regs); 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds force_sig_info(SIGTRAP, &info, tsk); 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int break_trap(struct pt_regs *regs, unsigned int instr) 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_break(current, regs); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct undef_hook arm_break_hook = { 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_mask = 0x0fffffff, 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_val = 0x07f001f0, 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_mask = PSR_T_BIT, 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_val = 0, 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fn = break_trap, 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct undef_hook thumb_break_hook = { 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_mask = 0xffff, 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_val = 0xde01, 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_mask = PSR_T_BIT, 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_val = PSR_T_BIT, 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fn = break_trap, 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 609d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitzstatic int thumb2_break_trap(struct pt_regs *regs, unsigned int instr) 610d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz{ 611d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz unsigned int instr2; 612d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz void __user *pc; 613d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz 614d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz /* Check the second half of the instruction. */ 615d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz pc = (void __user *)(instruction_pointer(regs) + 2); 616d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz 617d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz if (processor_mode(regs) == SVC_MODE) { 618d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz instr2 = *(u16 *) pc; 619d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz } else { 620d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz get_user(instr2, (u16 __user *)pc); 621d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz } 622d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz 623d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz if (instr2 == 0xa000) { 624d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz ptrace_break(current, regs); 625d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz return 0; 626d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz } else { 627d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz return 1; 628d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz } 629d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz} 630d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz 631d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitzstatic struct undef_hook thumb2_break_hook = { 632d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz .instr_mask = 0xffff, 633d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz .instr_val = 0xf7f0, 634d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz .cpsr_mask = PSR_T_BIT, 635d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz .cpsr_val = PSR_T_BIT, 636d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz .fn = thumb2_break_trap, 637d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz}; 638d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ptrace_break_init(void) 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_undef_hook(&arm_break_hook); 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_undef_hook(&thumb_break_hook); 643d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz register_undef_hook(&thumb2_break_hook); 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscore_initcall(ptrace_break_init); 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read the word at offset "off" into the "struct user". We 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * actually access the pt_regs stored on the kernel stack. 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_read_user(struct task_struct *tsk, unsigned long off, 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long __user *ret) 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long tmp; 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off & 3 || off >= sizeof(struct user)) 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = 0; 66268b7f7153fa58df710924fbb79722717d2d16094Paul Brook if (off == PT_TEXT_ADDR) 66368b7f7153fa58df710924fbb79722717d2d16094Paul Brook tmp = tsk->mm->start_code; 66468b7f7153fa58df710924fbb79722717d2d16094Paul Brook else if (off == PT_DATA_ADDR) 66568b7f7153fa58df710924fbb79722717d2d16094Paul Brook tmp = tsk->mm->start_data; 66668b7f7153fa58df710924fbb79722717d2d16094Paul Brook else if (off == PT_TEXT_END_ADDR) 66768b7f7153fa58df710924fbb79722717d2d16094Paul Brook tmp = tsk->mm->end_code; 66868b7f7153fa58df710924fbb79722717d2d16094Paul Brook else if (off < sizeof(struct pt_regs)) 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = get_user_reg(tsk, off >> 2); 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user(tmp, ret); 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write the word at offset "off" into "struct user". We 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * actually access the pt_regs stored on the kernel stack. 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_write_user(struct task_struct *tsk, unsigned long off, 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val) 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off & 3 || off >= sizeof(struct user)) 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off >= sizeof(struct pt_regs)) 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user_reg(tsk, off >> 2, val); 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get all user integer registers. 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_getregs(struct task_struct *tsk, void __user *uregs) 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 695815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro struct pt_regs *regs = task_pt_regs(tsk); 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set all user integer registers. 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_setregs(struct task_struct *tsk, void __user *uregs) 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pt_regs newregs; 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EFAULT; 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) { 710815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro struct pt_regs *regs = task_pt_regs(tsk); 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (valid_user_regs(&newregs)) { 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *regs = newregs; 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get the child FPU state. 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_getfpregs(struct task_struct *tsk, void __user *ufp) 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 727e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro return copy_to_user(ufp, &task_thread_info(tsk)->fpstate, 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct user_fp)) ? -EFAULT : 0; 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the child FPU state. 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_setfpregs(struct task_struct *tsk, void __user *ufp) 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 736e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro struct thread_info *thread = task_thread_info(tsk); 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds thread->used_cp[1] = thread->used_cp[2] = 1; 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return copy_from_user(&thread->fpstate, ufp, 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct user_fp)) ? -EFAULT : 0; 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IWMMXT 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get the child iWMMXt state. 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_getwmmxregs(struct task_struct *tsk, void __user *ufp) 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 749e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro struct thread_info *thread = task_thread_info(tsk); 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT)) 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODATA; 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwmmxt_task_disable(thread); /* force it to ram */ 754cdaabbd74b15296acf09215355a7f3b07b92b83eRussell King return copy_to_user(ufp, &thread->fpstate.iwmmxt, IWMMXT_SIZE) 755cdaabbd74b15296acf09215355a7f3b07b92b83eRussell King ? -EFAULT : 0; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the child iWMMXt state. 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_setwmmxregs(struct task_struct *tsk, void __user *ufp) 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 763e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro struct thread_info *thread = task_thread_info(tsk); 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT)) 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EACCES; 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwmmxt_task_release(thread); /* force a reload */ 76817320a9644a45ccac51ce4ff4333276844abf72dRussell King return copy_from_user(&thread->fpstate.iwmmxt, ufp, IWMMXT_SIZE) 769cdaabbd74b15296acf09215355a7f3b07b92b83eRussell King ? -EFAULT : 0; 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7745429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#ifdef CONFIG_CRUNCH 7755429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek/* 7765429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek * Get the child Crunch state. 7775429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek */ 7785429b060df6d556f396b78364ad017686015bc34Lennert Buytenhekstatic int ptrace_getcrunchregs(struct task_struct *tsk, void __user *ufp) 7795429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek{ 7805429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek struct thread_info *thread = task_thread_info(tsk); 7815429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 7825429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek crunch_task_disable(thread); /* force it to ram */ 7835429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek return copy_to_user(ufp, &thread->crunchstate, CRUNCH_SIZE) 7845429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek ? -EFAULT : 0; 7855429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek} 7865429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 7875429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek/* 7885429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek * Set the child Crunch state. 7895429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek */ 7905429b060df6d556f396b78364ad017686015bc34Lennert Buytenhekstatic int ptrace_setcrunchregs(struct task_struct *tsk, void __user *ufp) 7915429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek{ 7925429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek struct thread_info *thread = task_thread_info(tsk); 7935429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 7945429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek crunch_task_release(thread); /* force a reload */ 7955429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek return copy_from_user(&thread->crunchstate, ufp, CRUNCH_SIZE) 7965429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek ? -EFAULT : 0; 7975429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek} 7985429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#endif 7995429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 8003d1228ead618b88e8606015cbabc49019981805dCatalin Marinas#ifdef CONFIG_VFP 8013d1228ead618b88e8606015cbabc49019981805dCatalin Marinas/* 8023d1228ead618b88e8606015cbabc49019981805dCatalin Marinas * Get the child VFP state. 8033d1228ead618b88e8606015cbabc49019981805dCatalin Marinas */ 8043d1228ead618b88e8606015cbabc49019981805dCatalin Marinasstatic int ptrace_getvfpregs(struct task_struct *tsk, void __user *data) 8053d1228ead618b88e8606015cbabc49019981805dCatalin Marinas{ 8063d1228ead618b88e8606015cbabc49019981805dCatalin Marinas struct thread_info *thread = task_thread_info(tsk); 8073d1228ead618b88e8606015cbabc49019981805dCatalin Marinas union vfp_state *vfp = &thread->vfpstate; 8083d1228ead618b88e8606015cbabc49019981805dCatalin Marinas struct user_vfp __user *ufp = data; 8093d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 810ad187f956108e1c56b444706212bf08d84c0bee0Russell King vfp_sync_hwstate(thread); 8113d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 8123d1228ead618b88e8606015cbabc49019981805dCatalin Marinas /* copy the floating point registers */ 8133d1228ead618b88e8606015cbabc49019981805dCatalin Marinas if (copy_to_user(&ufp->fpregs, &vfp->hard.fpregs, 8143d1228ead618b88e8606015cbabc49019981805dCatalin Marinas sizeof(vfp->hard.fpregs))) 8153d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return -EFAULT; 8163d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 8173d1228ead618b88e8606015cbabc49019981805dCatalin Marinas /* copy the status and control register */ 8183d1228ead618b88e8606015cbabc49019981805dCatalin Marinas if (put_user(vfp->hard.fpscr, &ufp->fpscr)) 8193d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return -EFAULT; 8203d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 8213d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return 0; 8223d1228ead618b88e8606015cbabc49019981805dCatalin Marinas} 8233d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 8243d1228ead618b88e8606015cbabc49019981805dCatalin Marinas/* 8253d1228ead618b88e8606015cbabc49019981805dCatalin Marinas * Set the child VFP state. 8263d1228ead618b88e8606015cbabc49019981805dCatalin Marinas */ 8273d1228ead618b88e8606015cbabc49019981805dCatalin Marinasstatic int ptrace_setvfpregs(struct task_struct *tsk, void __user *data) 8283d1228ead618b88e8606015cbabc49019981805dCatalin Marinas{ 8293d1228ead618b88e8606015cbabc49019981805dCatalin Marinas struct thread_info *thread = task_thread_info(tsk); 8303d1228ead618b88e8606015cbabc49019981805dCatalin Marinas union vfp_state *vfp = &thread->vfpstate; 8313d1228ead618b88e8606015cbabc49019981805dCatalin Marinas struct user_vfp __user *ufp = data; 8323d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 833ad187f956108e1c56b444706212bf08d84c0bee0Russell King vfp_sync_hwstate(thread); 8343d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 8353d1228ead618b88e8606015cbabc49019981805dCatalin Marinas /* copy the floating point registers */ 8363d1228ead618b88e8606015cbabc49019981805dCatalin Marinas if (copy_from_user(&vfp->hard.fpregs, &ufp->fpregs, 8373d1228ead618b88e8606015cbabc49019981805dCatalin Marinas sizeof(vfp->hard.fpregs))) 8383d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return -EFAULT; 8393d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 8403d1228ead618b88e8606015cbabc49019981805dCatalin Marinas /* copy the status and control register */ 8413d1228ead618b88e8606015cbabc49019981805dCatalin Marinas if (get_user(vfp->hard.fpscr, &ufp->fpscr)) 8423d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return -EFAULT; 8433d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 844ad187f956108e1c56b444706212bf08d84c0bee0Russell King vfp_flush_hwstate(thread); 845ad187f956108e1c56b444706212bf08d84c0bee0Russell King 8463d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return 0; 8473d1228ead618b88e8606015cbabc49019981805dCatalin Marinas} 8483d1228ead618b88e8606015cbabc49019981805dCatalin Marinas#endif 8493d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 850481bed454247538e9f57d4ea37b153ccba24ba7bChristoph Hellwiglong arch_ptrace(struct task_struct *child, long request, long addr, long data) 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (request) { 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_PEEKUSR: 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_read_user(child, addr, (unsigned long __user *)data); 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_POKEUSR: 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_write_user(child, addr, data); 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GETREGS: 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_getregs(child, (void __user *)data); 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SETREGS: 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_setregs(child, (void __user *)data); 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GETFPREGS: 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_getfpregs(child, (void __user *)data); 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SETFPREGS: 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_setfpregs(child, (void __user *)data); 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IWMMXT 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GETWMMXREGS: 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_getwmmxregs(child, (void __user *)data); 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SETWMMXREGS: 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_setwmmxregs(child, (void __user *)data); 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GET_THREAD_AREA: 890e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro ret = put_user(task_thread_info(child)->tp_value, 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long __user *) data); 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8943f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre case PTRACE_SET_SYSCALL: 8955ba6d3febd4978f31b2c523d64d381603923a709Russell King task_thread_info(child)->syscall = data; 8963f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre ret = 0; 8973f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre break; 8983f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre 8995429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#ifdef CONFIG_CRUNCH 9005429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek case PTRACE_GETCRUNCHREGS: 9015429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek ret = ptrace_getcrunchregs(child, (void __user *)data); 9025429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek break; 9035429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 9045429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek case PTRACE_SETCRUNCHREGS: 9055429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek ret = ptrace_setcrunchregs(child, (void __user *)data); 9065429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek break; 9075429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#endif 9085429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 9093d1228ead618b88e8606015cbabc49019981805dCatalin Marinas#ifdef CONFIG_VFP 9103d1228ead618b88e8606015cbabc49019981805dCatalin Marinas case PTRACE_GETVFPREGS: 9113d1228ead618b88e8606015cbabc49019981805dCatalin Marinas ret = ptrace_getvfpregs(child, (void __user *)data); 9123d1228ead618b88e8606015cbabc49019981805dCatalin Marinas break; 9133d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 9143d1228ead618b88e8606015cbabc49019981805dCatalin Marinas case PTRACE_SETVFPREGS: 9153d1228ead618b88e8606015cbabc49019981805dCatalin Marinas ret = ptrace_setvfpregs(child, (void __user *)data); 9163d1228ead618b88e8606015cbabc49019981805dCatalin Marinas break; 9173d1228ead618b88e8606015cbabc49019981805dCatalin Marinas#endif 9183d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_request(child, request, addr, data); 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9273f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitreasmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long ip; 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_thread_flag(TIF_SYSCALL_TRACE)) 9323f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre return scno; 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(current->ptrace & PT_PTRACED)) 9343f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre return scno; 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Save IP. IP is used to denote syscall entry/exit: 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IP = 0 -> entry, = 1 -> exit 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip = regs->ARM_ip; 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->ARM_ip = why; 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9435ba6d3febd4978f31b2c523d64d381603923a709Russell King current_thread_info()->syscall = scno; 9443f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* the 0x80 provides a way for the tracing parent to distinguish 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds between a syscall stop and SIGTRAP delivery */ 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? 0x80 : 0)); 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this isn't the same as continuing with a signal, but it will do 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for normal use. strace only continues with a signal if the 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stopping signal is not SIGTRAP. -brl 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (current->exit_code) { 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_sig(current->exit_code, current, 1); 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current->exit_code = 0; 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->ARM_ip = ip; 9593f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre 9605ba6d3febd4978f31b2c523d64d381603923a709Russell King return current_thread_info()->syscall; 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 962