ptrace.c revision 7ed20e1ad521b5f5df61bf6559ae60738e393741
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/config.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/smp.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/smp_lock.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/user.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/security.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 227ed20e1ad521b5f5df61bf6559ae60738e393741Jesper Juhl#include <linux/signal.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 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 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get the address of the live pt_regs for the specified task. 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These are saved onto the top kernel stack when the process 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is not running. 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: if a user thread is execve'd from kernel space, the 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * kernel stack will not be empty on entry to the kernel, so 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ptracing these tasks will fail. 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct pt_regs * 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsget_user_regs(struct task_struct *task) 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (struct pt_regs *) 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((unsigned long)task->thread_info + THREAD_SIZE - 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8 - sizeof(struct pt_regs)); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine will get a word off of the processes privileged stack. 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the offset is how far from the base addr as stored in the THREAD. 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine assumes that all the privileged stacks are in our 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data space. 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline long get_user_reg(struct task_struct *task, int offset) 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return get_user_regs(task)->uregs[offset]; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine will put a word on the processes privileged stack. 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the offset is how far from the base addr as stored in the THREAD. 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine assumes that all the privileged stacks are in our 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data space. 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsput_user_reg(struct task_struct *task, int offset, long data) 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pt_regs newregs, *regs = get_user_regs(task); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -EINVAL; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newregs = *regs; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newregs.uregs[offset] = data; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (valid_user_regs(&newregs)) { 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->uregs[offset] = data; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsread_u32(struct task_struct *task, unsigned long addr, u32 *res) 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr, res, sizeof(*res), 0); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret == sizeof(*res) ? 0 : -EIO; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsread_instr(struct task_struct *task, unsigned long addr, u32 *res) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (addr & 1) { 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 val; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr & ~1, &val, sizeof(val), 0); 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ret == sizeof(val) ? 0 : -EIO; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *res = val; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr & ~3, &val, sizeof(val), 0); 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ret == sizeof(val) ? 0 : -EIO; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *res = val; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get value of register `rn' (in the instruction) 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsptrace_getrn(struct task_struct *child, unsigned long insn) 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int reg = (insn >> 16) & 15; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = get_user_reg(child, reg); 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reg == 15) 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = pc_pointer(val + 8); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get value of operand 2 (in an ALU instruction) 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsptrace_getaluop2(struct task_struct *child, unsigned long insn) 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int shift; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int type; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 1 << 25) { 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = insn & 255; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (insn >> 8) & 15; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = 3; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = get_user_reg (child, insn & 15); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & (1 << 4)) 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (int)get_user_reg (child, (insn >> 8) & 15); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (insn >> 7) & 31; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = (insn >> 5) & 3; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: val <<= shift; break; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: val >>= shift; break; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (((signed long)val) >> shift); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (val >> shift) | (val << (32 - shift)); 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get value of operand 2 (in a LDR instruction) 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsptrace_getldrop2(struct task_struct *child, unsigned long insn) 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int shift; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int type; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = get_user_reg(child, insn & 15); 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift = (insn >> 7) & 31; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = (insn >> 5) & 3; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: val <<= shift; break; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: val >>= shift; break; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (((signed long)val) >> shift); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (val >> shift) | (val << (32 - shift)); 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_MASK 0x01e00000 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_AND 0x00000000 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_EOR 0x00200000 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_SUB 0x00400000 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_RSB 0x00600000 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_ADD 0x00800000 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_ADC 0x00a00000 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_SBC 0x00c00000 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_RSC 0x00e00000 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_ORR 0x01800000 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_MOV 0x01a00000 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_BIC 0x01c00000 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP_MVN 0x01e00000 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsget_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn) 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 alt = 0; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (insn & 0x0e000000) { 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x00000000: 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x02000000: { 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data processing 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long aluop1, aluop2, ccbit; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((insn & 0xf000) != 0xf000) 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop1 = ptrace_getrn(child, insn); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop2 = ptrace_getaluop2(child, insn); 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ccbit = get_user_reg(child, REG_PSR) & PSR_C_BIT ? 1 : 0; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (insn & OP_MASK) { 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_AND: alt = aluop1 & aluop2; break; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_EOR: alt = aluop1 ^ aluop2; break; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_SUB: alt = aluop1 - aluop2; break; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_RSB: alt = aluop2 - aluop1; break; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_ADD: alt = aluop1 + aluop2; break; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_ADC: alt = aluop1 + aluop2 + ccbit; break; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_SBC: alt = aluop1 - aluop2 + ccbit; break; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_RSC: alt = aluop2 - aluop1 + ccbit; break; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_ORR: alt = aluop1 | aluop2; break; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_MOV: alt = aluop2; break; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_BIC: alt = aluop1 & ~aluop2; break; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case OP_MVN: alt = ~aluop2; break; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x04000000: 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x06000000: 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ldr 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((insn & 0x0010f000) == 0x0010f000) { 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long base; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base = ptrace_getrn(child, insn); 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 1 << 24) { 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long aluop2; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 0x02000000) 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop2 = ptrace_getldrop2(child, insn); 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aluop2 = insn & 0xfff; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & 1 << 23) 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base += aluop2; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base -= aluop2; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (read_u32(child, base, &alt) == 0) 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alt = pc_pointer(alt); 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x08000000: 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ldm 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((insn & 0x00108000) == 0x00108000) { 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long base; 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int nr_regs; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & (1 << 23)) { 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs = hweight16(insn & 65535) << 2; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(insn & (1 << 24))) 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs -= 4; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (insn & (1 << 24)) 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs = -4; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_regs = 0; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base = ptrace_getrn(child, insn); 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (read_u32(child, base + nr_regs, &alt) == 0) 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alt = pc_pointer(alt); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x0a000000: { 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bl or b 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds signed long displ; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* It's a branch/branch link: instead of trying to 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * figure out whether the branch will be taken or not, 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we'll put a breakpoint at both locations. This is 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * simpler, more reliable, and probably not a whole lot 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slower than the alternative approach of emulating the 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * branch. 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds displ = (insn & 0x00ffffff) << 8; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds displ = (displ >> 6) + 8; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (displ != 0 && displ != 4) 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alt = pc + displ; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return alt; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsswap_insn(struct task_struct *task, unsigned long addr, 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *old_insn, void *new_insn, int size) 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr, old_insn, size, 0); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret == size) 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(task, addr, new_insn, size, 1); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsadd_breakpoint(struct task_struct *task, struct debug_info *dbg, unsigned long addr) 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int nr = dbg->nsaved; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nr < 2) { 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 new_insn = BREAKINST_ARM; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = swap_insn(task, addr, &dbg->bp[nr].insn, &new_insn, 4); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res == 4) { 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg->bp[nr].address = addr; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg->nsaved += 1; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "ptrace: too many breakpoints\n"); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear one breakpoint in the user program. We copy what the hardware 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does and use bit 0 of the address to indicate whether this is a Thumb 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * breakpoint or an ARM breakpoint. 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void clear_breakpoint(struct task_struct *task, struct debug_entry *bp) 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long addr = bp->address; 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union debug_insn old_insn; 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (addr & 1) { 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = swap_insn(task, addr & ~1, &old_insn.thumb, 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bp->insn.thumb, 2); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != 2 || old_insn.thumb != BREAKINST_THUMB) 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s:%d: corrupted Thumb breakpoint at " 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "0x%08lx (0x%04x)\n", task->comm, task->pid, 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr, old_insn.thumb); 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = swap_insn(task, addr & ~3, &old_insn.arm, 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bp->insn.arm, 4); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != 4 || old_insn.arm != BREAKINST_ARM) 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s:%d: corrupted ARM breakpoint at " 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "0x%08lx (0x%08x)\n", task->comm, task->pid, 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr, old_insn.arm); 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_set_bpt(struct task_struct *child) 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pt_regs *regs; 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long pc; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 insn; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs = get_user_regs(child); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc = instruction_pointer(regs); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (thumb_mode(regs)) { 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "ptrace: can't handle thumb mode\n"); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = read_instr(child, pc, &insn); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!res) { 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct debug_info *dbg = &child->thread.debug; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long alt; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg->nsaved = 0; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alt = get_branch_address(child, pc, insn); 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (alt) 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_breakpoint(child, dbg, alt); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that we ignore the result of setting the above 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * breakpoint since it may fail. When it does, this is 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not so much an error, but a forewarning that we may 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be receiving a prefetch abort shortly. 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we don't set this breakpoint here, then we can 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lose control of the thread during single stepping. 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!alt || predicate(insn) != PREDICATE_ALWAYS) 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_breakpoint(child, dbg, pc + 4); 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ensure no single-step breakpoint is pending. Returns non-zero 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * value if child was being single-stepped. 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_cancel_bpt(struct task_struct *child) 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, nsaved = child->thread.debug.nsaved; 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child->thread.debug.nsaved = 0; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nsaved > 2) { 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nsaved = 2; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < nsaved; i++) 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_breakpoint(child, &child->thread.debug.bp[i]); 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called by kernel/ptrace.c when detaching.. 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make sure the single step bit is not set. 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_disable(struct task_struct *child) 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child->ptrace &= ~PT_SINGLESTEP; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_cancel_bpt(child); 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle hitting a breakpoint. 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ptrace_break(struct task_struct *tsk, struct pt_regs *regs) 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds siginfo_t info; 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_cancel_bpt(tsk); 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_signo = SIGTRAP; 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_errno = 0; 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_code = TRAP_BRKPT; 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.si_addr = (void __user *)instruction_pointer(regs); 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds force_sig_info(SIGTRAP, &info, tsk); 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int break_trap(struct pt_regs *regs, unsigned int instr) 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_break(current, regs); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct undef_hook arm_break_hook = { 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_mask = 0x0fffffff, 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_val = 0x07f001f0, 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_mask = PSR_T_BIT, 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_val = 0, 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fn = break_trap, 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct undef_hook thumb_break_hook = { 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_mask = 0xffff, 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .instr_val = 0xde01, 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_mask = PSR_T_BIT, 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cpsr_val = PSR_T_BIT, 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fn = break_trap, 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ptrace_break_init(void) 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_undef_hook(&arm_break_hook); 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_undef_hook(&thumb_break_hook); 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscore_initcall(ptrace_break_init); 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read the word at offset "off" into the "struct user". We 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * actually access the pt_regs stored on the kernel stack. 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_read_user(struct task_struct *tsk, unsigned long off, 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long __user *ret) 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long tmp; 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off & 3 || off >= sizeof(struct user)) 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = 0; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off < sizeof(struct pt_regs)) 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = get_user_reg(tsk, off >> 2); 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user(tmp, ret); 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write the word at offset "off" into "struct user". We 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * actually access the pt_regs stored on the kernel stack. 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_write_user(struct task_struct *tsk, unsigned long off, 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val) 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off & 3 || off >= sizeof(struct user)) 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (off >= sizeof(struct pt_regs)) 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user_reg(tsk, off >> 2, val); 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get all user integer registers. 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_getregs(struct task_struct *tsk, void __user *uregs) 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pt_regs *regs = get_user_regs(tsk); 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set all user integer registers. 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_setregs(struct task_struct *tsk, void __user *uregs) 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pt_regs newregs; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EFAULT; 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) { 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pt_regs *regs = get_user_regs(tsk); 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (valid_user_regs(&newregs)) { 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *regs = newregs; 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get the child FPU state. 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_getfpregs(struct task_struct *tsk, void __user *ufp) 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return copy_to_user(ufp, &tsk->thread_info->fpstate, 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct user_fp)) ? -EFAULT : 0; 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the child FPU state. 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_setfpregs(struct task_struct *tsk, void __user *ufp) 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct thread_info *thread = tsk->thread_info; 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds thread->used_cp[1] = thread->used_cp[2] = 1; 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return copy_from_user(&thread->fpstate, ufp, 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct user_fp)) ? -EFAULT : 0; 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IWMMXT 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get the child iWMMXt state. 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_getwmmxregs(struct task_struct *tsk, void __user *ufp) 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct thread_info *thread = tsk->thread_info; 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *ptr = &thread->fpstate; 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT)) 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODATA; 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwmmxt_task_disable(thread); /* force it to ram */ 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The iWMMXt state is stored doubleword-aligned. */ 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((long) ptr) & 4) 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptr += 4; 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return copy_to_user(ufp, ptr, 0x98) ? -EFAULT : 0; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the child iWMMXt state. 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ptrace_setwmmxregs(struct task_struct *tsk, void __user *ufp) 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct thread_info *thread = tsk->thread_info; 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *ptr = &thread->fpstate; 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT)) 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EACCES; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwmmxt_task_release(thread); /* force a reload */ 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The iWMMXt state is stored doubleword-aligned. */ 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((long) ptr) & 4) 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptr += 4; 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return copy_from_user(ptr, ufp, 0x98) ? -EFAULT : 0; 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_ptrace(int request, struct task_struct *child, long addr, long data) 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long tmp; 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (request) { 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read word at location "addr" in the child process. 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_PEEKTEXT: 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_PEEKDATA: 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(child, addr, &tmp, 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(unsigned long), 0); 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret == sizeof(unsigned long)) 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = put_user(tmp, (unsigned long __user *) data); 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EIO; 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_PEEKUSR: 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_read_user(child, addr, (unsigned long __user *)data); 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write the word at location addr. 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_POKETEXT: 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_POKEDATA: 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = access_process_vm(child, addr, &data, 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(unsigned long), 1); 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret == sizeof(unsigned long)) 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EIO; 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_POKEUSR: 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_write_user(child, addr, data); 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * continue/restart and stop at next (return from) syscall 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SYSCALL: 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_CONT: 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EIO; 6977ed20e1ad521b5f5df61bf6559ae60738e393741Jesper Juhl if (!valid_signal(data)) 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request == PTRACE_SYSCALL) 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child->exit_code = data; 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* make sure single-step breakpoint is gone. */ 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child->ptrace &= ~PT_SINGLESTEP; 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_cancel_bpt(child); 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_process(child); 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * make the child exit. Best I can do is send it a sigkill. 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * perhaps it should be put in the status that it wants to 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exit. 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_KILL: 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* make sure single-step breakpoint is gone. */ 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child->ptrace &= ~PT_SINGLESTEP; 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_cancel_bpt(child); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (child->exit_state != EXIT_ZOMBIE) { 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child->exit_code = SIGKILL; 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_process(child); 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * execute single instruction. 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SINGLESTEP: 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EIO; 7327ed20e1ad521b5f5df61bf6559ae60738e393741Jesper Juhl if (!valid_signal(data)) 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child->ptrace |= PT_SINGLESTEP; 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child->exit_code = data; 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* give it a chance to run. */ 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_process(child); 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_DETACH: 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_detach(child, data); 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GETREGS: 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_getregs(child, (void __user *)data); 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SETREGS: 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_setregs(child, (void __user *)data); 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GETFPREGS: 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_getfpregs(child, (void __user *)data); 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SETFPREGS: 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_setfpregs(child, (void __user *)data); 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IWMMXT 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GETWMMXREGS: 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_getwmmxregs(child, (void __user *)data); 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_SETWMMXREGS: 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_setwmmxregs(child, (void __user *)data); 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PTRACE_GET_THREAD_AREA: 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = put_user(child->thread_info->tp_value, 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long __user *) data); 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_request(child, request, addr, data); 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage int sys_ptrace(long request, long pid, long addr, long data) 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct task_struct *child; 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lock_kernel(); 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EPERM; 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request == PTRACE_TRACEME) { 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* are we already being traced? */ 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (current->ptrace & PT_PTRACED) 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = security_ptrace(current->parent, current); 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set the ptrace bit in the process flags. */ 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current->ptrace |= PT_PTRACED; 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ESRCH; 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_lock(&tasklist_lock); 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child = find_task_by_pid(pid); 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (child) 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_task_struct(child); 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&tasklist_lock); 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!child) 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EPERM; 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pid == 1) /* you may not mess with init */ 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_tsk; 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request == PTRACE_ATTACH) { 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_attach(child); 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_tsk; 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ptrace_check_attach(child, request == PTRACE_KILL); 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret == 0) 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = do_ptrace(request, child, addr, data); 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_tsk: 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_task_struct(child); 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unlock_kernel(); 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage void syscall_trace(int why, struct pt_regs *regs) 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long ip; 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_thread_flag(TIF_SYSCALL_TRACE)) 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(current->ptrace & PT_PTRACED)) 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Save IP. IP is used to denote syscall entry/exit: 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IP = 0 -> entry, = 1 -> exit 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip = regs->ARM_ip; 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->ARM_ip = why; 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* the 0x80 provides a way for the tracing parent to distinguish 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds between a syscall stop and SIGTRAP delivery */ 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? 0x80 : 0)); 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this isn't the same as continuing with a signal, but it will do 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for normal use. strace only continues with a signal if the 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stopping signal is not SIGTRAP. -brl 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (current->exit_code) { 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_sig(current->exit_code, current, 1); 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current->exit_code = 0; 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->ARM_ip = ip; 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 863