Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | /* * linux/arch/h8300/kernel/ptrace.c * * Yoshinori Sato <ysato@users.sourceforge.jp> * * Based on: * linux/arch/m68k/kernel/ptrace.c * * Copyright (C) 1994 by Hamish Macdonald * Taken from linux/kernel/ptrace.c and modified for M680x0. * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds * * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of * this archive for more details. */ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/smp.h> #include <linux/errno.h> #include <linux/ptrace.h> #include <linux/user.h> #include <linux/signal.h> #include <asm/uaccess.h> #include <asm/page.h> #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/signal.h> /* cpu depend functions */ extern long h8300_get_reg(struct task_struct *task, int regno); extern int h8300_put_reg(struct task_struct *task, int regno, unsigned long data); void user_disable_single_step(struct task_struct *child) { } /* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. */ void ptrace_disable(struct task_struct *child) { user_disable_single_step(child); } long arch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { int ret; int regno = addr >> 2; unsigned long __user *datap = (unsigned long __user *) data; switch (request) { /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsigned long tmp = 0; if ((addr & 3) || addr >= sizeof(struct user)) { ret = -EIO; break ; } ret = 0; /* Default return condition */ if (regno < H8300_REGS_NO) tmp = h8300_get_reg(child, regno); else { switch (regno) { case 49: tmp = child->mm->start_code; break ; case 50: tmp = child->mm->start_data; break ; case 51: tmp = child->mm->end_code; break ; case 52: tmp = child->mm->end_data; break ; default: ret = -EIO; } } if (!ret) ret = put_user(tmp, datap); break ; } /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ if ((addr & 3) || addr >= sizeof(struct user)) { ret = -EIO; break ; } if (regno == PT_ORIG_ER0) { ret = -EIO; break ; } if (regno < H8300_REGS_NO) { ret = h8300_put_reg(child, regno, data); break ; } ret = -EIO; break ; case PTRACE_GETREGS: { /* Get all gp regs from the child. */ int i; unsigned long tmp; for (i = 0; i < H8300_REGS_NO; i++) { tmp = h8300_get_reg(child, i); if (put_user(tmp, datap)) { ret = -EFAULT; break; } datap++; } ret = 0; break; } case PTRACE_SETREGS: { /* Set all gp regs in the child. */ int i; unsigned long tmp; for (i = 0; i < H8300_REGS_NO; i++) { if (get_user(tmp, datap)) { ret = -EFAULT; break; } h8300_put_reg(child, i, tmp); datap++; } ret = 0; break; } default: ret = ptrace_request(child, request, addr, data); break; } return ret; } asmlinkage void do_syscall_trace(void) { if (!test_thread_flag(TIF_SYSCALL_TRACE)) return; if (!(current->ptrace & PT_PTRACED)) return; ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); /* * this isn't the same as continuing with a signal, but it will do * for normal use. strace only continues with a signal if the * stopping signal is not SIGTRAP. -brl */ if (current->exit_code) { send_sig(current->exit_code, current, 1); current->exit_code = 0; } } |