* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
* 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, Lawrence Berkeley Laboratory.
* This module is believed to contain source code proprietary to AT&T.
* Use and redistribution is subject to the Berkeley Software License
* Agreement and your Software Agreement with AT&T (Western Electric).
* @(#)sys_process.c 8.1 (Berkeley) 6/11/93
* Used to pass trace command from
* parent to child being traced.
* This data base cannot be
#define ip_any ip_un.un_any
#define ip_data ip_un.un_wd.wd_data
#define ip_addr ip_un.un_wd.wd_addr
#define ip_tf ip_un.un_tf
* Process debugging system call.
ptrace(curp
, uap
, retval
)
register struct ptrace_args
*uap
;
register enum { t_oneword
, t_regin
, t_regout
} type
;
if (uap
->req
== PT_TRACE_ME
) {
if ((p
= pfind(uap
->pid
)) == NULL
)
* Must be root if the process has used set user or group
* privileges or does not belong to the real user. Must
* not be already traced. Can't attach to ourselves.
if ((p
->p_flag
& SUGID
||
p
->p_cred
->p_ruid
!= curp
->p_cred
->p_ruid
) &&
(error
= suser(p
->p_ucred
, &p
->p_acflag
)) != 0)
return (EALREADY
); /* ??? */
* It would be nice if the tracing relationship was separate
* from the parent relationship but that would require
* another set of links in the proc struct or for "wait"
* to scan the entire proc table. To make life easier,
* we just re-parent the process we're trying to trace.
* The old parent is remembered so we can put things back
p
->p_oppid
= p
->p_pptr
->p_pid
;
setrun(p
); /* long enough to stop */
size
= sizeof(struct trapframe
);
size
= sizeof(struct trapframe
);
size
= sizeof(struct fpstate
);
size
= sizeof(struct fpstate
);
if (p
->p_stat
!= SSTOP
|| p
->p_pptr
!= curp
|| !(p
->p_flag
& STRC
))
sleep((caddr_t
)&ipc
, IPCPRI
);
if ((error
= copyin(uap
->addr
, ipc
.ip_any
, size
)) != 0)
sleep((caddr_t
)&ipc
, IPCPRI
);
} while (ipc
.ip_req
> 0);
if ((error
= ipc
.ip_error
) == 0) {
else if (type
== t_regout
)
error
= copyout(ipc
.ip_any
, uap
->addr
, size
);
* Write text space by unprotecting, writing, and reprotecting.
writetext(p
, addr
, data
, len
)
map
= &p
->p_vmspace
->vm_map
;
sa
= trunc_page((vm_offset_t
)addr
);
ea
= round_page((vm_offset_t
)addr
+ len
);
if (vm_map_protect(map
, sa
, ea
, VM_PROT_DEFAULT
, 0) != KERN_SUCCESS
)
error
= copyout(data
, addr
, len
);
(void) vm_map_protect(map
, sa
, ea
, VM_PROT_READ
|VM_PROT_EXECUTE
, 0);
* Transmit a tracing request from the parent to the child process
* being debugged. This code runs in the context of the child process
* to fulfill the command requested by the parent.
register int req
, error
, sig
, pc
, psr
;
register struct trapframe
*tf
, *utf
;
register struct fpstate
*fs
, *oldfs
;
extern struct fpstate initfpstate
;
if (ipc
.ip_lock
!= p
->p_pid
)
case PT_READ_I
: /* read the child's text space */
case PT_READ_D
: /* read the child's data space */
(void) rwindow_save(p
); /* ignore unwritable windows */
error
= copyin(ipc
.ip_addr
, ipc
.ip_any
, sizeof(int));
case PT_WRITE_I
: /* write the child's text space */
case PT_WRITE_D
: /* write the child's data space */
error
= copyout(ipc
.ip_any
, addr
, sizeof(int));
if (error
&& req
== PT_WRITE_I
)
error
= writetext(p
, addr
, ipc
.ip_any
, sizeof(int));
case PT_CONTINUE
: /* continue the child */
if ((unsigned)sig
>= NSIG
) {
p
->p_xstat
= sig
; /* see issig */
case PT_KILL
: /* kill the child process */
exit1(p
, (int)p
->p_xstat
);
case PT_DETACH
: /* stop tracing the child */
if ((unsigned)sig
>= NSIG
) {
p
->p_xstat
= sig
; /* see issig */
if (p
->p_oppid
!= p
->p_pptr
->p_pid
) {
register struct proc
*pp
= pfind(p
->p_oppid
);
copywords((caddr_t
)p
->p_md
.md_tf
, (caddr_t
)&ipc
.ip_tf
,
sizeof(struct trapframe
));
ipc
.ip_tf
.tf_global
[0] = 0; /* XXX */
if ((utf
->tf_pc
| utf
->tf_npc
) & 3) {
psr
= (tf
->tf_psr
& ~PSR_ICC
) | (utf
->tf_psr
& PSR_ICC
);
copywords((caddr_t
)utf
, (caddr_t
)tf
, sizeof(*tf
));
if ((fs
= p
->p_md
.md_fpstate
) == NULL
)
copywords((caddr_t
)fs
, (caddr_t
)&ipc
.ip_f
, sizeof *fs
);
if ((fs
->fs_fsr
& FSR_MBZ
) != 0 || fs
->fs_qsize
) {
oldfs
= p
->p_md
.md_fpstate
;
p
->p_md
.md_fpstate
= oldfs
= malloc(sizeof *oldfs
,
p
->p_md
.md_tf
->tf_psr
&= ~PSR_EF
;
copywords((caddr_t
)fs
, (caddr_t
)oldfs
, sizeof *oldfs
);