Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * linux/arch/h8300/platform/h8s/ptrace_h8s.c |
| 3 | * ptrace cpu depend helper functions |
| 4 | * |
| 5 | * Yoshinori Sato <ysato@users.sourceforge.jp> |
| 6 | * |
| 7 | * This file is subject to the terms and conditions of the GNU General |
| 8 | * Public License. See the file COPYING in the main directory of |
| 9 | * this archive for more details. |
| 10 | */ |
| 11 | |
| 12 | #include <linux/linkage.h> |
| 13 | #include <linux/sched.h> |
| 14 | #include <linux/errno.h> |
| 15 | #include <asm/ptrace.h> |
| 16 | |
| 17 | #define CCR_MASK 0x6f |
| 18 | #define EXR_TRACE 0x80 |
| 19 | |
| 20 | /* Mapping from PT_xxx to the stack offset at which the register is |
| 21 | saved. Notice that usp has no stack-slot and needs to be treated |
| 22 | specially (see get_reg/put_reg below). */ |
| 23 | static const int h8300_register_offset[] = { |
| 24 | PT_REG(er1), PT_REG(er2), PT_REG(er3), PT_REG(er4), |
| 25 | PT_REG(er5), PT_REG(er6), PT_REG(er0), PT_REG(orig_er0), |
| 26 | PT_REG(ccr), PT_REG(pc), 0, PT_REG(exr) |
| 27 | }; |
| 28 | |
| 29 | /* read register */ |
| 30 | long h8300_get_reg(struct task_struct *task, int regno) |
| 31 | { |
| 32 | switch (regno) { |
| 33 | case PT_USP: |
| 34 | return task->thread.usp + sizeof(long)*2 + 2; |
| 35 | case PT_CCR: |
| 36 | case PT_EXR: |
| 37 | return *(unsigned short *)(task->thread.esp0 + h8300_register_offset[regno]); |
| 38 | default: |
| 39 | return *(unsigned long *)(task->thread.esp0 + h8300_register_offset[regno]); |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | /* write register */ |
| 44 | int h8300_put_reg(struct task_struct *task, int regno, unsigned long data) |
| 45 | { |
| 46 | unsigned short oldccr; |
| 47 | switch (regno) { |
| 48 | case PT_USP: |
| 49 | task->thread.usp = data - sizeof(long)*2 - 2; |
| 50 | case PT_CCR: |
| 51 | oldccr = *(unsigned short *)(task->thread.esp0 + h8300_register_offset[regno]); |
| 52 | oldccr &= ~CCR_MASK; |
| 53 | data &= CCR_MASK; |
| 54 | data |= oldccr; |
| 55 | *(unsigned short *)(task->thread.esp0 + h8300_register_offset[regno]) = data; |
| 56 | break; |
| 57 | case PT_EXR: |
| 58 | /* exr modify not support */ |
| 59 | return -EIO; |
| 60 | default: |
| 61 | *(unsigned long *)(task->thread.esp0 + h8300_register_offset[regno]) = data; |
| 62 | break; |
| 63 | } |
| 64 | return 0; |
| 65 | } |
| 66 | |
| 67 | /* disable singlestep */ |
Christoph Hellwig | 857fb25 | 2010-03-10 15:22:52 -0800 | [diff] [blame^] | 68 | void user_disable_single_step(struct task_struct *child) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 69 | { |
| 70 | *(unsigned short *)(child->thread.esp0 + h8300_register_offset[PT_EXR]) &= ~EXR_TRACE; |
| 71 | } |
| 72 | |
| 73 | /* enable singlestep */ |
Christoph Hellwig | 857fb25 | 2010-03-10 15:22:52 -0800 | [diff] [blame^] | 74 | void user_enable_single_step(struct task_struct *child) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 75 | { |
| 76 | *(unsigned short *)(child->thread.esp0 + h8300_register_offset[PT_EXR]) |= EXR_TRACE; |
| 77 | } |
| 78 | |
| 79 | asmlinkage void trace_trap(unsigned long bp) |
| 80 | { |
| 81 | (void)bp; |
| 82 | force_sig(SIGTRAP,current); |
| 83 | } |
| 84 | |