patch-2.1.126 linux/arch/alpha/kernel/ptrace.c

Next file: linux/arch/alpha/kernel/setup.c
Previous file: linux/arch/alpha/kernel/proto.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c
@@ -12,27 +12,26 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/malloc.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
 
+#include "proto.h"
+
+#define DEBUG	DBG_MEM
 #undef DEBUG
 
 #ifdef DEBUG
-
 enum {
 	DBG_MEM		= (1<<0),
 	DBG_BPT		= (1<<1),
 	DBG_MEM_ALL	= (1<<2)
 };
-
-int debug_mask = DBG_BPT;
-
-# define DBG(fac,args)	{if ((fac) & debug_mask) printk args;}
-
+#define DBG(fac,args)	{if ((fac) & DEBUG) printk args;}
 #else
-# define DBG(fac,args)
+#define DBG(fac,args)
 #endif
 
 #define BREAKINST	0x00000080	/* call_pal bpt */
@@ -45,33 +44,26 @@
 /*
  * Processes always block with the following stack-layout:
  *
- *  +================================+ --------------------------
- *  | PALcode saved frame (ps, pc,   | ^		      ^
- *  | gp, a0, a1, a2)		     | |		      |
- *  +================================+ | struct pt_regs	      |
- *  |	        		     | |		      |
- *  | frame generated by SAVE_ALL    | |		      |
- *  |	        		     | v		      | P
- *  +================================+			      |	A
- *  |	        		     | ^		      |	G
- *  | frame saved by do_switch_stack | | struct switch_stack  |	E
- *  |	        		     | v		      |	_
- *  +================================+			      |	S
- *  |	        		     |			      |	I
- *  |	        		     |			      |	Z
- *  /	        		     /			      |	E
- *  /	                             /			      |
- *  |				     |			      |
- *  |				     |			      |
- *  |				     |			      v
- *  +================================+ <-------------------------
- *					task + PAGE_SIZE
+ *  +================================+ <---- task + 2*PAGE_SIZE
+ *  | PALcode saved frame (ps, pc,   | ^
+ *  | gp, a0, a1, a2)		     | |
+ *  +================================+ | struct pt_regs
+ *  |	        		     | |
+ *  | frame generated by SAVE_ALL    | |
+ *  |	        		     | v
+ *  +================================+
+ *  |	        		     | ^
+ *  | frame saved by do_switch_stack | | struct switch_stack
+ *  |	        		     | v
+ *  +================================+
  */
-#define PT_REG(reg)	(PAGE_SIZE - sizeof(struct pt_regs)	\
+#define PT_REG(reg)	(PAGE_SIZE*2 - sizeof(struct pt_regs)		\
 			 + (long)&((struct pt_regs *)0)->reg)
-#define SW_REG(reg)	(PAGE_SIZE - sizeof(struct pt_regs)	\
-			 - sizeof(struct switch_stack)		\
+
+#define SW_REG(reg)	(PAGE_SIZE*2 - sizeof(struct pt_regs)		\
+			 - sizeof(struct switch_stack)			\
 			 + (long)&((struct switch_stack *)0)->reg)
+
 /* 
  * The following table maps a register index into the stack offset at
  * which the register is saved.  Register indices are 0-31 for integer
@@ -80,10 +72,10 @@
  * get_reg/put_reg below).
  */
 enum {
-	REG_R0 = 0, REG_F0 = 32, REG_PC = 64
+	REG_R0 = 0, REG_F0 = 32, REG_FPCR = 63, REG_PC = 64
 };
 
-static unsigned short regoff[] = {
+static int regoff[] = {
 	PT_REG(	   r0), PT_REG(	   r1), PT_REG(	   r2), PT_REG(	  r3),
 	PT_REG(	   r4), PT_REG(	   r5), PT_REG(	   r6), PT_REG(	  r7),
 	PT_REG(	   r8), SW_REG(	   r9), SW_REG(	  r10), SW_REG(	 r11),
@@ -106,38 +98,40 @@
 static long zero;
 
 /*
- * Get contents of register REGNO in task TASK.
+ * Get address of register REGNO in task TASK.
  */
-static inline long get_reg(struct task_struct * task, long regno)
+static long *
+get_reg_addr(struct task_struct * task, unsigned long regno)
 {
 	long *addr;
 
 	if (regno == 30) {
 		addr = &task->tss.usp;
-	} else if (regno == 31) {
+	} else if (regno == 31 || regno > 64) {
 		zero = 0;
 		addr = &zero;
 	} else {
-		addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task);
+		addr = (long *)((long)task + regoff[regno]);
 	}
-	return *addr;
+	return addr;
 }
 
 /*
- * Write contents of register REGNO in task TASK.
+ * Get contents of register REGNO in task TASK.
  */
-static inline int put_reg(struct task_struct *task, long regno, long data)
+static inline long
+get_reg(struct task_struct * task, unsigned long regno)
 {
-	long *addr, zero;
+	return *get_reg_addr(task, regno);
+}
 
-	if (regno == 30) {
-		addr = &task->tss.usp;
-	} else if (regno == 31) {
-		addr = &zero;
-	} else {
-		addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task);
-	}
-	*addr = data;
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+static inline int
+put_reg(struct task_struct *task, unsigned long regno, long data)
+{
+	*get_reg_addr(task, regno) = data;
 	return 0;
 }
 
