* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 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 SOFTWARE IS PROVIDED BY THE REGENTS 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
* 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)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* from: @(#)sys_process.c 7.22 (Berkeley) 5/11/91
* $Id: sys_process.c,v 1.7 1993/11/25 01:33:22 wollman Exp $
* The following ptrace calls have been defined in addition to
* the standard ones found in original <sys/ptrace.h>:
* PT_ATTACH - attach to running process
* PT_DETACH - detach from running process
* PT_SYSCALL - trace system calls
* PT_GETREG - get register file
* PT_SETREG - set register file
* PT_BREAD_[IDU] - block read from process (not yet implemented)
* PT_BWRITE_[IDU] - block write " "
* PT_INHERIT - make forked processes inherit trace flags
/* Define to prevent extraneous clutter in source */
pread (struct proc
*procp
, unsigned int addr
, unsigned int *retval
) {
int page_offset
; /* offset into page */
vm_offset_t pageno
; /* page number */
vm_map_entry_t out_entry
;
boolean_t wired
, single_use
;
/* Map page into kernel space */
map
= &procp
->p_vmspace
->vm_map
;
page_offset
= addr
- trunc_page(addr
);
pageno
= trunc_page(addr
);
rv
= vm_map_lookup (&tmap
, pageno
, VM_PROT_READ
, &out_entry
,
&object
, &off
, &out_prot
, &wired
, &single_use
);
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);
vm_object_reference (object
);
rv
= vm_map_pageable (kernel_map
, kva
, kva
+ PAGE_SIZE
, 0);
bcopy ((caddr_t
)(kva
+ page_offset
), retval
,
vm_map_remove (kernel_map
, kva
, kva
+ PAGE_SIZE
);
pwrite (struct proc
*procp
, unsigned int addr
, unsigned int datum
) {
int page_offset
; /* offset into page */
vm_offset_t pageno
; /* page number */
vm_map_entry_t out_entry
;
boolean_t wired
, single_use
;
/* 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!
/* 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.
rv
= vm_map_lookup (&tmap
, pageno
, VM_PROT_WRITE
, &out_entry
,
&object
, &off
, &out_prot
, &wired
, &single_use
);
if (rv
!= KERN_SUCCESS
) {
* Okay, we've got the page. Let's release tmap.
vm_map_lookup_done (tmap
, out_entry
);
rv
= vm_fault (map
, pageno
, VM_PROT_WRITE
, FALSE
);
* The page may need to be faulted in again, it seems.
* This covers COW pages, I believe.
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);
vm_object_reference (object
);
rv
= vm_map_pageable (kernel_map
, kva
, kva
+ PAGE_SIZE
, 0);
bcopy (&datum
, (caddr_t
)(kva
+ page_offset
), sizeof datum
);
vm_map_remove (kernel_map
, kva
, kva
+ PAGE_SIZE
);
vm_map_protect (map
, pageno
, pageno
+ PAGE_SIZE
,
VM_PROT_READ
|VM_PROT_EXECUTE
, 0);
* Process debugging system call.
ptrace(curp
, uap
, retval
)
register struct ptrace_args
*uap
;
if (uap
->req
== PT_TRACE_ME
) {
if ((p
= pfind(uap
->pid
)) == NULL
) {
if (uap
->req
!= PT_ATTACH
&& (
(p
->p_flag
& STRC
) == 0 ||
(p
->p_tptr
&& curp
!= p
->p_tptr
) ||
(!p
->p_tptr
&& curp
!= p
->p_pptr
)))
if (uap
->req
!= PT_ATTACH
) {
if ((p
->p_flag
& STRC
) == 0)
if (p
->p_stat
!= SSTOP
|| (p
->p_flag
& SWTED
) == 0)
* 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,
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
))
if ((unsigned)uap
->data
>= NSIG
)
p
->p_flag
&= ~(STRC
|SSTRC
|SFTRC
);
psignal(p
->p_pptr
, SIGCHLD
);
wakeup((caddr_t
)p
->p_pptr
);
if (p
->p_stat
== SSTOP
) {
if ((p
->p_flag
& STRC
) == 0)
if (error
= pread (p
, (unsigned int)uap
->addr
, retval
))
if (error
= pwrite (p
, (unsigned int)uap
->addr
,
(unsigned int)uap
->data
))
if (error
= ptrace_single_step (p
))
* 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
if (uap
->addr
!= (int*)1) {
fill_eproc (p
, &p
->p_addr
->u_kproc
.kp_eproc
);
if (error
= ptrace_set_pc (p
, uap
->addr
))
/* if (p->p_stat == SSTOP) */
if ((u_int
)uap
->addr
> (UPAGES
* NBPG
- sizeof(int))) {
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
);
if ((u_int
)uap
->addr
> (UPAGES
* NBPG
- sizeof(int))) {
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
;
* copyout the registers into addr. There's no
* size constraint!!! *GRRR*
return ptrace_getregs(p
, uap
->addr
);
* copyin the registers from addr. Again, no
* size constraint!!! *GRRRR*
return ptrace_setregs (p
, uap
->addr
);
* Enable process profiling system call.
short *bufbase
; /* base of data buffer */
unsigned bufsize
; /* size of data buffer */
unsigned pcoffset
; /* pc offset (for subtraction) */
unsigned pcscale
; /* scaling factor for offset pc */
register struct profil_args
*uap
;
/* from looking at man pages, and include files, looks like
* this just sets up the fields of p->p_stats->p_prof...
* and those fields come straight from the args.
* only thing *we* have to do is check the args for validity...
/* check to make sure that the buffer is OK. addupc (in locore)
* checks for faults, but would one be generated, say, writing to
* kernel space? probably not -- it just uses "movl"...
* so we've gotta check to make sure that the info set up for
* addupc is set right... it's gotta be writable by the user...
if (useracc(uap
->bufbase
,uap
->bufsize
*sizeof(short),B_WRITE
) == 0)
p
->p_stats
->p_prof
.pr_base
= uap
->bufbase
;
p
->p_stats
->p_prof
.pr_size
= uap
->bufsize
;
p
->p_stats
->p_prof
.pr_off
= uap
->pcoffset
;
p
->p_stats
->p_prof
.pr_scale
= uap
->pcscale
;