Make ptrace work.
This commit is contained in:
parent
6a5694427a
commit
a22401deb1
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user