diff options
| author | Doug Rabson <dfr@FreeBSD.org> | 1998-07-15 20:16:28 +0000 |
|---|---|---|
| committer | Doug Rabson <dfr@FreeBSD.org> | 1998-07-15 20:16:28 +0000 |
| commit | a22401deb1638657e28d0fdfd4dd18fa74724912 (patch) | |
| tree | 2e79e8c28e1decb33514a5e066004fcc9d3d0637 | |
| parent | 6a5694427a50461f0f5dd3733b206458cc4937fc (diff) | |
Notes
| -rw-r--r-- | sys/alpha/alpha/machdep.c | 197 | ||||
| -rw-r--r-- | sys/alpha/alpha/trap.c | 46 | ||||
| -rw-r--r-- | sys/alpha/include/proc.h | 10 | ||||
| -rw-r--r-- | sys/alpha/include/ptrace.h | 5 |
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 */ |
