Make ptrace work.

This commit is contained in:
Doug Rabson 1998-07-15 20:16:28 +00:00
parent 6a5694427a
commit a22401deb1
4 changed files with 247 additions and 21 deletions

View File

@ -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);
*(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)) {
*(int*)((char *)p->p_addr + off) = data;
return (0);
}
#endif
*(int*)((char *)p->p_addr + off) = data;
return (0);
}
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);
}
return (EFAULT);
}

View File

@ -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:

View File

@ -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 */

View File

@ -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 */