All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] H8/300 support update (1/3) - ptrace fix
@ 2004-04-06 11:00 Yoshinori Sato
  0 siblings, 0 replies; only message in thread
From: Yoshinori Sato @ 2004-04-06 11:00 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux kernel Mailing List

- 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 *);

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2004-04-06 11:05 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-04-06 11:00 [PATCH] H8/300 support update (1/3) - ptrace fix Yoshinori Sato

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.