[PATCH] H8/300 support update (1/3) - ptrace fix

Yoshinori Sato
2004-04-06T11:05:12Z

- fix PTRACE_SIGLESTEP bug.
- separate to CPU depend.

--
Yoshinori Sato
<ysato@users.sourceforge.jp>

diff -Nru -X .exclude-diff linux-2.6.5/arch/h8300/kernel/ptrace.c linux-2.6.5-h8300/arch/h8300/kernel/ptrace.c
--- linux-2.6.5/arch/h8300/kernel/ptrace.c 2004-01-09 15:59:19.000000000 +0900
+++ linux-2.6.5-h8300/arch/h8300/kernel/ptrace.c 2004-03-25 21:30:46.000000000 +0900
@@ -1,7 +1,7 @@
/*
* linux/arch/h8300/kernel/ptrace.c
*
- * Yoshinori Sato <qzb04471@nifty.ne.jp>
+ * Yoshinori Sato <ysato@users.sourceforge.jp>
*
* Based on:
* linux/arch/m68k/kernel/ptrace.c
@@ -32,194 +32,17 @@
#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);
+extern void h8300_disable_trace(struct task_struct *child);
+extern void h8300_enable_trace(struct task_struct *child);
+
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
*/

-/* determines which bits in the SR the user has access to. */
-/* 1 = access 0 = no access */
-#define SR_MASK 0x001f
-
-/* sets the trace bits. */
-#define TRACE_BITS 0x8000
-
-/* Find the stack offset for a register, relative to thread.esp0. */
-#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
-/* Mapping from PT_xxx to the stack offset at which the register is
- saved. Notice that usp has no stack-slot and needs to be treated
- specially (see get_reg/put_reg below). */
-static const int regoff[] = {
- PT_REG(er1), PT_REG(er2), PT_REG(er3), PT_REG(er4),
- PT_REG(er5), PT_REG(er6), PT_REG(er0), PT_REG(orig_er0),
- PT_REG(ccr), PT_REG(pc)
-};
-
-/*
- * Get contents of register REGNO in task TASK.
- */
-static inline long get_reg(struct task_struct *task, int regno)
-{
- unsigned long *addr;
-
- if (regno == PT_USP)
- addr = &task->thread.usp;
- else if (regno < sizeof(regoff)/sizeof(regoff[0]))
- addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
- else
- return 0;
- return *addr;
-}
-
-/*
- * Write contents of register REGNO in task TASK.
- */
-static inline int put_reg(struct task_struct *task, int regno,
- unsigned long data)
-{
- unsigned long *addr;
-
- if (regno == PT_USP)
- addr = &task->thread.usp;
- else if (regno < sizeof(regoff)/sizeof(regoff[0]))
- addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
- else
- return -1;
- *addr = data;
- return 0;
-}
-
-/*
- * Called by kernel/ptrace.c when detaching..
- *
- * Make sure the single step bit is not set.
- */
-int ptrace_cancel_bpt(struct task_struct *child)
-{
- int i,r=0;
-
- for(i=0; i<4; i++) {
- if (child->thread.debugreg[i]) {
- if (child->thread.debugreg[i] != ~0)
- put_user(child->thread.debugreg[i+4],
- (unsigned short *)child->thread.debugreg[i]);
- r = 1;
- child->thread.debugreg[i] = 0;
- }
- }
- return r;
-}
-
-const static unsigned char opcode0[]={
- 0x04,0x02,0x04,0x02,0x04,0x02,0x04,0x02, /* 0x58 */
- 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, /* 0x60 */
- 0x02,0x02,0x11,0x11,0x02,0x02,0x04,0x04, /* 0x68 */
- 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, /* 0x70 */
- 0x08,0x04,0x06,0x04,0x04,0x04,0x04,0x04}; /* 0x78 */
-
-const static int table_parser01(unsigned char *pc);
-const static int table_parser02(unsigned char *pc);
-const static int table_parser100(unsigned char *pc);
-const static int table_parser101(unsigned char *pc);
-
-const static int (*parsers[])(unsigned char *pc)={table_parser01,table_parser02};
-
-static int insn_length(unsigned char *pc)
-{
- if (*pc == 0x01)
- return table_parser01(pc+1);
- if (*pc < 0x58 || *pc>=0x80)
- return 2;
- else
- if (opcode0[*pc-0x58]<0x10)
- return opcode0[*pc-0x58];
- else
- return (*parsers[opcode0[*pc-0x58]-0x10])(pc+1);
-}
-
-const static int table_parser01(unsigned char *pc)
-{
- const unsigned char codelen[]={0x10,0x00,0x00,0x00,0x11,0x00,0x00,0x00,
- 0x02,0x00,0x00,0x00,0x04,0x04,0x00,0x04};
- const static int (*parsers[])(unsigned char *)={table_parser100,table_parser101};
- unsigned char second_index;
- second_index = (*pc) >> 4;
- if (codelen[second_index]<0x10)
- return codelen[second_index];
- else
- return parsers[codelen[second_index]-0x10](pc);
-}
-
-const static int table_parser02(unsigned char *pc)
-{
- return (*pc & 0x20)?0x06:0x04;
-}
-
-const static int table_parser100(unsigned char *pc)
-{
- return (*(pc+2) & 0x02)?0x08:0x06;
-}
-
-const static int table_parser101(unsigned char *pc)
-{
- return (*(pc+2) & 0x02)?0x08:0x06;
-}
-
-#define BREAK_INST 0x5730 /* TRAPA #3 */
-
-int ptrace_set_bpt(struct task_struct *child)
-{
- unsigned long pc,next;
- unsigned short insn;
- pc = get_reg(child,PT_PC);
- next = insn_length((unsigned char *)pc) + pc;
- get_user(insn,(unsigned short *)pc);
- if (insn == 0x5470) {
- /* rts */
- unsigned long sp;
- sp = get_reg(child,PT_USP);
- get_user(next,(unsigned long *)sp);
- } else if ((insn & 0xfb00) != 0x5800) {
- /* jmp / jsr */
- int regs;
- const short reg_tbl[]={PT_ER0,PT_ER1,PT_ER2,PT_ER3,
- PT_ER4,PT_ER5,PT_ER6,PT_USP};
- switch(insn & 0xfb00) {
- case 0x5900:
- regs = (insn & 0x0070) >> 8;
- next = get_reg(child,reg_tbl[regs]);
- break;
- case 0x5a00:
- get_user(next,(unsigned long *)(pc+2));
- next &= 0x00ffffff;
- break;
- case 0x5b00:
- /* unneccessary? */
- next = *(unsigned long *)(insn & 0xff);
- break;
- }
- } else if (((insn & 0xf000) == 0x4000) || ((insn &0xff00) == 0x5500)) {
- /* b**:8 */
- unsigned long dsp;
- dsp = (long)(insn && 0xff)+pc+2;
- child->thread.debugreg[1] = dsp;
- get_user(child->thread.debugreg[5],(unsigned short *)dsp);
- put_user(BREAK_INST,(unsigned short *)dsp);
- } else if (((insn & 0xff00) == 0x5800) || ((insn &0xff00) == 0x5c00)) {
- /* b**:16 */
- unsigned long dsp;
- get_user(dsp,(unsigned short *)(pc+2));
- dsp = (long)dsp+pc+4;
- child->thread.debugreg[1] = dsp;
- get_user(child->thread.debugreg[5],(unsigned short *)dsp);
- put_user(BREAK_INST,(unsigned short *)dsp);
- }
- child->thread.debugreg[0] = next;
- get_user(child->thread.debugreg[4],(unsigned short *)next);
- put_user(BREAK_INST,(unsigned short *)next);
- return 0;
-}
-
inline
static int read_long(struct task_struct * tsk, unsigned long addr,
unsigned long * result)
@@ -230,7 +53,7 @@

