* 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
#include "machine/eflags.h"
* 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 */
* `ipcreg' defined in <machine/reg.h>
* Should we define a structure with all regs?
{ 0,0,sEDI
,sESI
,sEBP
,sEBX
,sEDX
,sECX
,sEAX
,sEIP
,sCS
,sEFLAGS
,sESP
,sSS
};
int req
; /* copy of ptrace request */
int *addr
; /* copy of ptrace address */
int data
; /* copy of ptrace data */
int error
; /* errno from `procxmt' */
int regs
[NIPCREG
]; /* PT_[GS]ETREG */
caddr_t buf
; /* PT_BREAD/WRITE */
* Process debugging system call.
ptrace(curp
, uap
, retval
)
register struct ptrace_args
*uap
;
if (uap
->req
== PT_TRACE_ME
) {
/*p->p_tptr = p->p_pptr; * What shall we do here ? */
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 (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)
/* Other ptrace calls require target process to be in stopped state */
if ((p
->p_flag
& STRC
) == 0 || p
->p_stat
!= SSTOP
) {
/* Acquire the ipc structure */
while (ipc
.flag
& IPC_BUSY
) {
error
= tsleep((caddr_t
)&ipc
, PWAIT
|PCATCH
, "ipc", 0);
error
= copyin((char *)ipc
.addr
, (char *)ipc
.regs
, sizeof(ipc
.regs
));
#ifdef notyet /* requires change in number of args to ptrace syscall */
ipc
.buf
= kmem_alloc_wait(kernelmap
, uap
->data
);
error
= copyin((char *)ipc
.addr
, (char *)ipc
.buf
, ipc
.buflen
);
kmem_free_wakeup(kernelmap
, ipc
.buf
, ipc
.buflen
);
while ((ipc
.flag
& IPC_DONE
) == 0) {
error
= tsleep((caddr_t
)&ipc
, PWAIT
|PCATCH
, "ipc", 0);
error
= copyout((char *)ipc
.regs
, (char *)ipc
.addr
, sizeof(ipc
.regs
));
/* Release ipc structure */
if (ipc
.flag
& IPC_WANT
) {
int new_eflags
, old_cs
, old_ds
, old_es
, old_ss
, old_eflags
;
/* Are we still being traced? */
if ((p
->p_flag
& STRC
) == 0)
p
->p_addr
->u_kproc
.kp_proc
= *p
;
fill_eproc(p
, &p
->p_addr
->u_kproc
.kp_eproc
);
if (!useracc(ipc
.addr
, sizeof(ipc
.data
), B_READ
)) {
ipc
.error
= copyin((char *)ipc
.addr
, (char *)&ipc
.data
, sizeof(ipc
.data
));
if ((u_int
)ipc
.addr
> UPAGES
* NBPG
- sizeof(int)) {
ipc
.data
= *(int *)((u_int
)p
->p_addr
+ (u_int
)ipc
.addr
);
case PT_WRITE_D
: { /* 04 Sep 92*/
vm_prot_t prot
; /* current protection of region */
int cow
; /* ensure copy-on-write happens */
if (cow
= (useracc(ipc
.addr
, sizeof(ipc
.data
), B_WRITE
) == 0)) {
vm_offset_t addr
= (vm_offset_t
)ipc
.addr
;
* XXX - the useracc check is stronger than the vm
* checks because the user page tables are in the map.
* Anyway, most of this can be removed now that COW
if (!useracc(ipc
.addr
, sizeof(ipc
.data
), B_READ
) ||
vm_region(&p
->p_vmspace
->vm_map
, &addr
, &size
,
&prot
, &max_prot
, &inh
, &shared
,
&object
, &objoff
) != KERN_SUCCESS
||
vm_protect(&p
->p_vmspace
->vm_map
, ipc
.addr
,
prot
|VM_PROT_WRITE
) != KERN_SUCCESS
||
vm_fault(&p
->p_vmspace
->vm_map
,trunc_page(ipc
.addr
),
VM_PROT_WRITE
, FALSE
) != KERN_SUCCESS
) {
ipc
.error
= copyout((char *)&ipc
.data
,
(char *)ipc
.addr
, sizeof(ipc
.data
));
if (vm_protect(&p
->p_vmspace
->vm_map
, ipc
.addr
,
printf("ptrace: oops\n");
* XXX - privileged kernel state is scattered all over the
* user area. Only allow write access to areas known to
#define GO_IF_SAFE(min, size) \
if ((u_int)ipc.addr >= (min) \
&& (u_int)ipc.addr <= (min) + (size) - sizeof(int)) \
* Allow writing entire FPU state.
GO_IF_SAFE(offsetof(struct user
, u_pcb
)
+ offsetof(struct pcb
, pcb_savefpu
),
* Allow writing ordinary registers. Changes to segment
* registers and to some bits in %eflags will be silently
* ignored. Such changes ought to be an error.
* XXX - there is no define for the base of the user area except USRSTACK.
* XXX - USRSTACK is not the base of the user stack. It is the base of the
#define USER_OFF(va) ((u_int)(va) - USRSTACK)
GO_IF_SAFE(USER_OFF(regs
),
(curpcb
->pcb_flags
& FM_TRAP
? tSS
+ 1 : sSS
+ 1)
if ((u_int
)ipc
.addr
> UPAGES
* NBPG
- sizeof(int)) {
if (curpcb
->pcb_flags
& FM_TRAP
) {
old_eflags
= regs
[tEFLAGS
];
old_eflags
= regs
[sEFLAGS
];
*(int *)((u_int
)p
->p_addr
+ (u_int
)ipc
.addr
) = ipc
.data
;
* Don't allow segment registers to change (although they can
* be changed directly to certain values).
* Don't allow privileged bits in %eflags to change. Users
* have privilege to change TF and NT although although they
* XXX - simplify. Maybe copy through a temporary struct.
* Watch out for problems when ipc.addr is not a multiple
#define EFL_UNPRIVILEGED (EFL_CF | EFL_PF | EFL_AF | EFL_ZF | EFL_SF \
| EFL_TF | EFL_DF | EFL_OF | EFL_NT)
if (curpcb
->pcb_flags
& FM_TRAP
) {
new_eflags
= regs
[tEFLAGS
];
= (new_eflags
& EFL_UNPRIVILEGED
)
| (old_eflags
& ~EFL_UNPRIVILEGED
);
new_eflags
= regs
[sEFLAGS
];
= (new_eflags
& EFL_UNPRIVILEGED
)
| (old_eflags
& ~EFL_UNPRIVILEGED
);
if (ipc
.addr
!= (int *)1) {
p
->p_regs
[(curpcb
->pcb_flags
&FM_TRAP
)?tEIP
:sEIP
] = (int)ipc
.addr
;
p
->p_flag
&= ~SSTRC
; /* Only set by PT_SYSCALL */
if ((unsigned)ipc
.data
>= NSIG
) {
p
->p_flag
&= ~SSTRC
; /* Only set by PT_SYSCALL */
if (ipc
.addr
!= (int *)1) {
p
->p_regs
[(curpcb
->pcb_flags
&FM_TRAP
)?tEIP
:sEIP
] = (int)ipc
.addr
;
p
->p_regs
[(curpcb
->pcb_flags
&FM_TRAP
)?tEFLAGS
:sEFLAGS
] |= PSL_T
;
p
->p_flag
&= ~SSTRC
; /* Only set by PT_SYSCALL */
if (ipc
.addr
!= (int *)1) {
p
->p_regs
[(curpcb
->pcb_flags
&FM_TRAP
)?tEIP
:sEIP
] = (int)ipc
.addr
;
xreg
= (curpcb
->pcb_flags
&FM_TRAP
)?ipcreg
:sipcreg
;
for (i
= 0; i
< NIPCREG
; i
++)
ipc
.regs
[i
] = p
->p_regs
[xreg
[i
]];
xreg
= (curpcb
->pcb_flags
&FM_TRAP
)?ipcreg
:sipcreg
;
for (i
= 0; i
< NIPCREG
; i
++)
p
->p_regs
[xreg
[i
]] = ipc
.regs
[i
];
/* Should be able to specify core file name */
* 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
;