aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDoug Rabson <dfr@FreeBSD.org>1998-07-15 20:16:28 +0000
committerDoug Rabson <dfr@FreeBSD.org>1998-07-15 20:16:28 +0000
commita22401deb1638657e28d0fdfd4dd18fa74724912 (patch)
tree2e79e8c28e1decb33514a5e066004fcc9d3d0637
parent6a5694427a50461f0f5dd3733b206458cc4937fc (diff)
Notes
-rw-r--r--sys/alpha/alpha/machdep.c197
-rw-r--r--sys/alpha/alpha/trap.c46
-rw-r--r--sys/alpha/include/proc.h10
-rw-r--r--sys/alpha/include/ptrace.h5
4 files changed, 242 insertions, 16 deletions
diff --git a/sys/alpha/alpha/machdep.c b/sys/alpha/alpha/machdep.c
index 0504e17a01eea..4d15fd17b4abe 100644
--- a/sys/alpha/alpha/machdep.c
+++ b/sys/alpha/alpha/machdep.c
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: machdep.c,v 1.5 1998/07/05 12:24:17 dfr Exp $
+ * $Id: machdep.c,v 1.6 1998/07/12 16:10:52 dfr Exp $
*/
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -108,6 +108,7 @@
#include <sys/msgbuf.h>
#include <sys/exec.h>
#include <sys/sysctl.h>
+#include <sys/uio.h>
#include <net/netisr.h>
#include <vm/vm.h>
#include <vm/vm_kern.h>
@@ -131,6 +132,9 @@
#include <machine/vmparam.h>
#include <machine/elf.h>
#include <ddb/ddb.h>
+#include <alpha/alpha/db_instruction.h>
+#include <sys/vnode.h>
+#include <miscfs/procfs/procfs.h>
#ifdef SYSVSHM
#include <sys/shm.h>
@@ -1434,10 +1438,183 @@ ptrace_set_pc(struct proc *p, unsigned long addr)
return 0;
}
+static int
+ptrace_read_int(struct proc *p, vm_offset_t addr, u_int32_t *v)
+{
+ struct iovec iov;
+ struct uio uio;
+ iov.iov_base = (caddr_t) v;
+ iov.iov_len = sizeof(u_int32_t);
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = (off_t)addr;
+ uio.uio_resid = sizeof(u_int32_t);
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_READ;
+ uio.uio_procp = p;
+ return procfs_domem(curproc, p, NULL, &uio);
+}
+
+static int
+ptrace_write_int(struct proc *p, vm_offset_t addr, u_int32_t v)
+{
+ struct iovec iov;
+ struct uio uio;
+ iov.iov_base = (caddr_t) &v;
+ iov.iov_len = sizeof(u_int32_t);
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = (off_t)addr;
+ uio.uio_resid = sizeof(u_int32_t);
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_WRITE;
+ uio.uio_procp = p;
+ return procfs_domem(curproc, p, NULL, &uio);
+}
+
+static u_int64_t
+ptrace_read_register(struct proc *p, int regno)
+{
+ static int reg_to_frame[32] = {
+ FRAME_V0,
+ FRAME_T0,
+ FRAME_T1,
+ FRAME_T2,
+ FRAME_T3,
+ FRAME_T4,
+ FRAME_T5,
+ FRAME_T6,
+ FRAME_T7,
+
+ FRAME_S0,
+ FRAME_S1,
+ FRAME_S2,
+ FRAME_S3,
+ FRAME_S4,
+ FRAME_S5,
+ FRAME_S6,
+
+ FRAME_A0,
+ FRAME_A1,
+ FRAME_A2,
+ FRAME_A3,
+ FRAME_A4,
+ FRAME_A5,
+
+ FRAME_T8,
+ FRAME_T9,
+ FRAME_T10,
+ FRAME_T11,
+ FRAME_RA,
+ FRAME_T12,
+ FRAME_AT,
+ FRAME_GP,
+ FRAME_SP,
+ -1, /* zero */
+ };
+
+ if (regno == R_ZERO)
+ return 0;
+
+ return p->p_md.md_tf->tf_regs[reg_to_frame[regno]];
+}
+
+
+static int
+ptrace_clear_bpt(struct proc *p, struct mdbpt *bpt)
+{
+ return ptrace_write_int(p, bpt->addr, bpt->contents);
+}
+
+static int
+ptrace_set_bpt(struct proc *p, struct mdbpt *bpt)
+{
+ int error;
+ u_int32_t bpins = 0x00000080;
+ error = ptrace_read_int(p, bpt->addr, &bpt->contents);
+ if (error)
+ return error;
+ return ptrace_write_int(p, bpt->addr, bpins);
+}
+
+int
+ptrace_clear_single_step(struct proc *p)
+{
+ if (p->p_md.md_flags & MDP_STEP2) {
+ ptrace_clear_bpt(p, &p->p_md.md_sstep[1]);
+ ptrace_clear_bpt(p, &p->p_md.md_sstep[0]);
+ p->p_md.md_flags &= ~MDP_STEP2;
+ } else if (p->p_md.md_flags & MDP_STEP1) {
+ ptrace_clear_bpt(p, &p->p_md.md_sstep[0]);
+ p->p_md.md_flags &= ~MDP_STEP1;
+ }
+ return 0;
+}
+
int
ptrace_single_step(struct proc *p)
{
- return EINVAL;
+ int error;
+ vm_offset_t pc = p->p_md.md_tf->tf_regs[FRAME_PC];
+ alpha_instruction ins;
+ vm_offset_t addr[2]; /* places to set breakpoints */
+ int count = 0; /* count of breakpoints */
+
+ if (p->p_md.md_flags & (MDP_STEP1|MDP_STEP2))
+ panic("ptrace_single_step: step breakpoints not removed");
+
+ error = ptrace_read_int(p, pc, &ins.bits);
+ if (error)
+ return error;
+
+ switch (ins.branch_format.opcode) {
+
+ case op_j:
+ /* Jump: target is register value */
+ addr[0] = ptrace_read_register(p, ins.jump_format.rs) & ~3;
+ count = 1;
+ break;
+
+ case op_br:
+ case op_fbeq:
+ case op_fblt:
+ case op_fble:
+ case op_bsr:
+ case op_fbne:
+ case op_fbge:
+ case op_fbgt:
+ case op_blbc:
+ case op_beq:
+ case op_blt:
+ case op_ble:
+ case op_blbs:
+ case op_bne:
+ case op_bge:
+ case op_bgt:
+ /* Branch: target is pc+4+4*displacement */
+ addr[0] = pc + 4;
+ addr[1] = pc + 4 + 4 * ins.branch_format.displacement;
+ count = 2;
+
+ default:
+ addr[0] = pc + 4;
+ count = 1;
+ }
+
+ p->p_md.md_sstep[0].addr = addr[0];
+ if (error = ptrace_set_bpt(p, &p->p_md.md_sstep[0]))
+ return error;
+ if (count == 2) {
+ p->p_md.md_sstep[1].addr = addr[1];
+ if (error = ptrace_set_bpt(p, &p->p_md.md_sstep[1])) {
+ ptrace_clear_bpt(p, &p->p_md.md_sstep[0]);
+ return error;
+ }
+ p->p_md.md_flags |= MDP_STEP2;
+ } else
+ p->p_md.md_flags |= MDP_STEP1;
+
+ return 0;
}
int ptrace_read_u_check(p, addr, len)
@@ -1445,7 +1622,6 @@ int ptrace_read_u_check(p, addr, len)
vm_offset_t addr;
size_t len;
{
-#if 0
vm_offset_t gap;
if ((vm_offset_t) (addr + len) < addr)
@@ -1453,21 +1629,19 @@ int ptrace_read_u_check(p, addr, len)
if ((vm_offset_t) (addr + len) <= sizeof(struct user))
return 0;
- gap = (char *) p->p_md.md_regs - (char *) p->p_addr;
+ gap = (char *) p->p_md.md_tf - (char *) p->p_addr;
if ((vm_offset_t) addr < gap)
return EPERM;
if ((vm_offset_t) (addr + len) <=
(vm_offset_t) (gap + sizeof(struct trapframe)))
return 0;
-#endif
return EPERM;
}
int
ptrace_write_u(struct proc *p, vm_offset_t off, long data)
{
-#if 0
struct trapframe frame_copy;
vm_offset_t min;
struct trapframe *tp;
@@ -1476,23 +1650,24 @@ ptrace_write_u(struct proc *p, vm_offset_t off, long data)
* Privileged kernel state is scattered all over the user area.
* Only allow write access to parts of regs and to fpregs.
*/
- min = (char *)p->p_md.md_regs - (char *)p->p_addr;
+ min = (char *)p->p_md.md_tf - (char *)p->p_addr;
if (off >= min && off <= min + sizeof(struct trapframe) - sizeof(int)) {
- tp = p->p_md.md_regs;
+ tp = p->p_md.md_tf;
+#if 0
frame_copy = *tp;
*(int *)((char *)&frame_copy + (off - min)) = data;
if (!EFLAGS_SECURE(frame_copy.tf_eflags, tp->tf_eflags) ||
!CS_SECURE(frame_copy.tf_cs))
return (EINVAL);
+#endif
*(int*)((char *)p->p_addr + off) = data;
return (0);
}
- min = offsetof(struct user, u_pcb) + offsetof(struct pcb, pcb_savefpu);
- if (off >= min && off <= min + sizeof(struct save87) - sizeof(int)) {
+ min = offsetof(struct user, u_pcb) + offsetof(struct pcb, pcb_fp);
+ if (off >= min && off <= min + sizeof(struct fpreg) - sizeof(int)) {
*(int*)((char *)p->p_addr + off) = data;
return (0);
}
-#endif
return (EFAULT);
}
diff --git a/sys/alpha/alpha/trap.c b/sys/alpha/alpha/trap.c
index c6cd53fa04b58..69442a0cd2e99 100644
--- a/sys/alpha/alpha/trap.c
+++ b/sys/alpha/alpha/trap.c
@@ -1,4 +1,4 @@
-/* $Id: trap.c,v 1.3 1998/06/28 00:47:20 dfr Exp $ */
+/* $Id: trap.c,v 1.4 1998/07/05 12:24:17 dfr Exp $ */
/* $NetBSD: trap.c,v 1.31 1998/03/26 02:21:46 thorpej Exp $ */
/*
@@ -295,6 +295,10 @@ trap(a0, a1, a2, entry, framep)
/* FALLTHROUTH */
case ALPHA_IF_CODE_BPT:
case ALPHA_IF_CODE_BUGCHK:
+ if (p->p_md.md_flags & (MDP_STEP1|MDP_STEP2)) {
+ ptrace_clear_single_step(p);
+ p->p_md.md_tf->tf_regs[FRAME_PC] -= 4;
+ }
ucode = a0; /* trap type */
i = SIGTRAP;
break;
@@ -400,7 +404,41 @@ trap(a0, a1, a2, entry, framep)
}
va = trunc_page((vm_offset_t)a0);
- rv = vm_fault(map, va, ftype, FALSE);
+
+ if (map != kernel_map) {
+ /*
+ * Keep swapout from messing with us
+ * during thiscritical time.
+ */
+ ++p->p_lock;
+
+ /*
+ * Grow the stack if necessary
+ */
+ if ((caddr_t)va > vm->vm_maxsaddr
+ && (caddr_t)va < (caddr_t)USRSTACK) {
+ if (!grow(p, va)) {
+ rv = KERN_FAILURE;
+ --p->p_lock;
+ goto nogo;
+ }
+ }
+
+ /* Fault in the user page: */
+ rv = vm_fault(map, va, ftype,
+ (ftype & VM_PROT_WRITE)
+ ? VM_FAULT_DIRTY : 0);
+
+ --p->p_lock;
+ } else {
+ /*
+ * Don't have to worry about process
+ * locking or stacks in the kernel.
+ */
+ rv = vm_fault(map, va, ftype, FALSE);
+ }
+
+ nogo:;
/*
* If this was a stack access we keep track of the
* maximum accessed stack size. Also, if vm_fault
@@ -457,8 +495,10 @@ trap(a0, a1, a2, entry, framep)
#endif
trapsignal(p, i, ucode);
out:
- if (user)
+ if (user) {
+ framep->tf_regs[FRAME_SP] = alpha_pal_rdusp();
userret(p, framep->tf_regs[FRAME_PC], sticks);
+ }
return;
dopanic:
diff --git a/sys/alpha/include/proc.h b/sys/alpha/include/proc.h
index 6cb6d1beb457c..6a1af705706e3 100644
--- a/sys/alpha/include/proc.h
+++ b/sys/alpha/include/proc.h
@@ -1,4 +1,4 @@
-/* $Id: proc.h,v 1.1.1.1 1998/03/09 05:43:16 jb Exp $ */
+/* $Id: proc.h,v 1.2 1998/06/10 10:55:17 dfr Exp $ */
/* From: NetBSD: proc.h,v 1.3 1997/04/06 08:47:36 cgd Exp */
/*
@@ -32,10 +32,18 @@
* Machine-dependent part of the proc struct for the Alpha.
*/
+struct mdbpt {
+ vm_offset_t addr;
+ u_int32_t contents;
+};
+
struct mdproc {
u_long md_flags;
struct trapframe *md_tf; /* trap/syscall registers */
struct pcb *md_pcbpaddr; /* phys addr of the pcb */
+ struct mdbpt md_sstep[2]; /* two single step breakpoints */
};
#define MDP_FPUSED 0x0001 /* Process used the FPU */
+#define MDP_STEP1 0x0002 /* Single step normal instruction */
+#define MDP_STEP2 0x0004 /* Single step branch instruction */
diff --git a/sys/alpha/include/ptrace.h b/sys/alpha/include/ptrace.h
index 2b4a9cb103f42..27f3b2423082f 100644
--- a/sys/alpha/include/ptrace.h
+++ b/sys/alpha/include/ptrace.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)ptrace.h 8.1 (Berkeley) 6/11/93
- * $Id: ptrace.h,v 1.6 1998/05/19 00:00:12 tegge Exp $
+ * $Id: ptrace.h,v 1.1 1998/06/10 10:55:24 dfr Exp $
*/
#ifndef _MACHINE_PTRACE_H_
@@ -45,7 +45,10 @@
#define PT_GETFPREGS (PT_FIRSTMACH + 3)
#define PT_SETFPREGS (PT_FIRSTMACH + 4)
+#define FIX_SSTEP(p) ptrace_clear_single_step(p)
+
#ifdef KERNEL
+int ptrace_clear_single_step __P((struct proc *p));
int ptrace_read_u_check __P((struct proc *p, vm_offset_t off, size_t len));
#endif /* !KERNEL */