void ptrace_disable(struct task_struct *child)
{
- ptrace_cancel_bpt(child);
+ h8300_disable_trace(child);
}

asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
@@ -298,8 +121,8 @@

tmp = 0; /* Default return condition */
addr = addr >> 2; /* temporary hack. */
- if (addr < 10)
- tmp = get_reg(child, addr);
+ if (addr < H8300_REGS_NO)
+ tmp = h8300_get_reg(child, addr);
else {
ret = -EIO;
break ;
@@ -328,14 +151,8 @@
ret = -EIO;
break ;
}
- if (addr == PT_CCR) {
- data &= SR_MASK;
- }
- if (addr < 10) {
- if (put_reg(child, addr, data))
- ret = -EIO;
- else
- ret = 0;
+ if (addr < H8300_REGS_NO) {
+ ret = h8300_put_reg(child, addr, data);
break ;
}
ret = -EIO;
@@ -352,7 +169,7 @@
child->exit_code = data;
wake_up_process(child);
/* make sure the single step bit is not set. */
- ptrace_cancel_bpt(child);
+ h8300_disable_trace(child);
ret = 0;
}

@@ -367,7 +184,7 @@
if (child->state == TASK_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
- ptrace_cancel_bpt(child);
+ h8300_disable_trace(child);
wake_up_process(child);
break;
}
@@ -377,8 +194,8 @@
if ((unsigned long) data > _NSIG)
break;
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- child->thread.debugreg[0]=-1;
child->exit_code = data;
+ h8300_enable_trace(child);
wake_up_process(child);
ret = 0;
break;
@@ -391,8 +208,8 @@
case PTRACE_GETREGS: { /* Get all gp regs from the child. */
int i;
unsigned long tmp;
- for (i = 0; i < 19; i++) {
- tmp = get_reg(child, i);
+ for (i = 0; i < H8300_REGS_NO; i++) {
+ tmp = h8300_get_reg(child, i);
if (put_user(tmp, (unsigned long *) data)) {
ret = -EFAULT;
break;
@@ -406,12 +223,12 @@
case PTRACE_SETREGS: { /* Set all gp regs in the child. */
int i;
unsigned long tmp;
- for (i = 0; i < 10; i++) {
+ for (i = 0; i < H8300_REGS_NO; i++) {
if (get_user(tmp, (unsigned long *) data)) {
ret = -EFAULT;
break;
}
- put_reg(child, i, tmp);
+ h8300_put_reg(child, i, tmp);
data += sizeof(long);
}
ret = 0;
@@ -449,13 +266,3 @@
current->exit_code = 0;
}
}
-
-asmlinkage void trace_trap(unsigned long bp)
-{
- if (current->thread.debugreg[0] == bp ||
- current->thread.debugreg[1] == bp) {
- ptrace_cancel_bpt(current);
- force_sig(SIGTRAP,current);
- } else
- force_sig(SIGILL,current);
-}
diff -Nru -X .exclude-diff linux-2.6.5/arch/h8300/platform/h8300h/Makefile linux-2.6.5-h8300/arch/h8300/platform/h8300h/Makefile
--- linux-2.6.5/arch/h8300/platform/h8300h/Makefile 2004-04-06 17:11:10.000000000 +0900
+++ linux-2.6.5-h8300/arch/h8300/platform/h8300h/Makefile 2004-03-23 23:42:00.000000000 +0900
@@ -4,5 +4,4 @@
# Reuse any files we can from the H8/300H
#

-obj-y := entry.o ints_h8300h.o
-
+obj-y := entry.o ints_h8300h.o ptrace_h8300h.o
diff -Nru -X .exclude-diff linux-2.6.5/arch/h8300/platform/h8300h/ptrace_h8300h.c linux-2.6.5-h8300/arch/h8300/platform/h8300h/ptrace_h8300h.c
--- linux-2.6.5/arch/h8300/platform/h8300h/ptrace_h8300h.c 1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.5-h8300/arch/h8300/platform/h8300h/ptrace_h8300h.c 2004-03-23 23:42:00.000000000 +0900
@@ -0,0 +1,282 @@
+/*
+ * linux/arch/h8300/platform/h8300h/ptrace_h8300h.c
+ * ptrace cpu depend helper functions
+ *
+ * Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * 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/linkage.h>
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+
+#define CCR_MASK 0x6f /* mode/imask not set */
+#define BREAKINST 0x5730 /* trapa #3 */
+
+/* Mapping from PT_xxx to the stack offset at which the register is
+ saved. Notice that usp has no stack-slot and needs to be treated
+ specially (see get_reg/put_reg below). */
+static const int h8300_register_offset[] = {
+ PT_REG(er1), PT_REG(er2), PT_REG(er3), PT_REG(er4),
+ PT_REG(er5), PT_REG(er6), PT_REG(er0), PT_REG(orig_er0),
+ PT_REG(ccr), PT_REG(pc)
+};
+
+/* read register */
+long h8300_get_reg(struct task_struct *task, int regno)
+{
+ switch (regno) {
+ case PT_USP:
+ return task->thread.usp + sizeof(long)*2;
+ case PT_CCR:
+ return *(unsigned short *)(task->thread.esp0 + h8300_register_offset[regno]);
+ default:
+ return *(unsigned long *)(task->thread.esp0 + h8300_register_offset[regno]);
+ }
+}
+
+/* write register */
+int h8300_put_reg(struct task_struct *task, int regno, unsigned long data)
+{
+ unsigned short oldccr;
+ switch (regno) {
+ case PT_USP:
+ task->thread.usp = data - sizeof(long)*2;
+ case PT_CCR:
+ oldccr = *(unsigned short *)(task->thread.esp0 + h8300_register_offset[regno]);
+ oldccr &= ~CCR_MASK;
+ data &= CCR_MASK;
+ data |= oldccr;
+ *(unsigned short *)(task->thread.esp0 + h8300_register_offset[regno]) = data;
+ break;
+ default:
+ *(unsigned long *)(task->thread.esp0 + h8300_register_offset[regno]) = data;
+ break;
+ }
+ return 0;
+}
+
+/* disable singlestep */
+void h8300_disable_trace(struct task_struct *child)
+{
+ if((long)child->thread.breakinfo.addr != -1L) {
+ *child->thread.breakinfo.addr = child->thread.breakinfo.inst;
+ child->thread.breakinfo.addr = (unsigned short *)-1L;
+ }
+}
+
+/* calculate next pc */
+enum jump_type {none, /* normal instruction */
+ jabs, /* absolute address jump */
+ ind, /* indirect address jump */
+ ret, /* return to subrutine */
+ reg, /* register indexed jump */
+ relb, /* pc relative jump (byte offset) */
+ relw, /* pc relative jump (word offset) */
+ };
+
+/* opcode decode table define
+ ptn: opcode pattern
+ msk: opcode bitmask
+ len: instruction length (<0 next table index)
+ jmp: jump operation mode */
+struct optable {
+ unsigned char bitpattern;
+ unsigned char bitmask;
+ signed char length;
+ signed char type;
+} __attribute__((aligned(1),packed));
+
+#define OPTABLE(ptn,msk,len,jmp) \
+ { \
+ .bitpattern = ptn, \
+ .bitmask = msk, \
+ .length = len, \
+ .type = jmp, \
+ }
+
+const static struct optable optable_0[] = {
+ OPTABLE(0x00,0xff, 1,none), /* 0x00 */
+ OPTABLE(0x01,0xff,-1,none), /* 0x01 */
+ OPTABLE(0x02,0xfe, 1,none), /* 0x02-0x03 */
+ OPTABLE(0x04,0xee, 1,none), /* 0x04-0x05/0x14-0x15 */
+ OPTABLE(0x06,0xfe, 1,none), /* 0x06-0x07 */
+ OPTABLE(0x08,0xea, 1,none), /* 0x08-0x09/0x0c-0x0d/0x18-0x19/0x1c-0x1d */
+ OPTABLE(0x0a,0xee, 1,none), /* 0x0a-0x0b/0x1a-0x1b */
+ OPTABLE(0x0e,0xee, 1,none), /* 0x0e-0x0f/0x1e-0x1f */
+ OPTABLE(0x10,0xfc, 1,none), /* 0x10-0x13 */
+ OPTABLE(0x16,0xfe, 1,none), /* 0x16-0x17 */
+ OPTABLE(0x20,0xe0, 1,none), /* 0x20-0x3f */
+ OPTABLE(0x40,0xf0, 1,relb), /* 0x40-0x4f */
+ OPTABLE(0x50,0xfc, 1,none), /* 0x50-0x53 */
+ OPTABLE(0x54,0xfd, 1,ret ), /* 0x54/0x56 */
+ OPTABLE(0x55,0xff, 1,relb), /* 0x55 */
+ OPTABLE(0x57,0xff, 1,none), /* 0x57 */
+ OPTABLE(0x58,0xfb, 2,relw), /* 0x58/0x5c */
+ OPTABLE(0x59,0xfb, 1,reg ), /* 0x59/0x5b */
+ OPTABLE(0x5a,0xfb, 2,jabs), /* 0x5a/0x5e */
+ OPTABLE(0x5b,0xfb, 2,ind ), /* 0x5b/0x5f */
+ OPTABLE(0x60,0xe8, 1,none), /* 0x60-0x67/0x70-0x77 */
+ OPTABLE(0x68,0xfa, 1,none), /* 0x68-0x69/0x6c-0x6d */
+ OPTABLE(0x6a,0xfe,-2,none), /* 0x6a-0x6b */
+ OPTABLE(0x6e,0xfe, 2,none), /* 0x6e-0x6f */
+ OPTABLE(0x78,0xff, 4,none), /* 0x78 */
+ OPTABLE(0x79,0xff, 2,none), /* 0x79 */
+ OPTABLE(0x7a,0xff, 3,none), /* 0x7a */
+ OPTABLE(0x7b,0xff, 2,none), /* 0x7b */
+ OPTABLE(0x7c,0xfc, 2,none), /* 0x7c-0x7f */
+ OPTABLE(0x80,0x80, 1,none), /* 0x80-0xff */
+};
+
+const static struct optable optable_1[] = {
+ OPTABLE(0x00,0xff,-3,none), /* 0x0100 */
+ OPTABLE(0x40,0xf0,-3,none), /* 0x0140-0x14f */
+ OPTABLE(0x80,0xf0, 1,none), /* 0x0180-0x018f */
+ OPTABLE(0xc0,0xc0, 2,none), /* 0x01c0-0x01ff */
+};
+
+const static struct optable optable_2[] = {
+ OPTABLE(0x00,0x20, 2,none), /* 0x6a0?/0x6a8?/0x6b0?/0x6b8? */
+ OPTABLE(0x20,0x20, 3,none), /* 0x6a2?/0x6aa?/0x6b2?/0x6ba? */
+};
+
+const static struct optable optable_3[] = {
+ OPTABLE(0x69,0xfb, 2,none), /* 0x010069/0x01006d/014069/0x01406d */
+ OPTABLE(0x6b,0xff,-4,none), /* 0x01006b/0x01406b */
+ OPTABLE(0x6f,0xff, 3,none), /* 0x01006f/0x01406f */
+ OPTABLE(0x78,0xff, 5,none), /* 0x010078/0x014078 */
+};
+
+const static struct optable optable_4[] = {
+ OPTABLE(0x00,0x78, 3,none), /* 0x0100690?/0x01006d0?/0140690/0x01406d0?/0x0100698?/0x01006d8?/0140698?/0x01406d8? */
+ OPTABLE(0x20,0x78, 4,none), /* 0x0100692?/0x01006d2?/0140692/0x01406d2?/0x010069a?/0x01006da?/014069a?/0x01406da? */
+};
+
+const static struct optables_list {
+ const struct optable *ptr;
+ int size;
+} optables[] = {
+#define OPTABLES(no) \
+ { \
+ .ptr = optable_##no, \
+ .size = sizeof(optable_##no) / sizeof(struct optable), \
+ }
+ OPTABLES(0),
+ OPTABLES(1),
+ OPTABLES(2),
+ OPTABLES(3),
+ OPTABLES(4),
+
+};
+
+const unsigned char condmask[] = {
+ 0x00,0x40,0x01,0x04,0x02,0x08,0x10,0x20
+};
+
+static int isbranch(struct task_struct *task,int reson)
+{
+ unsigned char cond = h8300_get_reg(task, PT_CCR);
+ /* encode complex conditions */
+ /* B4: N^V
+ B5: Z|(N^V)
+ B6: C|Z */
+ __asm__("bld #3,%w0\n\t"
+ "bxor #1,%w0\n\t"
+ "bst #4,%w0\n\t"
+ "bor #2,%w0\n\t"
+ "bst #5,%w0\n\t"
+ "bld #2,%w0\n\t"
+ "bor #0,%w0\n\t"
+ "bst #6,%w0\n\t"
+ :"=&r"(cond)::"cc");
+ cond &= condmask[reson >> 1];
+ if (!(reson & 1))
+ return cond == 0;
+ else
+ return cond != 0;
+}
+
+static unsigned short *getnextpc(struct task_struct *child, unsigned short *pc)
+{
+ const struct optable *op;
+ unsigned char *fetch_p;
+ unsigned char inst;
+ unsigned long addr;
+ unsigned long *sp;
+ int op_len,regno;
+ op = optables[0].ptr;
+ op_len = optables[0].size;
+ fetch_p = (unsigned char *)pc;
+ inst = *fetch_p++;
+ do {
+ if ((inst & op->bitmask) == op->bitpattern) {
+ if (op->length < 0) {
+ op = optables[-op->length].ptr;
+ op_len = optables[-op->length].size + 1;
+ inst = *fetch_p++;
+ } else {
+ switch (op->type) {
+ case none:
+ return pc + op->length;
+ case jabs:
+ addr = *(unsigned long *)pc;
+ return (unsigned short *)(addr & 0x00ffffff);
+ case ind:
+ addr = *pc & 0xff;
+ return (unsigned short *)(*(unsigned long *)addr);
+ case ret:
+ sp = (unsigned long *)h8300_get_reg(child, PT_USP);
+ /* user stack frames
+ | er0 | temporary saved
+ +--------+
+ | exp | exception stack frames
+ +--------+
+ | ret pc | userspace return address
+ */
+ return (unsigned short *)(*(sp+2) & 0x00ffffff);
+ case reg:
+ regno = (*pc >> 4) & 0x07;
+ if (regno == 0)
+ addr = h8300_get_reg(child, PT_ER0);
+ else
+ addr = h8300_get_reg(child, regno-1+PT_ER1);
+ return (unsigned short *)addr;
+ case relb:
+ if ((inst = 0x55) || isbranch(child,inst & 0x0f))
+ (unsigned char *)pc += (signed char)(*fetch_p);
+ return pc+1; /* skip myself */
+ case relw:
+ if ((inst = 0x5c) || isbranch(child,(*fetch_p & 0xf0) >> 4))
+ (unsigned char *)pc += (signed short)(*(pc+1));
+ return pc+2; /* skip myself */
+ }
+ }
+ } else
+ op++;
+ } while(--op_len > 0);
+ return NULL;
+}
+
+/* Set breakpoint(s) to simulate a single step from the current PC. */
+
+void h8300_enable_trace(struct task_struct *child)
+{
+ unsigned short *nextpc;
+ nextpc = getnextpc(child,(unsigned short *)h8300_get_reg(child, PT_PC));
+ child->thread.breakinfo.addr = nextpc;
+ child->thread.breakinfo.inst = *nextpc;
+ *nextpc = BREAKINST;
+}
+
+asmlinkage void trace_trap(unsigned long bp)
+{
+ if ((unsigned long)current->thread.breakinfo.addr == bp) {
+ h8300_disable_trace(current);
+ force_sig(SIGTRAP,current);
+ } else
+ force_sig(SIGILL,current);
+}
+
diff -Nru -X .exclude-diff linux-2.6.5/arch/h8300/platform/h8s/Makefile linux-2.6.5-h8300/arch/h8300/platform/h8s/Makefile
--- linux-2.6.5/arch/h8300/platform/h8s/Makefile 2004-04-06 17:11:10.000000000 +0900
+++ linux-2.6.5-h8300/arch/h8300/platform/h8s/Makefile 2004-03-23 23:42:00.000000000 +0900
@@ -4,4 +4,4 @@
# Reuse any files we can from the H8S
#

-obj-y := entry.o ints_h8s.o
+obj-y := entry.o ints_h8s.o ptrace_h8s.o
diff -Nru -X .exclude-diff linux-2.6.5/arch/h8300/platform/h8s/ptrace_h8s.c linux-2.6.5-h8300/arch/h8300/platform/h8s/ptrace_h8s.c
--- linux-2.6.5/arch/h8300/platform/h8s/ptrace_h8s.c 1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.5-h8300/arch/h8300/platform/h8s/ptrace_h8s.c 2004-03-23 23:42:00.000000000 +0900
@@ -0,0 +1,84 @@
+/*
+ * linux/arch/h8300/platform/h8s/ptrace_h8s.c
+ * ptrace cpu depend helper functions
+ *
+ * Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * 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/linkage.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <asm/ptrace.h>
+
+#define CCR_MASK 0x6f
+#define EXR_TRACE 0x80
+
+/* Mapping from PT_xxx to the stack offset at which the register is
+ saved. Notice that usp has no stack-slot and needs to be treated
+ specially (see get_reg/put_reg below). */
+static const int h8300_register_offset[] = {
+ PT_REG(er1), PT_REG(er2), PT_REG(er3), PT_REG(er4),
+ PT_REG(er5), PT_REG(er6), PT_REG(er0), PT_REG(orig_er0),
+ PT_REG(ccr), PT_REG(pc), PT_REG(exr)
+};
+
+/* read register */
+long h8300_get_reg(struct task_struct *task, int regno)
+{
+ switch (regno) {
+ case PT_USP:
+ return task->thread.usp + sizeof(long)*2 + 2;
+ case PT_CCR:
+ case PT_EXR:
+ return *(unsigned short *)(task->thread.esp0 + h8300_register_offset[regno]);
+ default:
+ return *(unsigned long *)(task->thread.esp0 + h8300_register_offset[regno]);
+ }
+}
+
+/* write register */
+int h8300_put_reg(struct task_struct *task, int regno, unsigned long data)
+{
+ unsigned short oldccr;
+ switch (regno) {
+ case PT_USP:
+ task->thread.usp = data - sizeof(long)*2 - 2;
+ case PT_CCR:
+ oldccr = *(unsigned short *)(task->thread.esp0 + h8300_register_offset[regno]);
+ oldccr &= ~CCR_MASK;
+ data &= CCR_MASK;
+ data |= oldccr;
+ *(unsigned short *)(task->thread.esp0 + h8300_register_offset[regno]) = data;
+ break;
+ case PT_EXR:
+ /* exr modify not support */
+ return -EIO;
+ default:
+ *(unsigned long *)(task->thread.esp0 + h8300_register_offset[regno]) = data;
+ break;
+ }
+ return 0;
+}
+
+/* disable singlestep */
+void h8300_disable_trace(struct task_struct *child)
+{
+ *(unsigned short *)(child->thread.esp0 + h8300_register_offset[PT_EXR]) &= ~EXR_TRACE;
+}
+
+/* enable singlestep */
+void h8300_enable_trace(struct task_struct *child)
+{
+ *(unsigned short *)(child->thread.esp0 + h8300_register_offset[PT_EXR]) |= EXR_TRACE;
+}
+
+asmlinkage void trace_trap(unsigned long bp)
+{
+ (void)bp;
+ force_sig(SIGTRAP,current);
+}
+
diff -Nru -X .exclude-diff linux-2.6.5/include/asm-h8300/processor.h linux-2.6.5-h8300/include/asm-h8300/processor.h
--- linux-2.6.5/include/asm-h8300/processor.h 2004-04-06 17:10:58.000000000 +0900
+++ linux-2.6.5-h8300/include/asm-h8300/processor.h 2004-04-06 01:52:17.000000000 +0900
@@ -51,16 +51,19 @@
#define MCA_bus 0

struct thread_struct {
- unsigned long ksp; /* kernel stack pointer */
- unsigned long usp; /* user stack pointer */
- unsigned long ccr; /* saved status register */
- unsigned long esp0; /* points to SR of stack frame */
- unsigned long debugreg[8]; /* debug info */
+ unsigned long ksp; /* kernel stack pointer */
+ unsigned long usp; /* user stack pointer */
+ unsigned long ccr; /* saved status register */
+ unsigned long esp0; /* points to SR of stack frame */
+ struct {
+ unsigned short *addr;
+ unsigned short inst;
+ } breakinfo;
};

#define INIT_THREAD { \
sizeof(init_stack) + (unsigned long) init_stack, 0, \
- PS_S, \
+ PS_S, 0, {(unsigned short *)-1, 0}, \
}

/*
diff -Nru -X .exclude-diff linux-2.6.5/include/asm-h8300/ptrace.h linux-2.6.5-h8300/include/asm-h8300/ptrace.h
--- linux-2.6.5/include/asm-h8300/ptrace.h 2004-01-09 16:00:02.000000000 +0900
+++ linux-2.6.5-h8300/include/asm-h8300/ptrace.h 2004-03-25 21:30:46.000000000 +0900
@@ -14,6 +14,7 @@
#define PT_CCR 8
#define PT_PC 9
#define PT_USP 10
+#define PT_EXR 12

/* this struct defines the way the registers are stored on the
stack during a system call. */
@@ -44,6 +45,16 @@
#define PS_S (0x10)
#endif

+#if defined(__H8300H__)
+#define H8300_REGS_NO 11
+#endif
+#if defined(__H8300S__)
+#define H8300_REGS_NO 12
+#endif
+
+/* Find the stack offset for a register, relative to thread.esp0. */
+#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
+
#define user_mode(regs) (!((regs)->ccr & PS_S))
#define instruction_pointer(regs) ((regs)->pc)
extern void show_regs(struct pt_regs *);