1/* 2 * linux/arch/h8300/kernel/ptrace.c 3 * 4 * Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp> 5 * 6 * This file is subject to the terms and conditions of the GNU General 7 * Public License. See the file COPYING in the main directory of 8 * this archive for more details. 9 */ 10 11#include <linux/kernel.h> 12#include <linux/errno.h> 13#include <linux/ptrace.h> 14#include <linux/audit.h> 15#include <linux/tracehook.h> 16#include <linux/regset.h> 17#include <linux/elf.h> 18 19#define CCR_MASK 0x6f /* mode/imask not set */ 20#define EXR_MASK 0x80 /* modify only T */ 21 22#define PT_REG(r) offsetof(struct pt_regs, r) 23 24extern void user_disable_single_step(struct task_struct *child); 25 26/* Mapping from PT_xxx to the stack offset at which the register is 27 saved. Notice that usp has no stack-slot and needs to be treated 28 specially (see get_reg/put_reg below). */ 29static const int register_offset[] = { 30 PT_REG(er1), PT_REG(er2), PT_REG(er3), PT_REG(er4), 31 PT_REG(er5), PT_REG(er6), PT_REG(er0), -1, 32 PT_REG(orig_er0), PT_REG(ccr), PT_REG(pc), 33#if defined(CONFIG_CPU_H8S) 34 PT_REG(exr), 35#endif 36}; 37 38/* read register */ 39long h8300_get_reg(struct task_struct *task, int regno) 40{ 41 switch (regno) { 42 case PT_USP: 43 return task->thread.usp + sizeof(long)*2; 44 case PT_CCR: 45 case PT_EXR: 46 return *(unsigned short *)(task->thread.esp0 + 47 register_offset[regno]); 48 default: 49 return *(unsigned long *)(task->thread.esp0 + 50 register_offset[regno]); 51 } 52} 53 54int h8300_put_reg(struct task_struct *task, int regno, unsigned long data) 55{ 56 unsigned short oldccr; 57 unsigned short oldexr; 58 59 switch (regno) { 60 case PT_USP: 61 task->thread.usp = data - sizeof(long)*2; 62 case PT_CCR: 63 oldccr = *(unsigned short *)(task->thread.esp0 + 64 register_offset[regno]); 65 oldccr &= ~CCR_MASK; 66 data &= CCR_MASK; 67 data |= oldccr; 68 *(unsigned short *)(task->thread.esp0 + 69 register_offset[regno]) = data; 70 break; 71 case PT_EXR: 72 oldexr = *(unsigned short *)(task->thread.esp0 + 73 register_offset[regno]); 74 oldccr &= ~EXR_MASK; 75 data &= EXR_MASK; 76 data |= oldexr; 77 *(unsigned short *)(task->thread.esp0 + 78 register_offset[regno]) = data; 79 break; 80 default: 81 *(unsigned long *)(task->thread.esp0 + 82 register_offset[regno]) = data; 83 break; 84 } 85 return 0; 86} 87 88static int regs_get(struct task_struct *target, 89 const struct user_regset *regset, 90 unsigned int pos, unsigned int count, 91 void *kbuf, void __user *ubuf) 92{ 93 int r; 94 struct user_regs_struct regs; 95 long *reg = (long *)®s; 96 97 /* build user regs in buffer */ 98 for (r = 0; r < ARRAY_SIZE(register_offset); r++) 99 *reg++ = h8300_get_reg(target, r); 100 101 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 102 ®s, 0, sizeof(regs)); 103} 104 105static int regs_set(struct task_struct *target, 106 const struct user_regset *regset, 107 unsigned int pos, unsigned int count, 108 const void *kbuf, const void __user *ubuf) 109{ 110 int r; 111 int ret; 112 struct user_regs_struct regs; 113 long *reg; 114 115 /* build user regs in buffer */ 116 for (reg = (long *)®s, r = 0; r < ARRAY_SIZE(register_offset); r++) 117 *reg++ = h8300_get_reg(target, r); 118 119 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 120 ®s, 0, sizeof(regs)); 121 if (ret) 122 return ret; 123 124 /* write back to pt_regs */ 125 for (reg = (long *)®s, r = 0; r < ARRAY_SIZE(register_offset); r++) 126 h8300_put_reg(target, r, *reg++); 127 return 0; 128} 129 130enum h8300_regset { 131 REGSET_GENERAL, 132}; 133 134static const struct user_regset h8300_regsets[] = { 135 [REGSET_GENERAL] = { 136 .core_note_type = NT_PRSTATUS, 137 .n = ELF_NGREG, 138 .size = sizeof(long), 139 .align = sizeof(long), 140 .get = regs_get, 141 .set = regs_set, 142 }, 143}; 144 145static const struct user_regset_view user_h8300_native_view = { 146 .name = "h8300", 147 .e_machine = EM_H8_300, 148 .regsets = h8300_regsets, 149 .n = ARRAY_SIZE(h8300_regsets), 150}; 151 152const struct user_regset_view *task_user_regset_view(struct task_struct *task) 153{ 154 return &user_h8300_native_view; 155} 156 157void ptrace_disable(struct task_struct *child) 158{ 159 user_disable_single_step(child); 160} 161 162long arch_ptrace(struct task_struct *child, long request, 163 unsigned long addr, unsigned long data) 164{ 165 int ret; 166 167 switch (request) { 168 default: 169 ret = ptrace_request(child, request, addr, data); 170 break; 171 } 172 return ret; 173} 174 175asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) 176{ 177 long ret = 0; 178 179 if (test_thread_flag(TIF_SYSCALL_TRACE) && 180 tracehook_report_syscall_entry(regs)) 181 /* 182 * Tracing decided this syscall should not happen. 183 * We'll return a bogus call number to get an ENOSYS 184 * error, but leave the original number in regs->regs[0]. 185 */ 186 ret = -1L; 187 188 audit_syscall_entry(regs->er1, regs->er2, regs->er3, 189 regs->er4, regs->er5); 190 191 return ret ?: regs->er0; 192} 193 194asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) 195{ 196 int step; 197 198 audit_syscall_exit(regs); 199 200 step = test_thread_flag(TIF_SINGLESTEP); 201 if (step || test_thread_flag(TIF_SYSCALL_TRACE)) 202 tracehook_report_syscall_exit(regs, step); 203} 204