mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-13 10:02:38 +00:00
Process tracing code. Written by Sean Eric Fagan.
Submitted by: Sean Eric Fagan
This commit is contained in:
parent
90fd8c3866
commit
4e68ceaba0
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=1945
@ -1,11 +1,6 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, Inc.
|
||||
/*
|
||||
* Copyright (c) 1994, Sean Eric Fagan
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -17,16 +12,14 @@
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
* This product includes software developed by Sean Eric Fagan.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
@ -35,14 +28,163 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)sys_process.c 8.1 (Berkeley) 6/10/93
|
||||
* $Id$
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#include <machine/reg.h>
|
||||
#include <machine/psl.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/vm_kern.h>
|
||||
|
||||
#include "user.h"
|
||||
|
||||
int
|
||||
pread (struct proc *procp, unsigned int addr, unsigned int *retval) {
|
||||
int rv;
|
||||
vm_map_t map, tmap;
|
||||
vm_object_t object;
|
||||
vm_offset_t kva = 0;
|
||||
int page_offset; /* offset into page */
|
||||
vm_offset_t pageno; /* page number */
|
||||
vm_map_entry_t out_entry;
|
||||
vm_prot_t out_prot;
|
||||
boolean_t wired, single_use;
|
||||
vm_offset_t off;
|
||||
|
||||
/* Map page into kernel space */
|
||||
|
||||
map = &procp->p_vmspace->vm_map;
|
||||
|
||||
page_offset = addr - trunc_page(addr);
|
||||
pageno = trunc_page(addr);
|
||||
|
||||
tmap = map;
|
||||
rv = vm_map_lookup (&tmap, pageno, VM_PROT_READ, &out_entry,
|
||||
&object, &off, &out_prot, &wired, &single_use);
|
||||
|
||||
if (rv != KERN_SUCCESS)
|
||||
return EINVAL;
|
||||
|
||||
vm_map_lookup_done (tmap, out_entry);
|
||||
|
||||
/* Find space in kernel_map for the page we're interested in */
|
||||
rv = vm_map_find (kernel_map, object, off, &kva, PAGE_SIZE, 1);
|
||||
|
||||
if (!rv) {
|
||||
vm_object_reference (object);
|
||||
|
||||
rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0);
|
||||
if (!rv) {
|
||||
*retval = 0;
|
||||
bcopy (kva + page_offset, retval, sizeof *retval);
|
||||
}
|
||||
vm_map_remove (kernel_map, kva, kva + PAGE_SIZE);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
pwrite (struct proc *procp, unsigned int addr, unsigned int datum) {
|
||||
int rv;
|
||||
vm_map_t map, tmap;
|
||||
vm_object_t object;
|
||||
vm_offset_t kva = 0;
|
||||
int page_offset; /* offset into page */
|
||||
vm_offset_t pageno; /* page number */
|
||||
vm_map_entry_t out_entry;
|
||||
vm_prot_t out_prot;
|
||||
boolean_t wired, single_use;
|
||||
vm_offset_t off;
|
||||
boolean_t fix_prot = 0;
|
||||
|
||||
/* Map page into kernel space */
|
||||
|
||||
map = &procp->p_vmspace->vm_map;
|
||||
|
||||
page_offset = addr - trunc_page(addr);
|
||||
pageno = trunc_page(addr);
|
||||
|
||||
/*
|
||||
* Check the permissions for the area we're interested in.
|
||||
*/
|
||||
|
||||
if (vm_map_check_protection (map, pageno, pageno + PAGE_SIZE,
|
||||
VM_PROT_WRITE) == FALSE) {
|
||||
/*
|
||||
* If the page was not writable, we make it so.
|
||||
* XXX It is possible a page may *not* be read/executable,
|
||||
* if a process changes that!
|
||||
*/
|
||||
fix_prot = 1;
|
||||
/* The page isn't writable, so let's try making it so... */
|
||||
if ((rv = vm_map_protect (map, pageno, pageno + PAGE_SIZE,
|
||||
VM_PROT_ALL, 0)) != KERN_SUCCESS)
|
||||
return EFAULT; /* I guess... */
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we need to get the page. out_entry, out_prot, wired, and
|
||||
* single_use aren't used. One would think the vm code would be
|
||||
* a *bit* nicer... We use tmap because vm_map_lookup() can
|
||||
* change the map argument.
|
||||
*/
|
||||
|
||||
tmap = map;
|
||||
rv = vm_map_lookup (&tmap, pageno, VM_PROT_WRITE, &out_entry,
|
||||
&object, &off, &out_prot, &wired, &single_use);
|
||||
if (rv != KERN_SUCCESS) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Okay, we've got the page. Let's release tmap.
|
||||
*/
|
||||
|
||||
vm_map_lookup_done (tmap, out_entry);
|
||||
|
||||
/*
|
||||
* Fault the page in...
|
||||
*/
|
||||
|
||||
rv = vm_fault (map, pageno, VM_PROT_WRITE, FALSE);
|
||||
if (rv != KERN_SUCCESS)
|
||||
return EFAULT;
|
||||
|
||||
/*
|
||||
* The page may need to be faulted in again, it seems.
|
||||
* This covers COW pages, I believe.
|
||||
*/
|
||||
|
||||
if (!rv)
|
||||
rv = vm_fault (map, pageno, VM_PROT_WRITE, 0);
|
||||
|
||||
/* Find space in kernel_map for the page we're interested in */
|
||||
rv = vm_map_find (kernel_map, object, off, &kva, PAGE_SIZE, 1);
|
||||
|
||||
if (!rv) {
|
||||
vm_object_reference (object);
|
||||
|
||||
rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0);
|
||||
if (!rv) {
|
||||
bcopy (&datum, kva + page_offset, sizeof datum);
|
||||
}
|
||||
vm_map_remove (kernel_map, kva, kva + PAGE_SIZE);
|
||||
}
|
||||
|
||||
if (fix_prot)
|
||||
vm_map_protect (map, pageno, pageno + PAGE_SIZE,
|
||||
VM_PROT_READ|VM_PROT_EXECUTE, 0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process debugging system call.
|
||||
*/
|
||||
@ -52,26 +194,171 @@ struct ptrace_args {
|
||||
caddr_t addr;
|
||||
int data;
|
||||
};
|
||||
int
|
||||
ptrace(a1, a2, a3)
|
||||
struct proc *a1;
|
||||
struct ptrace_args *a2;
|
||||
int *a3;
|
||||
{
|
||||
|
||||
int
|
||||
ptrace(curp, uap, retval)
|
||||
struct proc *curp;
|
||||
struct ptrace_args *uap;
|
||||
int *retval;
|
||||
{
|
||||
struct proc *p;
|
||||
int s, error = 0;
|
||||
|
||||
*retval = 0;
|
||||
if (uap->req == PT_TRACE_ME) {
|
||||
curp->p_flag |= P_TRACED;
|
||||
return 0;
|
||||
}
|
||||
if ((p = pfind(uap->pid)) == NULL) {
|
||||
return ESRCH;
|
||||
}
|
||||
|
||||
#ifdef PT_ATTACH
|
||||
if (uap->req != PT_ATTACH && (
|
||||
(p->p_flag & P_TRACED) == 0 ||
|
||||
(p->p_tptr && curp != p->p_tptr) ||
|
||||
(!p->p_tptr && curp != p->p_pptr)))
|
||||
|
||||
return ESRCH;
|
||||
#endif
|
||||
#ifdef PT_ATTACH
|
||||
if (uap->req != PT_ATTACH) {
|
||||
#endif
|
||||
if ((p->p_flag & P_TRACED) == 0)
|
||||
return EPERM;
|
||||
if (p->p_stat != SSTOP || (p->p_flag & P_WAITED) == 0)
|
||||
return EBUSY;
|
||||
#ifdef PT_ATTACH
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Body deleted.
|
||||
* XXX The PT_ATTACH code is completely broken. It will
|
||||
* be obsoleted by a /proc filesystem, so is it worth it
|
||||
* to fix it? (Answer, probably. So that'll be next,
|
||||
* I guess.)
|
||||
*/
|
||||
return (ENOSYS);
|
||||
|
||||
switch (uap->req) {
|
||||
#ifdef PT_ATTACH
|
||||
case PT_ATTACH:
|
||||
if (curp->p_ucred->cr_uid != 0 && (
|
||||
curp->p_ucred->cr_uid != p->p_ucred->cr_uid ||
|
||||
curp->p_ucred->cr_uid != p->p_cred->p_svuid))
|
||||
return EACCES;
|
||||
|
||||
p->p_tptr = curp;
|
||||
p->p_flag |= P_TRACED;
|
||||
psignal(p, SIGSTOP);
|
||||
return 0;
|
||||
|
||||
case PT_DETACH:
|
||||
if ((unsigned)uap->data >= NSIG)
|
||||
return EINVAL;
|
||||
p->p_flag &= ~P_TRACED;
|
||||
p->p_tptr = NULL;
|
||||
psignal(p->p_pptr, SIGCHLD);
|
||||
wakeup((caddr_t)p->p_pptr);
|
||||
s = splhigh();
|
||||
if (p->p_stat == SSTOP) {
|
||||
p->p_xstat = uap->data;
|
||||
setrunnable(p);
|
||||
} else if (uap->data) {
|
||||
psignal(p, uap->data);
|
||||
}
|
||||
splx(s);
|
||||
return 0;
|
||||
|
||||
# ifdef PT_INHERIT
|
||||
case PT_INHERIT:
|
||||
if ((p->p_flag & P_TRACED) == 0)
|
||||
return ESRCH;
|
||||
return 0;
|
||||
# endif /* PT_INHERIT */
|
||||
#endif /* PT_ATTACH */
|
||||
|
||||
case PT_READ_I:
|
||||
case PT_READ_D:
|
||||
if (error = pread (p, (unsigned int)uap->addr, retval))
|
||||
return error;
|
||||
return 0;
|
||||
case PT_WRITE_I:
|
||||
case PT_WRITE_D:
|
||||
if (error = pwrite (p, (unsigned int)uap->addr,
|
||||
(unsigned int)uap->data))
|
||||
return error;
|
||||
return 0;
|
||||
case PT_STEP:
|
||||
if (error = ptrace_single_step (p))
|
||||
return error;
|
||||
/* fallthrough */
|
||||
case PT_CONTINUE:
|
||||
/*
|
||||
* Continue at addr uap->addr with signal
|
||||
* uap->data; if uap->addr is 1, then we just
|
||||
* let the chips fall where they may.
|
||||
*
|
||||
* The only check I'll make right now is for
|
||||
* uap->data to be larger than NSIG; if so, we return
|
||||
* EINVAL.
|
||||
*/
|
||||
if (uap->data >= NSIG)
|
||||
return EINVAL;
|
||||
|
||||
if (uap->addr != (caddr_t)1) {
|
||||
fill_eproc (p, &p->p_addr->u_kproc.kp_eproc);
|
||||
if (error = ptrace_set_pc (p, uap->addr))
|
||||
return error;
|
||||
}
|
||||
|
||||
p->p_xstat = uap->data;
|
||||
|
||||
/* if (p->p_stat == SSTOP) */
|
||||
setrunnable (p);
|
||||
return 0;
|
||||
case PT_READ_U:
|
||||
if ((u_int)uap->addr > (UPAGES * NBPG - sizeof(int))) {
|
||||
return EFAULT;
|
||||
}
|
||||
p->p_addr->u_kproc.kp_proc = *p;
|
||||
fill_eproc (p, &p->p_addr->u_kproc.kp_eproc);
|
||||
*retval = *(int*)((u_int)p->p_addr + (u_int)uap->addr);
|
||||
return 0;
|
||||
case PT_WRITE_U:
|
||||
if ((u_int)uap->addr > (UPAGES * NBPG - sizeof(int))) {
|
||||
return EFAULT;
|
||||
}
|
||||
p->p_addr->u_kproc.kp_proc = *p;
|
||||
fill_eproc (p, &p->p_addr->u_kproc.kp_eproc);
|
||||
*(int*)((u_int)p->p_addr + (u_int)uap->addr) = uap->data;
|
||||
return 0;
|
||||
case PT_KILL:
|
||||
p->p_xstat = SIGKILL;
|
||||
setrunnable(p);
|
||||
return 0;
|
||||
#ifdef PT_GETREGS
|
||||
case PT_GETREGS:
|
||||
/*
|
||||
* copyout the registers into addr. There's no
|
||||
* size constraint!!! *GRRR*
|
||||
*/
|
||||
return ptrace_getregs(p, uap->addr);
|
||||
case PT_SETREGS:
|
||||
/*
|
||||
* copyin the registers from addr. Again, no
|
||||
* size constraint!!! *GRRRR*
|
||||
*/
|
||||
return ptrace_setregs (p, uap->addr);
|
||||
#endif /* PT_GETREGS */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
trace_req(a1)
|
||||
struct proc *a1;
|
||||
trace_req(p)
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
/*
|
||||
* Body deleted.
|
||||
*/
|
||||
return (0);
|
||||
return 1;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)ptrace.h 8.2 (Berkeley) 1/4/94
|
||||
* $Id$
|
||||
* $Id: ptrace.h,v 1.2 1994/08/02 07:53:24 davidg Exp $
|
||||
*/
|
||||
|
||||
#ifndef _SYS_PTRACE_H_
|
||||
@ -47,8 +47,11 @@
|
||||
#define PT_CONTINUE 7 /* continue the child */
|
||||
#define PT_KILL 8 /* kill the child process */
|
||||
#define PT_STEP 9 /* single step the child */
|
||||
|
||||
#ifdef notdef
|
||||
#define PT_ATTACH 10 /* trace some running process */
|
||||
#define PT_DETACH 11 /* stop tracing a process */
|
||||
#endif
|
||||
|
||||
#define PT_FIRSTMACH 32 /* for machine-specific requests */
|
||||
#include <machine/ptrace.h> /* machine-specific requests, if any */
|
||||
|
Loading…
Reference in New Issue
Block a user