ptrace.c revision b640a0d192265c47bbf60951115bdb59d2c017d1
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> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/traps.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ptrace.h" 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define REG_PC 15 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define REG_PSR 16 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does not yet catch signals sent when the child dies. 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in exit.c or in signal.c. 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Breakpoint SWI instruction: SWI &9F0001 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_ARM 0xef9f0001 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_THUMB 0xdf00 /* fill this in later */ 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * New breakpoints - use an undefined instruction. The ARM architecture 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reference manual guarantees that the following instruction space 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will produce an undefined instruction exception on all CPUs: 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ARM: xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Thumb: 1101 1110 xxxx xxxx 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_ARM 0xe7f001f0 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_THUMB 0xde01 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconstruct pt_regs_offset { 58e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon const char *name; 59e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon int offset; 60e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon}; 61e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 62e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon#define REG_OFFSET_NAME(r) \ 63e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon {.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)} 64e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon#define REG_OFFSET_END {.name = NULL, .offset = 0} 65e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 66e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconstatic const struct pt_regs_offset regoffset_table[] = { 67e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r0), 68e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r1), 69e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r2), 70e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r3), 71e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r4), 72e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r5), 73e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r6), 74e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r7), 75e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r8), 76e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r9), 77e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(r10), 78e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(fp), 79e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(ip), 80e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(sp), 81e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(lr), 82e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(pc), 83e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(cpsr), 84e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_NAME(ORIG_r0), 85e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon REG_OFFSET_END, 86e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon}; 87e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 88e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon/** 89e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_query_register_offset() - query register offset from its name 90e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @name: the name of a register 91e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * 92e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_query_register_offset() returns the offset of a register in struct 93e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * pt_regs from its name. If the name is invalid, this returns -EINVAL; 94e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon */ 95e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconint regs_query_register_offset(const char *name) 96e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon{ 97e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon const struct pt_regs_offset *roff; 98e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon for (roff = regoffset_table; roff->name != NULL; roff++) 99e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon if (!strcmp(roff->name, name)) 100e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return roff->offset; 101e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return -EINVAL; 102e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon} 103e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 104e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon/** 105e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_query_register_name() - query register name from its offset 106e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @offset: the offset of a register in struct pt_regs. 107e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * 108e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_query_register_name() returns the name of a register from its 109e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * offset in struct pt_regs. If the @offset is invalid, this returns NULL; 110e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon */ 111e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconconst char *regs_query_register_name(unsigned int offset) 112e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon{ 113e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon const struct pt_regs_offset *roff; 114e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon for (roff = regoffset_table; roff->name != NULL; roff++) 115e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon if (roff->offset == offset) 116e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return roff->name; 117e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return NULL; 118e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon} 119e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 120e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon/** 121e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_within_kernel_stack() - check the address in the stack 122e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @regs: pt_regs which contains kernel stack pointer. 123e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @addr: address which is checked. 124e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * 125e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). 126e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * If @addr is within the kernel stack, it returns true. If not, returns false. 127e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon */ 128e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconbool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) 129e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon{ 130e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return ((addr & ~(THREAD_SIZE - 1)) == 131e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))); 132e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon} 133e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 134e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon/** 135e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_get_kernel_stack_nth() - get Nth entry of the stack 136e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @regs: pt_regs which contains kernel stack pointer. 137e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * @n: stack entry number. 138e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * 139e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which 140e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * is specified by @regs. If the @n th entry is NOT in the kernel stack, 141e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon * this returns 0. 142e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon */ 143e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deaconunsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) 144e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon{ 145e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); 146e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon addr += n; 147e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon if (regs_within_kernel_stack(regs, (unsigned long)addr)) 148e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return *addr; 149e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon else 150e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon return 0; 151e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon} 152e513f8bf240d34bd6e732ba2f74df9ab84686ce6Will Deacon 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine will get a word off of the processes privileged stack. 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the offset is how far from the base addr as stored in the THREAD. 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine assumes that all the privileged stacks are in our 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data space. 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline long get_user_reg(struct task_struct *task, int offset) 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 161815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro return task_pt_regs(task)->uregs[offset]; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine will put a word on the processes privileged stack. 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the offset is how far from the base addr as stored in the THREAD. 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine assumes that all the privileged stacks are in our 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data space. 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsput_user_reg(struct task_struct *task, int offset, long data) 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 173815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro struct pt_regs newregs, *regs = task_pt_regs(task); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -EINVAL; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newregs = *regs; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newregs.uregs[offset] = data; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (valid_user_regs(&newregs)) { 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->uregs[offset] = data; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsread_u32(struct task_struct *task, unsigned long addr, u32 *res) 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr, res, sizeof(*res), 0); 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret == sizeof(*res) ? 0 : -EIO; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsread_instr(struct task_struct *task, unsigned long addr, u32 *res) 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (addr & 1) { 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 val; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr & ~1, &val, sizeof(val), 0); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ret == sizeof(val) ? 0 : -EIO; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *res = val; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr & ~3, &val, sizeof(val), 0); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ret == sizeof(val) ? 0 : -EIO; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *res = val; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get value of register `rn' (in the instruction) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsptrace_getrn(struct task_struct *child, unsigned long insn) 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int reg = (insn >> 16) & 15; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = get_user_reg(child, reg); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reg == 15) 2271de765c1e940e23d83ec57035769e8af003f8796Russell King val += 8; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get value of operand 2 (in an ALU instruction) 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsptrace_getaluop2(struct task_struct *child, unsigned long insn) 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int shift; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int type; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 1 << 25) { 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = insn & 255; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (insn >> 8) & 15; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = 3; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = get_user_reg (child, insn & 15); 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & (1 << 4)) 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (int)get_user_reg (child, (insn >> 8) & 15); 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (insn >> 7) & 31; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = (insn >> 5) & 3; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: val <<= shift; break; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: val >>= shift; break; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (((signed long)val) >> shift); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (val >> shift) | (val << (32 - shift)); 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get value of operand 2 (in a LDR instruction) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsptrace_getldrop2(struct task_struct *child, unsigned long insn) 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int shift; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int type; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = get_user_reg(child, insn & 15); 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (insn >> 7) & 31; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = (insn >> 5) & 3; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: val <<= shift; break; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: val >>= shift; break; 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (((signed long)val) >> shift); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (val >> shift) | (val << (32 - shift)); 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_MASK 0x01e00000 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_AND 0x00000000 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_EOR 0x00200000 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_SUB 0x00400000 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_RSB 0x00600000 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_ADD 0x00800000 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_ADC 0x00a00000 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_SBC 0x00c00000 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_RSC 0x00e00000 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_ORR 0x01800000 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_MOV 0x01a00000 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_BIC 0x01c00000 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_MVN 0x01e00000 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsget_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn) 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 alt = 0; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (insn & 0x0e000000) { 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x00000000: 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x02000000: { 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data processing 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long aluop1, aluop2, ccbit; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32422f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev if ((insn & 0x0fffffd0) == 0x012fff10) { 32522f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev /* 32622f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev * bx or blx 32722f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev */ 32822f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev alt = get_user_reg(child, insn & 15); 32922f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev break; 33022f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev } 33122f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev 33222f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((insn & 0xf000) != 0xf000) 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop1 = ptrace_getrn(child, insn); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop2 = ptrace_getaluop2(child, insn); 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccbit = get_user_reg(child, REG_PSR) & PSR_C_BIT ? 1 : 0; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (insn & OP_MASK) { 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_AND: alt = aluop1 & aluop2; break; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_EOR: alt = aluop1 ^ aluop2; break; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_SUB: alt = aluop1 - aluop2; break; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_RSB: alt = aluop2 - aluop1; break; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_ADD: alt = aluop1 + aluop2; break; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_ADC: alt = aluop1 + aluop2 + ccbit; break; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_SBC: alt = aluop1 - aluop2 + ccbit; break; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_RSC: alt = aluop2 - aluop1 + ccbit; break; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_ORR: alt = aluop1 | aluop2; break; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_MOV: alt = aluop2; break; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_BIC: alt = aluop1 & ~aluop2; break; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_MVN: alt = ~aluop2; break; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x04000000: 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x06000000: 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ldr 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((insn & 0x0010f000) == 0x0010f000) { 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long base; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base = ptrace_getrn(child, insn); 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 1 << 24) { 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long aluop2; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 0x02000000) 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop2 = ptrace_getldrop2(child, insn); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop2 = insn & 0xfff; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 1 << 23) 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base += aluop2; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base -= aluop2; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3791de765c1e940e23d83ec57035769e8af003f8796Russell King read_u32(child, base, &alt); 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x08000000: 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ldm 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((insn & 0x00108000) == 0x00108000) { 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long base; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int nr_regs; 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & (1 << 23)) { 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs = hweight16(insn & 65535) << 2; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(insn & (1 << 24))) 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs -= 4; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & (1 << 24)) 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs = -4; 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs = 0; 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base = ptrace_getrn(child, insn); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4051de765c1e940e23d83ec57035769e8af003f8796Russell King read_u32(child, base + nr_regs, &alt); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x0a000000: { 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bl or b 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds signed long displ; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* It's a branch/branch link: instead of trying to 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * figure out whether the branch will be taken or not, 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we'll put a breakpoint at both locations. This is 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * simpler, more reliable, and probably not a whole lot 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slower than the alternative approach of emulating the 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * branch. 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds displ = (insn & 0x00ffffff) << 8; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds displ = (displ >> 6) + 8; 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (displ != 0 && displ != 4) 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alt = pc + displ; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return alt; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsswap_insn(struct task_struct *task, unsigned long addr, 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *old_insn, void *new_insn, int size) 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr, old_insn, size, 0); 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret == size) 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr, new_insn, size, 1); 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsadd_breakpoint(struct task_struct *task, struct debug_info *dbg, unsigned long addr) 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int nr = dbg->nsaved; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nr < 2) { 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 new_insn = BREAKINST_ARM; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = swap_insn(task, addr, &dbg->bp[nr].insn, &new_insn, 4); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res == 4) { 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg->bp[nr].address = addr; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg->nsaved += 1; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "ptrace: too many breakpoints\n"); 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear one breakpoint in the user program. We copy what the hardware 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does and use bit 0 of the address to indicate whether this is a Thumb 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * breakpoint or an ARM breakpoint. 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void clear_breakpoint(struct task_struct *task, struct debug_entry *bp) 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long addr = bp->address; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union debug_insn old_insn; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (addr & 1) { 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = swap_insn(task, addr & ~1, &old_insn.thumb, 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bp->insn.thumb, 2); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != 2 || old_insn.thumb != BREAKINST_THUMB) 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s:%d: corrupted Thumb breakpoint at " 48119c5870c0eefd27c6d09d867465e0571262e05d0Alexey Dobriyan "0x%08lx (0x%04x)\n", task->comm, 48219c5870c0eefd27c6d09d867465e0571262e05d0Alexey Dobriyan task_pid_nr(task), addr, old_insn.thumb); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = swap_insn(task, addr & ~3, &old_insn.arm, 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bp->insn.arm, 4); 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != 4 || old_insn.arm != BREAKINST_ARM) 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s:%d: corrupted ARM breakpoint at " 48919c5870c0eefd27c6d09d867465e0571262e05d0Alexey Dobriyan "0x%08lx (0x%08x)\n", task->comm, 49019c5870c0eefd27c6d09d867465e0571262e05d0Alexey Dobriyan task_pid_nr(task), addr, old_insn.arm); 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_set_bpt(struct task_struct *child) 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pt_regs *regs; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long pc; 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 insn; 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro regs = task_pt_regs(child); 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc = instruction_pointer(regs); 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (thumb_mode(regs)) { 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "ptrace: can't handle thumb mode\n"); 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = read_instr(child, pc, &insn); 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) { 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct debug_info *dbg = &child->thread.debug; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long alt; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg->nsaved = 0; 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alt = get_branch_address(child, pc, insn); 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (alt) 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_breakpoint(child, dbg, alt); 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that we ignore the result of setting the above 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * breakpoint since it may fail. When it does, this is 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not so much an error, but a forewarning that we may 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be receiving a prefetch abort shortly. 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we don't set this breakpoint here, then we can 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lose control of the thread during single stepping. 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!alt || predicate(insn) != PREDICATE_ALWAYS) 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_breakpoint(child, dbg, pc + 4); 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ensure no single-step breakpoint is pending. Returns non-zero 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * value if child was being single-stepped. 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_cancel_bpt(struct task_struct *child) 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, nsaved = child->thread.debug.nsaved; 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child->thread.debug.nsaved = 0; 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nsaved > 2) { 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nsaved = 2; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < nsaved; i++) 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_breakpoint(child, &child->thread.debug.bp[i]); 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 553440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwigvoid user_disable_single_step(struct task_struct *task) 554440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig{ 555440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig task->ptrace &= ~PT_SINGLESTEP; 556440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig ptrace_cancel_bpt(task); 557440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig} 558440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig 559440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwigvoid user_enable_single_step(struct task_struct *task) 560440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig{ 561440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig task->ptrace |= PT_SINGLESTEP; 562440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig} 563440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by kernel/ptrace.c when detaching.. 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_disable(struct task_struct *child) 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 569440e6ca79aebdc274ce4c625a6f42c8bf3c7bc91Christoph Hellwig user_disable_single_step(child); 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle hitting a breakpoint. 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_break(struct task_struct *tsk, struct pt_regs *regs) 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds siginfo_t info; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_cancel_bpt(tsk); 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_signo = SIGTRAP; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_errno = 0; 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_code = TRAP_BRKPT; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_addr = (void __user *)instruction_pointer(regs); 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds force_sig_info(SIGTRAP, &info, tsk); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int break_trap(struct pt_regs *regs, unsigned int instr) 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_break(current, regs); 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct undef_hook arm_break_hook = { 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_mask = 0x0fffffff, 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_val = 0x07f001f0, 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_mask = PSR_T_BIT, 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_val = 0, 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fn = break_trap, 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct undef_hook thumb_break_hook = { 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_mask = 0xffff, 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_val = 0xde01, 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_mask = PSR_T_BIT, 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_val = PSR_T_BIT, 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fn = break_trap, 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitzstatic int thumb2_break_trap(struct pt_regs *regs, unsigned int instr) 612d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz{ 613d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz unsigned int instr2; 614d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz void __user *pc; 615d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz 616d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz /* Check the second half of the instruction. */ 617d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz pc = (void __user *)(instruction_pointer(regs) + 2); 618d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz 619d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz if (processor_mode(regs) == SVC_MODE) { 620d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz instr2 = *(u16 *) pc; 621d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz } else { 622d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz get_user(instr2, (u16 __user *)pc); 623d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz } 624d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz 625d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz if (instr2 == 0xa000) { 626d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz ptrace_break(current, regs); 627d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz return 0; 628d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz } else { 629d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz return 1; 630d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz } 631d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz} 632d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz 633d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitzstatic struct undef_hook thumb2_break_hook = { 634d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz .instr_mask = 0xffff, 635d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz .instr_val = 0xf7f0, 636d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz .cpsr_mask = PSR_T_BIT, 637d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz .cpsr_val = PSR_T_BIT, 638d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz .fn = thumb2_break_trap, 639d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz}; 640d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ptrace_break_init(void) 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_undef_hook(&arm_break_hook); 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_undef_hook(&thumb_break_hook); 645d23bc1b3a7e6db935acb9a949a5985d9b77dfd13Daniel Jacobowitz register_undef_hook(&thumb2_break_hook); 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscore_initcall(ptrace_break_init); 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read the word at offset "off" into the "struct user". We 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * actually access the pt_regs stored on the kernel stack. 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_read_user(struct task_struct *tsk, unsigned long off, 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long __user *ret) 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long tmp; 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off & 3 || off >= sizeof(struct user)) 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = 0; 66468b7f7153fa58df710924fbb79722717d2d16094Paul Brook if (off == PT_TEXT_ADDR) 66568b7f7153fa58df710924fbb79722717d2d16094Paul Brook tmp = tsk->mm->start_code; 66668b7f7153fa58df710924fbb79722717d2d16094Paul Brook else if (off == PT_DATA_ADDR) 66768b7f7153fa58df710924fbb79722717d2d16094Paul Brook tmp = tsk->mm->start_data; 66868b7f7153fa58df710924fbb79722717d2d16094Paul Brook else if (off == PT_TEXT_END_ADDR) 66968b7f7153fa58df710924fbb79722717d2d16094Paul Brook tmp = tsk->mm->end_code; 67068b7f7153fa58df710924fbb79722717d2d16094Paul Brook else if (off < sizeof(struct pt_regs)) 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = get_user_reg(tsk, off >> 2); 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user(tmp, ret); 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write the word at offset "off" into "struct user". We 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * actually access the pt_regs stored on the kernel stack. 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_write_user(struct task_struct *tsk, unsigned long off, 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val) 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off & 3 || off >= sizeof(struct user)) 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off >= sizeof(struct pt_regs)) 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user_reg(tsk, off >> 2, val); 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get all user integer registers. 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_getregs(struct task_struct *tsk, void __user *uregs) 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 697815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro struct pt_regs *regs = task_pt_regs(tsk); 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set all user integer registers. 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_setregs(struct task_struct *tsk, void __user *uregs) 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pt_regs newregs; 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EFAULT; 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) { 712815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro struct pt_regs *regs = task_pt_regs(tsk); 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (valid_user_regs(&newregs)) { 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *regs = newregs; 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get the child FPU state. 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_getfpregs(struct task_struct *tsk, void __user *ufp) 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 729e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro return copy_to_user(ufp, &task_thread_info(tsk)->fpstate, 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct user_fp)) ? -EFAULT : 0; 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the child FPU state. 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_setfpregs(struct task_struct *tsk, void __user *ufp) 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 738e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro struct thread_info *thread = task_thread_info(tsk); 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds thread->used_cp[1] = thread->used_cp[2] = 1; 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return copy_from_user(&thread->fpstate, ufp, 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct user_fp)) ? -EFAULT : 0; 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IWMMXT 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get the child iWMMXt state. 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_getwmmxregs(struct task_struct *tsk, void __user *ufp) 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 751e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro struct thread_info *thread = task_thread_info(tsk); 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT)) 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODATA; 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwmmxt_task_disable(thread); /* force it to ram */ 756cdaabbd74b15296acf09215355a7f3b07b92b83eRussell King return copy_to_user(ufp, &thread->fpstate.iwmmxt, IWMMXT_SIZE) 757cdaabbd74b15296acf09215355a7f3b07b92b83eRussell King ? -EFAULT : 0; 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the child iWMMXt state. 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_setwmmxregs(struct task_struct *tsk, void __user *ufp) 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 765e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro struct thread_info *thread = task_thread_info(tsk); 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT)) 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EACCES; 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwmmxt_task_release(thread); /* force a reload */ 77017320a9644a45ccac51ce4ff4333276844abf72dRussell King return copy_from_user(&thread->fpstate.iwmmxt, ufp, IWMMXT_SIZE) 771cdaabbd74b15296acf09215355a7f3b07b92b83eRussell King ? -EFAULT : 0; 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7765429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#ifdef CONFIG_CRUNCH 7775429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek/* 7785429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek * Get the child Crunch state. 7795429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek */ 7805429b060df6d556f396b78364ad017686015bc34Lennert Buytenhekstatic int ptrace_getcrunchregs(struct task_struct *tsk, void __user *ufp) 7815429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek{ 7825429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek struct thread_info *thread = task_thread_info(tsk); 7835429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 7845429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek crunch_task_disable(thread); /* force it to ram */ 7855429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek return copy_to_user(ufp, &thread->crunchstate, CRUNCH_SIZE) 7865429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek ? -EFAULT : 0; 7875429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek} 7885429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 7895429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek/* 7905429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek * Set the child Crunch state. 7915429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek */ 7925429b060df6d556f396b78364ad017686015bc34Lennert Buytenhekstatic int ptrace_setcrunchregs(struct task_struct *tsk, void __user *ufp) 7935429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek{ 7945429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek struct thread_info *thread = task_thread_info(tsk); 7955429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 7965429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek crunch_task_release(thread); /* force a reload */ 7975429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek return copy_from_user(&thread->crunchstate, ufp, CRUNCH_SIZE) 7985429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek ? -EFAULT : 0; 7995429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek} 8005429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#endif 8015429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 8023d1228ead618b88e8606015cbabc49019981805dCatalin Marinas#ifdef CONFIG_VFP 8033d1228ead618b88e8606015cbabc49019981805dCatalin Marinas/* 8043d1228ead618b88e8606015cbabc49019981805dCatalin Marinas * Get the child VFP state. 8053d1228ead618b88e8606015cbabc49019981805dCatalin Marinas */ 8063d1228ead618b88e8606015cbabc49019981805dCatalin Marinasstatic int ptrace_getvfpregs(struct task_struct *tsk, void __user *data) 8073d1228ead618b88e8606015cbabc49019981805dCatalin Marinas{ 8083d1228ead618b88e8606015cbabc49019981805dCatalin Marinas struct thread_info *thread = task_thread_info(tsk); 8093d1228ead618b88e8606015cbabc49019981805dCatalin Marinas union vfp_state *vfp = &thread->vfpstate; 8103d1228ead618b88e8606015cbabc49019981805dCatalin Marinas struct user_vfp __user *ufp = data; 8113d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 812ad187f956108e1c56b444706212bf08d84c0bee0Russell King vfp_sync_hwstate(thread); 8133d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 8143d1228ead618b88e8606015cbabc49019981805dCatalin Marinas /* copy the floating point registers */ 8153d1228ead618b88e8606015cbabc49019981805dCatalin Marinas if (copy_to_user(&ufp->fpregs, &vfp->hard.fpregs, 8163d1228ead618b88e8606015cbabc49019981805dCatalin Marinas sizeof(vfp->hard.fpregs))) 8173d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return -EFAULT; 8183d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 8193d1228ead618b88e8606015cbabc49019981805dCatalin Marinas /* copy the status and control register */ 8203d1228ead618b88e8606015cbabc49019981805dCatalin Marinas if (put_user(vfp->hard.fpscr, &ufp->fpscr)) 8213d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return -EFAULT; 8223d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 8233d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return 0; 8243d1228ead618b88e8606015cbabc49019981805dCatalin Marinas} 8253d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 8263d1228ead618b88e8606015cbabc49019981805dCatalin Marinas/* 8273d1228ead618b88e8606015cbabc49019981805dCatalin Marinas * Set the child VFP state. 8283d1228ead618b88e8606015cbabc49019981805dCatalin Marinas */ 8293d1228ead618b88e8606015cbabc49019981805dCatalin Marinasstatic int ptrace_setvfpregs(struct task_struct *tsk, void __user *data) 8303d1228ead618b88e8606015cbabc49019981805dCatalin Marinas{ 8313d1228ead618b88e8606015cbabc49019981805dCatalin Marinas struct thread_info *thread = task_thread_info(tsk); 8323d1228ead618b88e8606015cbabc49019981805dCatalin Marinas union vfp_state *vfp = &thread->vfpstate; 8333d1228ead618b88e8606015cbabc49019981805dCatalin Marinas struct user_vfp __user *ufp = data; 8343d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 835ad187f956108e1c56b444706212bf08d84c0bee0Russell King vfp_sync_hwstate(thread); 8363d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 8373d1228ead618b88e8606015cbabc49019981805dCatalin Marinas /* copy the floating point registers */ 8383d1228ead618b88e8606015cbabc49019981805dCatalin Marinas if (copy_from_user(&vfp->hard.fpregs, &ufp->fpregs, 8393d1228ead618b88e8606015cbabc49019981805dCatalin Marinas sizeof(vfp->hard.fpregs))) 8403d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return -EFAULT; 8413d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 8423d1228ead618b88e8606015cbabc49019981805dCatalin Marinas /* copy the status and control register */ 8433d1228ead618b88e8606015cbabc49019981805dCatalin Marinas if (get_user(vfp->hard.fpscr, &ufp->fpscr)) 8443d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return -EFAULT; 8453d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 846ad187f956108e1c56b444706212bf08d84c0bee0Russell King vfp_flush_hwstate(thread); 847ad187f956108e1c56b444706212bf08d84c0bee0Russell King 8483d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return 0; 8493d1228ead618b88e8606015cbabc49019981805dCatalin Marinas} 8503d1228ead618b88e8606015cbabc49019981805dCatalin Marinas#endif 8513d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 852864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon#ifdef CONFIG_HAVE_HW_BREAKPOINT 853864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon/* 854864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * Convert a virtual register number into an index for a thread_info 855864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * breakpoint array. Breakpoints are identified using positive numbers 856864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * whilst watchpoints are negative. The registers are laid out as pairs 857864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * of (address, control), each pair mapping to a unique hw_breakpoint struct. 858864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * Register 0 is reserved for describing resource information. 859864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon */ 860864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconstatic int ptrace_hbp_num_to_idx(long num) 861864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 862864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (num < 0) 863864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon num = (ARM_MAX_BRP << 1) - num; 864864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon return (num - 1) >> 1; 865864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 866864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 867864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon/* 868864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * Returns the virtual register number for the address of the 869864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * breakpoint at index idx. 870864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon */ 871864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconstatic long ptrace_hbp_idx_to_num(int idx) 872864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 873864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon long mid = ARM_MAX_BRP << 1; 874864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon long num = (idx << 1) + 1; 875864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon return num > mid ? mid - num : num; 876864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 877864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 878864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon/* 879864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * Handle hitting a HW-breakpoint. 880864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon */ 881864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconstatic void ptrace_hbptriggered(struct perf_event *bp, int unused, 882864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct perf_sample_data *data, 883864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct pt_regs *regs) 884864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 885864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp); 886864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon long num; 887864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon int i; 888864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon siginfo_t info; 889864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 890864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon for (i = 0; i < ARM_MAX_HBP_SLOTS; ++i) 891864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (current->thread.debug.hbp[i] == bp) 892864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon break; 893864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 894864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon num = (i == ARM_MAX_HBP_SLOTS) ? 0 : ptrace_hbp_idx_to_num(i); 895864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 896864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon info.si_signo = SIGTRAP; 897864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon info.si_errno = (int)num; 898864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon info.si_code = TRAP_HWBKPT; 899864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon info.si_addr = (void __user *)(bkpt->trigger); 900864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 901864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon force_sig_info(SIGTRAP, &info, current); 902864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 903864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 904864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon/* 905864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * Set ptrace breakpoint pointers to zero for this task. 906864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * This is required in order to prevent child processes from unregistering 907864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * breakpoints held by their parent. 908864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon */ 909864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconvoid clear_ptrace_hw_breakpoint(struct task_struct *tsk) 910864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 911864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon memset(tsk->thread.debug.hbp, 0, sizeof(tsk->thread.debug.hbp)); 912864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 913864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 914864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon/* 915864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * Unregister breakpoints from this task and reset the pointers in 916864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * the thread_struct. 917864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon */ 918864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconvoid flush_ptrace_hw_breakpoint(struct task_struct *tsk) 919864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 920864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon int i; 921864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct thread_struct *t = &tsk->thread; 922864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 923864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon for (i = 0; i < ARM_MAX_HBP_SLOTS; i++) { 924864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (t->debug.hbp[i]) { 925864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon unregister_hw_breakpoint(t->debug.hbp[i]); 926864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon t->debug.hbp[i] = NULL; 927864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 928864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 929864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 930864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 931864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconstatic u32 ptrace_get_hbp_resource_info(void) 932864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 933864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon u8 num_brps, num_wrps, debug_arch, wp_len; 934864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon u32 reg = 0; 935864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 936864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon num_brps = hw_breakpoint_slots(TYPE_INST); 937864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon num_wrps = hw_breakpoint_slots(TYPE_DATA); 938864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon debug_arch = arch_get_debug_arch(); 939864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon wp_len = arch_get_max_wp_len(); 940864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 941864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg |= debug_arch; 942864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg <<= 8; 943864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg |= wp_len; 944864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg <<= 8; 945864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg |= num_wrps; 946864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg <<= 8; 947864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg |= num_brps; 948864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 949864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon return reg; 950864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 951864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 952864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconstatic struct perf_event *ptrace_hbp_create(struct task_struct *tsk, int type) 953864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 954864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct perf_event_attr attr; 955864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 956864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ptrace_breakpoint_init(&attr); 957864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 958864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon /* Initialise fields to sane defaults. */ 959864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.bp_addr = 0; 960864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.bp_len = HW_BREAKPOINT_LEN_4; 961864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.bp_type = type; 962864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.disabled = 1; 963864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 964864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon return register_user_hw_breakpoint(&attr, ptrace_hbptriggered, tsk); 965864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 966864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 967864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconstatic int ptrace_gethbpregs(struct task_struct *tsk, long num, 968864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon unsigned long __user *data) 969864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 970864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon u32 reg; 971864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon int idx, ret = 0; 972864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct perf_event *bp; 973864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct arch_hw_breakpoint_ctrl arch_ctrl; 974864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 975864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (num == 0) { 976864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg = ptrace_get_hbp_resource_info(); 977864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } else { 978864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon idx = ptrace_hbp_num_to_idx(num); 979864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) { 980864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = -EINVAL; 981864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon goto out; 982864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 983864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 984864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon bp = tsk->thread.debug.hbp[idx]; 985864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (!bp) { 986864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg = 0; 987864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon goto put; 988864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 989864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 990864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon arch_ctrl = counter_arch_bp(bp)->ctrl; 991864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 992864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon /* 993864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * Fix up the len because we may have adjusted it 994864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon * to compensate for an unaligned address. 995864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon */ 996864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon while (!(arch_ctrl.len & 0x1)) 997864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon arch_ctrl.len >>= 1; 998864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 999864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (idx & 0x1) 1000864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg = encode_ctrl_reg(arch_ctrl); 1001864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon else 1002864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon reg = bp->attr.bp_addr; 1003864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 1004864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 1005864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconput: 1006864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (put_user(reg, data)) 1007864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = -EFAULT; 1008864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 1009864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconout: 1010864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon return ret; 1011864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 1012864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 1013864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconstatic int ptrace_sethbpregs(struct task_struct *tsk, long num, 1014864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon unsigned long __user *data) 1015864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon{ 1016864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon int idx, gen_len, gen_type, implied_type, ret = 0; 1017864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon u32 user_val; 1018864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct perf_event *bp; 1019864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct arch_hw_breakpoint_ctrl ctrl; 1020864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon struct perf_event_attr attr; 1021864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 1022864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (num == 0) 1023864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon goto out; 1024864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon else if (num < 0) 1025864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon implied_type = HW_BREAKPOINT_RW; 1026864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon else 1027864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon implied_type = HW_BREAKPOINT_X; 1028864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 1029864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon idx = ptrace_hbp_num_to_idx(num); 1030864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) { 1031864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = -EINVAL; 1032864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon goto out; 1033864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 1034864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 1035864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (get_user(user_val, data)) { 1036864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = -EFAULT; 1037864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon goto out; 1038864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 1039864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 1040864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon bp = tsk->thread.debug.hbp[idx]; 1041864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (!bp) { 1042864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon bp = ptrace_hbp_create(tsk, implied_type); 1043864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (IS_ERR(bp)) { 1044864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = PTR_ERR(bp); 1045864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon goto out; 1046864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 1047864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon tsk->thread.debug.hbp[idx] = bp; 1048864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 1049864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 1050864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr = bp->attr; 1051864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 1052864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (num & 0x1) { 1053864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon /* Address */ 1054864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.bp_addr = user_val; 1055864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } else { 1056864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon /* Control */ 1057864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon decode_ctrl_reg(user_val, &ctrl); 1058864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = arch_bp_generic_fields(ctrl, &gen_len, &gen_type); 1059864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if (ret) 1060864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon goto out; 1061864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 1062864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon if ((gen_type & implied_type) != gen_type) { 1063864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = -EINVAL; 1064864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon goto out; 1065864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 1066864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 1067864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.bp_len = gen_len; 1068864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.bp_type = gen_type; 1069864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon attr.disabled = !ctrl.enabled; 1070864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon } 1071864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 1072864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = modify_user_hw_breakpoint(bp, &attr); 1073864232fa1a2f8dfe003438ef0851a56722740f3eWill Deaconout: 1074864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon return ret; 1075864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon} 1076864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon#endif 1077864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 10789b05a69e0534ec70bc94921936ffa05b330507cbNamhyung Kimlong arch_ptrace(struct task_struct *child, long request, 10799b05a69e0534ec70bc94921936ffa05b330507cbNamhyung Kim unsigned long addr, unsigned long data) 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1082b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim unsigned long __user *datap = (unsigned long __user *) data; 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (request) { 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_PEEKUSR: 1086b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_read_user(child, addr, datap); 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_POKEUSR: 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_write_user(child, addr, data); 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GETREGS: 1094b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_getregs(child, datap); 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SETREGS: 1098b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_setregs(child, datap); 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GETFPREGS: 1102b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_getfpregs(child, datap); 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SETFPREGS: 1106b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_setfpregs(child, datap); 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IWMMXT 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GETWMMXREGS: 1111b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_getwmmxregs(child, datap); 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SETWMMXREGS: 1115b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_setwmmxregs(child, datap); 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GET_THREAD_AREA: 1120e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro ret = put_user(task_thread_info(child)->tp_value, 1121b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim datap); 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11243f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre case PTRACE_SET_SYSCALL: 11255ba6d3febd4978f31b2c523d64d381603923a709Russell King task_thread_info(child)->syscall = data; 11263f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre ret = 0; 11273f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre break; 11283f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre 11295429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#ifdef CONFIG_CRUNCH 11305429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek case PTRACE_GETCRUNCHREGS: 1131b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_getcrunchregs(child, datap); 11325429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek break; 11335429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 11345429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek case PTRACE_SETCRUNCHREGS: 1135b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_setcrunchregs(child, datap); 11365429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek break; 11375429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#endif 11385429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 11393d1228ead618b88e8606015cbabc49019981805dCatalin Marinas#ifdef CONFIG_VFP 11403d1228ead618b88e8606015cbabc49019981805dCatalin Marinas case PTRACE_GETVFPREGS: 1141b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_getvfpregs(child, datap); 11423d1228ead618b88e8606015cbabc49019981805dCatalin Marinas break; 11433d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 11443d1228ead618b88e8606015cbabc49019981805dCatalin Marinas case PTRACE_SETVFPREGS: 1145b640a0d192265c47bbf60951115bdb59d2c017d1Namhyung Kim ret = ptrace_setvfpregs(child, datap); 11463d1228ead618b88e8606015cbabc49019981805dCatalin Marinas break; 11473d1228ead618b88e8606015cbabc49019981805dCatalin Marinas#endif 11483d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 1149864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon#ifdef CONFIG_HAVE_HW_BREAKPOINT 1150864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon case PTRACE_GETHBPREGS: 1151864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = ptrace_gethbpregs(child, addr, 1152864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon (unsigned long __user *)data); 1153864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon break; 1154864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon case PTRACE_SETHBPREGS: 1155864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon ret = ptrace_sethbpregs(child, addr, 1156864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon (unsigned long __user *)data); 1157864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon break; 1158864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon#endif 1159864232fa1a2f8dfe003438ef0851a56722740f3eWill Deacon 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_request(child, request, addr, data); 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11683f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitreasmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long ip; 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_thread_flag(TIF_SYSCALL_TRACE)) 11733f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre return scno; 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(current->ptrace & PT_PTRACED)) 11753f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre return scno; 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Save IP. IP is used to denote syscall entry/exit: 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IP = 0 -> entry, = 1 -> exit 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip = regs->ARM_ip; 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->ARM_ip = why; 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11845ba6d3febd4978f31b2c523d64d381603923a709Russell King current_thread_info()->syscall = scno; 11853f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* the 0x80 provides a way for the tracing parent to distinguish 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds between a syscall stop and SIGTRAP delivery */ 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? 0x80 : 0)); 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this isn't the same as continuing with a signal, but it will do 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for normal use. strace only continues with a signal if the 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stopping signal is not SIGTRAP. -brl 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (current->exit_code) { 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_sig(current->exit_code, current, 1); 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current->exit_code = 0; 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->ARM_ip = ip; 12003f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre 12015ba6d3febd4978f31b2c523d64d381603923a709Russell King return current_thread_info()->syscall; 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1203