ptrace.c revision 68b7f7153fa58df710924fbb79722717d2d16094
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/arch/arm/kernel/ptrace.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * By Ross Biro 1/23/92 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * edited by Linus Torvalds 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ARM modifications Copyright (C) 2000 Russell King 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/smp.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/user.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/security.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 207ed20e1ad521b5f5df61bf6559ae60738e393741Jesper Juhl#include <linux/signal.h> 2133fa9b13285e76fb95d940120964562e4c7081c2Russell King#include <linux/uaccess.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/traps.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ptrace.h" 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define REG_PC 15 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define REG_PSR 16 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does not yet catch signals sent when the child dies. 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in exit.c or in signal.c. 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Breakpoint SWI instruction: SWI &9F0001 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_ARM 0xef9f0001 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_THUMB 0xdf00 /* fill this in later */ 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * New breakpoints - use an undefined instruction. The ARM architecture 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reference manual guarantees that the following instruction space 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will produce an undefined instruction exception on all CPUs: 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ARM: xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Thumb: 1101 1110 xxxx xxxx 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_ARM 0xe7f001f0 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAKINST_THUMB 0xde01 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine will get a word off of the processes privileged stack. 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the offset is how far from the base addr as stored in the THREAD. 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine assumes that all the privileged stacks are in our 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data space. 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline long get_user_reg(struct task_struct *task, int offset) 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 63815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro return task_pt_regs(task)->uregs[offset]; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine will put a word on the processes privileged stack. 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the offset is how far from the base addr as stored in the THREAD. 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine assumes that all the privileged stacks are in our 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data space. 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsput_user_reg(struct task_struct *task, int offset, long data) 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 75815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro struct pt_regs newregs, *regs = task_pt_regs(task); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -EINVAL; 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newregs = *regs; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newregs.uregs[offset] = data; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (valid_user_regs(&newregs)) { 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->uregs[offset] = data; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsread_u32(struct task_struct *task, unsigned long addr, u32 *res) 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr, res, sizeof(*res), 0); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret == sizeof(*res) ? 0 : -EIO; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsread_instr(struct task_struct *task, unsigned long addr, u32 *res) 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (addr & 1) { 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 val; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr & ~1, &val, sizeof(val), 0); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ret == sizeof(val) ? 0 : -EIO; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *res = val; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr & ~3, &val, sizeof(val), 0); 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ret == sizeof(val) ? 0 : -EIO; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *res = val; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get value of register `rn' (in the instruction) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsptrace_getrn(struct task_struct *child, unsigned long insn) 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int reg = (insn >> 16) & 15; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = get_user_reg(child, reg); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reg == 15) 1291de765c1e940e23d83ec57035769e8af003f8796Russell King val += 8; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get value of operand 2 (in an ALU instruction) 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsptrace_getaluop2(struct task_struct *child, unsigned long insn) 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int shift; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int type; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 1 << 25) { 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = insn & 255; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (insn >> 8) & 15; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = 3; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = get_user_reg (child, insn & 15); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & (1 << 4)) 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (int)get_user_reg (child, (insn >> 8) & 15); 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (insn >> 7) & 31; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = (insn >> 5) & 3; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: val <<= shift; break; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: val >>= shift; break; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (((signed long)val) >> shift); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (val >> shift) | (val << (32 - shift)); 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get value of operand 2 (in a LDR instruction) 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsptrace_getldrop2(struct task_struct *child, unsigned long insn) 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int shift; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int type; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = get_user_reg(child, insn & 15); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (insn >> 7) & 31; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = (insn >> 5) & 3; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: val <<= shift; break; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: val >>= shift; break; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (((signed long)val) >> shift); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (val >> shift) | (val << (32 - shift)); 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_MASK 0x01e00000 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_AND 0x00000000 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_EOR 0x00200000 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_SUB 0x00400000 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_RSB 0x00600000 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_ADD 0x00800000 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_ADC 0x00a00000 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_SBC 0x00c00000 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_RSC 0x00e00000 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_ORR 0x01800000 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_MOV 0x01a00000 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_BIC 0x01c00000 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_MVN 0x01e00000 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsget_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn) 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 alt = 0; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (insn & 0x0e000000) { 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x00000000: 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x02000000: { 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data processing 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long aluop1, aluop2, ccbit; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22622f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev if ((insn & 0x0fffffd0) == 0x012fff10) { 22722f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev /* 22822f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev * bx or blx 22922f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev */ 23022f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev alt = get_user_reg(child, insn & 15); 23122f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev break; 23222f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev } 23322f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev 23422f975f4ffa707ea24507f6899bb9f5a1ff034bcNikola Valerjev 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((insn & 0xf000) != 0xf000) 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop1 = ptrace_getrn(child, insn); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop2 = ptrace_getaluop2(child, insn); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccbit = get_user_reg(child, REG_PSR) & PSR_C_BIT ? 1 : 0; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (insn & OP_MASK) { 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_AND: alt = aluop1 & aluop2; break; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_EOR: alt = aluop1 ^ aluop2; break; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_SUB: alt = aluop1 - aluop2; break; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_RSB: alt = aluop2 - aluop1; break; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_ADD: alt = aluop1 + aluop2; break; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_ADC: alt = aluop1 + aluop2 + ccbit; break; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_SBC: alt = aluop1 - aluop2 + ccbit; break; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_RSC: alt = aluop2 - aluop1 + ccbit; break; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_ORR: alt = aluop1 | aluop2; break; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_MOV: alt = aluop2; break; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_BIC: alt = aluop1 & ~aluop2; break; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_MVN: alt = ~aluop2; break; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x04000000: 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x06000000: 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ldr 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((insn & 0x0010f000) == 0x0010f000) { 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long base; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base = ptrace_getrn(child, insn); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 1 << 24) { 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long aluop2; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 0x02000000) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop2 = ptrace_getldrop2(child, insn); 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop2 = insn & 0xfff; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 1 << 23) 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base += aluop2; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base -= aluop2; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2811de765c1e940e23d83ec57035769e8af003f8796Russell King read_u32(child, base, &alt); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x08000000: 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ldm 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((insn & 0x00108000) == 0x00108000) { 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long base; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int nr_regs; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & (1 << 23)) { 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs = hweight16(insn & 65535) << 2; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(insn & (1 << 24))) 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs -= 4; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & (1 << 24)) 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs = -4; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs = 0; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base = ptrace_getrn(child, insn); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071de765c1e940e23d83ec57035769e8af003f8796Russell King read_u32(child, base + nr_regs, &alt); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x0a000000: { 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bl or b 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds signed long displ; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* It's a branch/branch link: instead of trying to 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * figure out whether the branch will be taken or not, 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we'll put a breakpoint at both locations. This is 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * simpler, more reliable, and probably not a whole lot 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slower than the alternative approach of emulating the 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * branch. 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds displ = (insn & 0x00ffffff) << 8; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds displ = (displ >> 6) + 8; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (displ != 0 && displ != 4) 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alt = pc + displ; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return alt; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsswap_insn(struct task_struct *task, unsigned long addr, 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *old_insn, void *new_insn, int size) 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr, old_insn, size, 0); 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret == size) 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr, new_insn, size, 1); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsadd_breakpoint(struct task_struct *task, struct debug_info *dbg, unsigned long addr) 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int nr = dbg->nsaved; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nr < 2) { 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 new_insn = BREAKINST_ARM; 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = swap_insn(task, addr, &dbg->bp[nr].insn, &new_insn, 4); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res == 4) { 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg->bp[nr].address = addr; 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg->nsaved += 1; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "ptrace: too many breakpoints\n"); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear one breakpoint in the user program. We copy what the hardware 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does and use bit 0 of the address to indicate whether this is a Thumb 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * breakpoint or an ARM breakpoint. 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void clear_breakpoint(struct task_struct *task, struct debug_entry *bp) 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long addr = bp->address; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union debug_insn old_insn; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (addr & 1) { 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = swap_insn(task, addr & ~1, &old_insn.thumb, 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bp->insn.thumb, 2); 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != 2 || old_insn.thumb != BREAKINST_THUMB) 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s:%d: corrupted Thumb breakpoint at " 38319c5870c0eefd27c6d09d867465e0571262e05d0Alexey Dobriyan "0x%08lx (0x%04x)\n", task->comm, 38419c5870c0eefd27c6d09d867465e0571262e05d0Alexey Dobriyan task_pid_nr(task), addr, old_insn.thumb); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = swap_insn(task, addr & ~3, &old_insn.arm, 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bp->insn.arm, 4); 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != 4 || old_insn.arm != BREAKINST_ARM) 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s:%d: corrupted ARM breakpoint at " 39119c5870c0eefd27c6d09d867465e0571262e05d0Alexey Dobriyan "0x%08lx (0x%08x)\n", task->comm, 39219c5870c0eefd27c6d09d867465e0571262e05d0Alexey Dobriyan task_pid_nr(task), addr, old_insn.arm); 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_set_bpt(struct task_struct *child) 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pt_regs *regs; 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long pc; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 insn; 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 403815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro regs = task_pt_regs(child); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc = instruction_pointer(regs); 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (thumb_mode(regs)) { 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "ptrace: can't handle thumb mode\n"); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = read_instr(child, pc, &insn); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) { 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct debug_info *dbg = &child->thread.debug; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long alt; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg->nsaved = 0; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alt = get_branch_address(child, pc, insn); 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (alt) 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_breakpoint(child, dbg, alt); 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that we ignore the result of setting the above 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * breakpoint since it may fail. When it does, this is 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not so much an error, but a forewarning that we may 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be receiving a prefetch abort shortly. 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we don't set this breakpoint here, then we can 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lose control of the thread during single stepping. 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!alt || predicate(insn) != PREDICATE_ALWAYS) 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_breakpoint(child, dbg, pc + 4); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ensure no single-step breakpoint is pending. Returns non-zero 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * value if child was being single-stepped. 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_cancel_bpt(struct task_struct *child) 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, nsaved = child->thread.debug.nsaved; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child->thread.debug.nsaved = 0; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nsaved > 2) { 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nsaved = 2; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < nsaved; i++) 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_breakpoint(child, &child->thread.debug.bp[i]); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by kernel/ptrace.c when detaching.. 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_disable(struct task_struct *child) 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 460b2a0d36fde90fa9dd20b7dde21dbcff09b130b38Russell King single_step_disable(child); 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle hitting a breakpoint. 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_break(struct task_struct *tsk, struct pt_regs *regs) 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds siginfo_t info; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_cancel_bpt(tsk); 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_signo = SIGTRAP; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_errno = 0; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_code = TRAP_BRKPT; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_addr = (void __user *)instruction_pointer(regs); 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds force_sig_info(SIGTRAP, &info, tsk); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int break_trap(struct pt_regs *regs, unsigned int instr) 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_break(current, regs); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct undef_hook arm_break_hook = { 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_mask = 0x0fffffff, 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_val = 0x07f001f0, 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_mask = PSR_T_BIT, 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_val = 0, 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fn = break_trap, 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct undef_hook thumb_break_hook = { 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_mask = 0xffff, 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_val = 0xde01, 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_mask = PSR_T_BIT, 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_val = PSR_T_BIT, 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fn = break_trap, 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ptrace_break_init(void) 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_undef_hook(&arm_break_hook); 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_undef_hook(&thumb_break_hook); 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscore_initcall(ptrace_break_init); 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read the word at offset "off" into the "struct user". We 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * actually access the pt_regs stored on the kernel stack. 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_read_user(struct task_struct *tsk, unsigned long off, 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long __user *ret) 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long tmp; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off & 3 || off >= sizeof(struct user)) 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = 0; 52468b7f7153fa58df710924fbb79722717d2d16094Paul Brook if (off == PT_TEXT_ADDR) 52568b7f7153fa58df710924fbb79722717d2d16094Paul Brook tmp = tsk->mm->start_code; 52668b7f7153fa58df710924fbb79722717d2d16094Paul Brook else if (off == PT_DATA_ADDR) 52768b7f7153fa58df710924fbb79722717d2d16094Paul Brook tmp = tsk->mm->start_data; 52868b7f7153fa58df710924fbb79722717d2d16094Paul Brook else if (off == PT_TEXT_END_ADDR) 52968b7f7153fa58df710924fbb79722717d2d16094Paul Brook tmp = tsk->mm->end_code; 53068b7f7153fa58df710924fbb79722717d2d16094Paul Brook else if (off < sizeof(struct pt_regs)) 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = get_user_reg(tsk, off >> 2); 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user(tmp, ret); 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write the word at offset "off" into "struct user". We 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * actually access the pt_regs stored on the kernel stack. 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_write_user(struct task_struct *tsk, unsigned long off, 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val) 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off & 3 || off >= sizeof(struct user)) 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off >= sizeof(struct pt_regs)) 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user_reg(tsk, off >> 2, val); 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get all user integer registers. 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_getregs(struct task_struct *tsk, void __user *uregs) 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 557815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro struct pt_regs *regs = task_pt_regs(tsk); 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set all user integer registers. 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_setregs(struct task_struct *tsk, void __user *uregs) 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pt_regs newregs; 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EFAULT; 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) { 572815d5ec86eb8d5f57e5e4aa147bd1fb6338c58acAl Viro struct pt_regs *regs = task_pt_regs(tsk); 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (valid_user_regs(&newregs)) { 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *regs = newregs; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get the child FPU state. 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_getfpregs(struct task_struct *tsk, void __user *ufp) 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 589e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro return copy_to_user(ufp, &task_thread_info(tsk)->fpstate, 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct user_fp)) ? -EFAULT : 0; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the child FPU state. 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_setfpregs(struct task_struct *tsk, void __user *ufp) 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 598e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro struct thread_info *thread = task_thread_info(tsk); 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds thread->used_cp[1] = thread->used_cp[2] = 1; 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return copy_from_user(&thread->fpstate, ufp, 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct user_fp)) ? -EFAULT : 0; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IWMMXT 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get the child iWMMXt state. 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_getwmmxregs(struct task_struct *tsk, void __user *ufp) 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 611e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro struct thread_info *thread = task_thread_info(tsk); 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT)) 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODATA; 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwmmxt_task_disable(thread); /* force it to ram */ 616cdaabbd74b15296acf09215355a7f3b07b92b83eRussell King return copy_to_user(ufp, &thread->fpstate.iwmmxt, IWMMXT_SIZE) 617cdaabbd74b15296acf09215355a7f3b07b92b83eRussell King ? -EFAULT : 0; 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the child iWMMXt state. 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_setwmmxregs(struct task_struct *tsk, void __user *ufp) 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 625e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro struct thread_info *thread = task_thread_info(tsk); 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT)) 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EACCES; 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwmmxt_task_release(thread); /* force a reload */ 63017320a9644a45ccac51ce4ff4333276844abf72dRussell King return copy_from_user(&thread->fpstate.iwmmxt, ufp, IWMMXT_SIZE) 631cdaabbd74b15296acf09215355a7f3b07b92b83eRussell King ? -EFAULT : 0; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6365429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#ifdef CONFIG_CRUNCH 6375429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek/* 6385429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek * Get the child Crunch state. 6395429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek */ 6405429b060df6d556f396b78364ad017686015bc34Lennert Buytenhekstatic int ptrace_getcrunchregs(struct task_struct *tsk, void __user *ufp) 6415429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek{ 6425429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek struct thread_info *thread = task_thread_info(tsk); 6435429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 6445429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek crunch_task_disable(thread); /* force it to ram */ 6455429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek return copy_to_user(ufp, &thread->crunchstate, CRUNCH_SIZE) 6465429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek ? -EFAULT : 0; 6475429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek} 6485429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 6495429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek/* 6505429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek * Set the child Crunch state. 6515429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek */ 6525429b060df6d556f396b78364ad017686015bc34Lennert Buytenhekstatic int ptrace_setcrunchregs(struct task_struct *tsk, void __user *ufp) 6535429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek{ 6545429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek struct thread_info *thread = task_thread_info(tsk); 6555429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 6565429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek crunch_task_release(thread); /* force a reload */ 6575429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek return copy_from_user(&thread->crunchstate, ufp, CRUNCH_SIZE) 6585429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek ? -EFAULT : 0; 6595429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek} 6605429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#endif 6615429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 6623d1228ead618b88e8606015cbabc49019981805dCatalin Marinas#ifdef CONFIG_VFP 6633d1228ead618b88e8606015cbabc49019981805dCatalin Marinas/* 6643d1228ead618b88e8606015cbabc49019981805dCatalin Marinas * Get the child VFP state. 6653d1228ead618b88e8606015cbabc49019981805dCatalin Marinas */ 6663d1228ead618b88e8606015cbabc49019981805dCatalin Marinasstatic int ptrace_getvfpregs(struct task_struct *tsk, void __user *data) 6673d1228ead618b88e8606015cbabc49019981805dCatalin Marinas{ 6683d1228ead618b88e8606015cbabc49019981805dCatalin Marinas struct thread_info *thread = task_thread_info(tsk); 6693d1228ead618b88e8606015cbabc49019981805dCatalin Marinas union vfp_state *vfp = &thread->vfpstate; 6703d1228ead618b88e8606015cbabc49019981805dCatalin Marinas struct user_vfp __user *ufp = data; 6713d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 6723d1228ead618b88e8606015cbabc49019981805dCatalin Marinas vfp_sync_state(thread); 6733d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 6743d1228ead618b88e8606015cbabc49019981805dCatalin Marinas /* copy the floating point registers */ 6753d1228ead618b88e8606015cbabc49019981805dCatalin Marinas if (copy_to_user(&ufp->fpregs, &vfp->hard.fpregs, 6763d1228ead618b88e8606015cbabc49019981805dCatalin Marinas sizeof(vfp->hard.fpregs))) 6773d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return -EFAULT; 6783d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 6793d1228ead618b88e8606015cbabc49019981805dCatalin Marinas /* copy the status and control register */ 6803d1228ead618b88e8606015cbabc49019981805dCatalin Marinas if (put_user(vfp->hard.fpscr, &ufp->fpscr)) 6813d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return -EFAULT; 6823d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 6833d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return 0; 6843d1228ead618b88e8606015cbabc49019981805dCatalin Marinas} 6853d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 6863d1228ead618b88e8606015cbabc49019981805dCatalin Marinas/* 6873d1228ead618b88e8606015cbabc49019981805dCatalin Marinas * Set the child VFP state. 6883d1228ead618b88e8606015cbabc49019981805dCatalin Marinas */ 6893d1228ead618b88e8606015cbabc49019981805dCatalin Marinasstatic int ptrace_setvfpregs(struct task_struct *tsk, void __user *data) 6903d1228ead618b88e8606015cbabc49019981805dCatalin Marinas{ 6913d1228ead618b88e8606015cbabc49019981805dCatalin Marinas struct thread_info *thread = task_thread_info(tsk); 6923d1228ead618b88e8606015cbabc49019981805dCatalin Marinas union vfp_state *vfp = &thread->vfpstate; 6933d1228ead618b88e8606015cbabc49019981805dCatalin Marinas struct user_vfp __user *ufp = data; 6943d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 6953d1228ead618b88e8606015cbabc49019981805dCatalin Marinas vfp_sync_state(thread); 6963d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 6973d1228ead618b88e8606015cbabc49019981805dCatalin Marinas /* copy the floating point registers */ 6983d1228ead618b88e8606015cbabc49019981805dCatalin Marinas if (copy_from_user(&vfp->hard.fpregs, &ufp->fpregs, 6993d1228ead618b88e8606015cbabc49019981805dCatalin Marinas sizeof(vfp->hard.fpregs))) 7003d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return -EFAULT; 7013d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 7023d1228ead618b88e8606015cbabc49019981805dCatalin Marinas /* copy the status and control register */ 7033d1228ead618b88e8606015cbabc49019981805dCatalin Marinas if (get_user(vfp->hard.fpscr, &ufp->fpscr)) 7043d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return -EFAULT; 7053d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 7063d1228ead618b88e8606015cbabc49019981805dCatalin Marinas return 0; 7073d1228ead618b88e8606015cbabc49019981805dCatalin Marinas} 7083d1228ead618b88e8606015cbabc49019981805dCatalin Marinas#endif 7093d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 710481bed454247538e9f57d4ea37b153ccba24ba7bChristoph Hellwiglong arch_ptrace(struct task_struct *child, long request, long addr, long data) 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (request) { 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read word at location "addr" in the child process. 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_PEEKTEXT: 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_PEEKDATA: 7207664732315c97f48dba9d1e7339ad16fc5a320acAlexey Dobriyan ret = generic_ptrace_peekdata(child, addr, data); 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_PEEKUSR: 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_read_user(child, addr, (unsigned long __user *)data); 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write the word at location addr. 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_POKETEXT: 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_POKEDATA: 732f284ce7269031947326bac6bb19a977705276222Alexey Dobriyan ret = generic_ptrace_pokedata(child, addr, data); 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_POKEUSR: 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_write_user(child, addr, data); 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * continue/restart and stop at next (return from) syscall 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SYSCALL: 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_CONT: 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EIO; 7457ed20e1ad521b5f5df61bf6559ae60738e393741Jesper Juhl if (!valid_signal(data)) 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request == PTRACE_SYSCALL) 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child->exit_code = data; 752b2a0d36fde90fa9dd20b7dde21dbcff09b130b38Russell King single_step_disable(child); 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_process(child); 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * make the child exit. Best I can do is send it a sigkill. 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * perhaps it should be put in the status that it wants to 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exit. 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_KILL: 763b2a0d36fde90fa9dd20b7dde21dbcff09b130b38Russell King single_step_disable(child); 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (child->exit_state != EXIT_ZOMBIE) { 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child->exit_code = SIGKILL; 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_process(child); 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * execute single instruction. 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SINGLESTEP: 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EIO; 7767ed20e1ad521b5f5df61bf6559ae60738e393741Jesper Juhl if (!valid_signal(data)) 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 778b2a0d36fde90fa9dd20b7dde21dbcff09b130b38Russell King single_step_enable(child); 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child->exit_code = data; 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* give it a chance to run. */ 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_process(child); 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GETREGS: 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_getregs(child, (void __user *)data); 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SETREGS: 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_setregs(child, (void __user *)data); 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GETFPREGS: 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_getfpregs(child, (void __user *)data); 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SETFPREGS: 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_setfpregs(child, (void __user *)data); 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IWMMXT 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GETWMMXREGS: 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_getwmmxregs(child, (void __user *)data); 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SETWMMXREGS: 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_setwmmxregs(child, (void __user *)data); 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GET_THREAD_AREA: 813e7c1b32fd354c34c4dceb1736a485bc5d91f7c43Al Viro ret = put_user(task_thread_info(child)->tp_value, 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long __user *) data); 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8173f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre case PTRACE_SET_SYSCALL: 8185ba6d3febd4978f31b2c523d64d381603923a709Russell King task_thread_info(child)->syscall = data; 8193f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre ret = 0; 8203f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre break; 8213f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre 8225429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#ifdef CONFIG_CRUNCH 8235429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek case PTRACE_GETCRUNCHREGS: 8245429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek ret = ptrace_getcrunchregs(child, (void __user *)data); 8255429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek break; 8265429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 8275429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek case PTRACE_SETCRUNCHREGS: 8285429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek ret = ptrace_setcrunchregs(child, (void __user *)data); 8295429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek break; 8305429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek#endif 8315429b060df6d556f396b78364ad017686015bc34Lennert Buytenhek 8323d1228ead618b88e8606015cbabc49019981805dCatalin Marinas#ifdef CONFIG_VFP 8333d1228ead618b88e8606015cbabc49019981805dCatalin Marinas case PTRACE_GETVFPREGS: 8343d1228ead618b88e8606015cbabc49019981805dCatalin Marinas ret = ptrace_getvfpregs(child, (void __user *)data); 8353d1228ead618b88e8606015cbabc49019981805dCatalin Marinas break; 8363d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 8373d1228ead618b88e8606015cbabc49019981805dCatalin Marinas case PTRACE_SETVFPREGS: 8383d1228ead618b88e8606015cbabc49019981805dCatalin Marinas ret = ptrace_setvfpregs(child, (void __user *)data); 8393d1228ead618b88e8606015cbabc49019981805dCatalin Marinas break; 8403d1228ead618b88e8606015cbabc49019981805dCatalin Marinas#endif 8413d1228ead618b88e8606015cbabc49019981805dCatalin Marinas 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_request(child, request, addr, data); 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8503f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitreasmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long ip; 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_thread_flag(TIF_SYSCALL_TRACE)) 8553f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre return scno; 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(current->ptrace & PT_PTRACED)) 8573f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre return scno; 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Save IP. IP is used to denote syscall entry/exit: 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IP = 0 -> entry, = 1 -> exit 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip = regs->ARM_ip; 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->ARM_ip = why; 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8665ba6d3febd4978f31b2c523d64d381603923a709Russell King current_thread_info()->syscall = scno; 8673f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* the 0x80 provides a way for the tracing parent to distinguish 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds between a syscall stop and SIGTRAP delivery */ 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? 0x80 : 0)); 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this isn't the same as continuing with a signal, but it will do 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for normal use. strace only continues with a signal if the 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stopping signal is not SIGTRAP. -brl 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (current->exit_code) { 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_sig(current->exit_code, current, 1); 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current->exit_code = 0; 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->ARM_ip = ip; 8823f471126ee53feb5e9b210ea2f525ed3bb9b7a7fNicolas Pitre 8835ba6d3febd4978f31b2c523d64d381603923a709Russell King return current_thread_info()->syscall; 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 885