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
- Lines: 420
- Date:
Mon Oct 12 11:40:12 1998
- Orig file:
v2.1.125/linux/arch/alpha/kernel/ptrace.c
- Orig date:
Wed Sep 9 14:51:04 1998
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