@@ -147,8 +141,9 @@
  * and that it is in the task area before calling this: this routine does
  * no checking.
  */
-static unsigned long get_long(struct task_struct * tsk,
-			      struct vm_area_struct * vma, unsigned long addr)
+static unsigned long
+get_long(struct task_struct * tsk, struct vm_area_struct * vma,
+	 unsigned long addr)
 {
 	pgd_t * pgdir;
 	pmd_t * pgmiddle;
@@ -199,8 +194,9 @@
  * Now keeps R/W state of page so that a text page stays readonly
  * even if a debugger scribbles breakpoints into it.  -M.U-
  */
-static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
-		     unsigned long addr, unsigned long data)
+static void
+put_long(struct task_struct * tsk, struct vm_area_struct * vma,
+	 unsigned long addr, unsigned long data)
 {
 	pgd_t *pgdir;
 	pmd_t *pgmiddle;
@@ -250,8 +246,8 @@
 	flush_tlb();
 }
 
-static struct vm_area_struct * find_extend_vma(struct task_struct * tsk,
-					       unsigned long addr)
+static struct vm_area_struct *
+find_extend_vma(struct task_struct * tsk, unsigned long addr)
 {
 	struct vm_area_struct * vma;
 
@@ -274,8 +270,8 @@
  * This routine checks the page boundaries, and that the offset is
  * within the task area. It then calls get_long() to read a long.
  */
-static int read_long(struct task_struct * tsk, unsigned long addr,
-		     unsigned long * result)
+static int
+read_long(struct task_struct * tsk, unsigned long addr, unsigned long * result)
 {
 	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
 
@@ -315,8 +311,8 @@
  * This routine checks the page boundaries, and that the offset is
  * within the task area. It then calls put_long() to write a long.
  */
-static int write_long(struct task_struct * tsk, unsigned long addr,
-		      unsigned long data)
+static int
+write_long(struct task_struct * tsk, unsigned long addr, unsigned long data)
 {
 	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
 
@@ -349,8 +345,8 @@
 /*
  * Read a 32bit int from address space TSK.
  */
-static int read_int(struct task_struct * tsk, unsigned long addr,
-		    unsigned int *data)
+static int
+read_int(struct task_struct * tsk, unsigned long addr, unsigned int *data)
 {
 	unsigned long l, align;
 	int res;
@@ -376,8 +372,8 @@
  * For simplicity, do a read-modify-write of the 64bit word that
  * contains the 32bit word that we are about to write.
  */
-static int write_int(struct task_struct * tsk, unsigned long addr,
-		     unsigned int data)
+static int
+write_int(struct task_struct * tsk, unsigned long addr, unsigned int data)
 {
 	unsigned long l, align;
 	int res;
@@ -400,7 +396,8 @@
 /*
  * Set breakpoint.
  */
-int ptrace_set_bpt(struct task_struct * child)
+int
+ptrace_set_bpt(struct task_struct * child)
 {
 	int displ, i, res, reg_b, nsaved = 0;
 	u32 insn, op_code;
@@ -422,31 +419,31 @@
 		 * branch (emulation can be tricky for fp branches).
 		 */
 		displ = ((s32)(insn << 11)) >> 9;
-		child->tss.debugreg[nsaved++] = pc + 4;
+		child->tss.bpt_addr[nsaved++] = pc + 4;
 		if (displ)		/* guard against unoptimized code */
-			child->tss.debugreg[nsaved++] = pc + 4 + displ;
+			child->tss.bpt_addr[nsaved++] = pc + 4 + displ;
 		DBG(DBG_BPT, ("execing branch\n"));
 	} else if (op_code == 0x1a) {
 		reg_b = (insn >> 16) & 0x1f;
-		child->tss.debugreg[nsaved++] = get_reg(child, reg_b);
+		child->tss.bpt_addr[nsaved++] = get_reg(child, reg_b);
 		DBG(DBG_BPT, ("execing jump\n"));
 	} else {
-		child->tss.debugreg[nsaved++] = pc + 4;
+		child->tss.bpt_addr[nsaved++] = pc + 4;
 		DBG(DBG_BPT, ("execing normal insn\n"));
 	}
 
 	/* install breakpoints: */
 	for (i = 0; i < nsaved; ++i) {
-		res = read_int(child, child->tss.debugreg[i], &insn);
+		res = read_int(child, child->tss.bpt_addr[i], &insn);
 		if (res < 0)
 			return res;
-		child->tss.debugreg[i + 2] = insn;
-		DBG(DBG_BPT, ("    -> next_pc=%lx\n", child->tss.debugreg[i]));
-		res = write_int(child, child->tss.debugreg[i], BREAKINST);
+		child->tss.bpt_insn[i] = insn;
+		DBG(DBG_BPT, ("    -> next_pc=%lx\n", child->tss.bpt_addr[i]));
+		res = write_int(child, child->tss.bpt_addr[i], BREAKINST);
 		if (res < 0)
 			return res;
 	}
-	child->tss.debugreg[4] = nsaved;
+	child->tss.bpt_nsaved = nsaved;
 	return 0;
 }
 
@@ -454,11 +451,12 @@
  * Ensure no single-step breakpoint is pending.  Returns non-zero
  * value if child was being single-stepped.
  */
-int ptrace_cancel_bpt(struct task_struct * child)
+int
+ptrace_cancel_bpt(struct task_struct * child)
 {
-	int i, nsaved = child->tss.debugreg[4];
+	int i, nsaved = child->tss.bpt_nsaved;
 
-	child->tss.debugreg[4] = 0;
+	child->tss.bpt_nsaved = 0;
 
 	if (nsaved > 2) {
 		printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
@@ -466,16 +464,18 @@
 	}
 
 	for (i = 0; i < nsaved; ++i) {
-		write_int(child, child->tss.debugreg[i],
-			  child->tss.debugreg[i + 2]);
+		write_int(child, child->tss.bpt_addr[i],
+			  child->tss.bpt_insn[i]);
 	}
 	return (nsaved != 0);
 }
 
-asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
-			   int a4, int a5, struct pt_regs regs)
+asmlinkage long
+sys_ptrace(long request, long pid, long addr, long data,
+	   int a4, int a5, struct pt_regs regs)
 {
 	struct task_struct *child;
+	unsigned long tmp;
 	long ret;
 
 	lock_kernel();
@@ -540,9 +540,7 @@
 	switch (request) {
 	/* When I and D space are separate, these will need to be fixed.  */
 	case PTRACE_PEEKTEXT: /* read word at location addr. */
-	case PTRACE_PEEKDATA: {
-		unsigned long tmp;
-
+	case PTRACE_PEEKDATA:
 		ret = read_long(child, addr, &tmp);
 		DBG(DBG_MEM, ("peek %#lx->%#lx\n", addr, tmp));
 		if (ret < 0)
@@ -550,13 +548,12 @@
 		regs.r0 = 0;	/* special return: no errors */
 		ret = tmp;
 		goto out;
-	}
 
-	/* read register number ADDR. */
+	/* Read register number ADDR. */
 	case PTRACE_PEEKUSR:
 		regs.r0 = 0;	/* special return: no errors */
-		DBG(DBG_MEM, ("peek $%ld=%#lx\n", addr, regs.r0));
 		ret = get_reg(child, addr);
+		DBG(DBG_MEM, ("peek $%ld->%#lx\n", addr, ret));
 		goto out;
 
 	/* When I and D space are separate, this will have to be fixed.  */
@@ -573,7 +570,7 @@
 
 	case PTRACE_SYSCALL: /* continue and stop at next
 				(return from) syscall */
-	case PTRACE_CONT: { /* restart after signal. */
+	case PTRACE_CONT:    /* restart after signal. */
 		ret = -EIO;
 		if ((unsigned long) data > _NSIG)
 			goto out;
@@ -587,14 +584,13 @@
 		ptrace_cancel_bpt(child);
 		ret = data;
 		goto out;
-	}
 
 	/*
 	 * Make the child exit.  Best I can do is send it a sigkill.
 	 * perhaps it should be put in the status that it wants to
 	 * exit.
 	 */
-	case PTRACE_KILL: {
+	case PTRACE_KILL:
 		if (child->state != TASK_ZOMBIE) {
 			wake_up_process(child);
 			child->exit_code = SIGKILL;
@@ -603,22 +599,20 @@
 		ptrace_cancel_bpt(child);
 		ret = 0;
 		goto out;
-	}
 
-	case PTRACE_SINGLESTEP: {  /* execute single instruction. */
+	case PTRACE_SINGLESTEP:  /* execute single instruction. */
 		ret = -EIO;
 		if ((unsigned long) data > _NSIG)
 			goto out;
-		child->tss.debugreg[4] = -1;	/* mark single-stepping */
+		child->tss.bpt_nsaved = -1;	/* mark single-stepping */
 		child->flags &= ~PF_TRACESYS;
 		wake_up_process(child);
 		child->exit_code = data;
 		/* give it a chance to run. */
 		ret = 0;
 		goto out;
-	}
 
-	case PTRACE_DETACH: { /* detach a process that was attached. */
+	case PTRACE_DETACH: /* detach a process that was attached. */
 		ret = -EIO;
 		if ((unsigned long) data > _NSIG)
 			goto out;
@@ -632,7 +626,6 @@
 		ptrace_cancel_bpt(child);
 		ret = 0;
 		goto out;
-	}
 
 	default:
 		ret = -EIO;
@@ -643,7 +636,8 @@
 	return ret;
 }
 
-asmlinkage void syscall_trace(void)
+asmlinkage void
+syscall_trace(void)
 {
 	if ((current->flags & (PF_PTRACED|PF_TRACESYS))
 	    != (PF_PTRACED|PF_TRACESYS))

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov