* Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
* %sccs.include.proprietary.c%
* @(#)sys_process.c 7.31 (Berkeley) %G%
* Used to pass trace command from
* parent to child being traced.
* This data base cannot be
* Process debugging system call.
ptrace(curp
, uap
, retval
)
register struct ptrace_args
*uap
;
if (uap
->req
== PT_ATTACH
) {
* 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.
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
;
if (p
== 0 || p
->p_stat
!= SSTOP
|| p
->p_pptr
!= curp
||
sleep((caddr_t
)&ipc
, IPCPRI
);
sleep((caddr_t
)&ipc
, IPCPRI
);
#define PHYSOFF(p, o) ((caddr_t)(p) + (o))
* 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.
if (ipc
.ip_lock
!= p
->p_pid
)
p
->p_addr
->u_kproc
.kp_proc
.p_md
.md_regs
= p
->p_md
.md_regs
; /* u.u_ar0 */
case PT_READ_I
: /* read the child's text space */
if (!useracc((caddr_t
)ipc
.ip_addr
, 4, B_READ
))
ipc
.ip_data
= fuiword((caddr_t
)ipc
.ip_addr
);
case PT_READ_D
: /* read the child's data space */
if (!useracc((caddr_t
)ipc
.ip_addr
, 4, B_READ
))
ipc
.ip_data
= fuword((caddr_t
)ipc
.ip_addr
);
case PT_READ_U
: /* read the child's u. */
if (p
->p_addr
->u_pcb
.pcb_flags
& PCB_HPUXTRACE
)
i
= hpuxtobsduoff(ipc
.ip_addr
);
if ((u_int
) i
> ctob(UPAGES
)-sizeof(int) || (i
& 1) != 0)
ipc
.ip_data
= *(int *)PHYSOFF(p
->p_addr
, i
);
case PT_WRITE_I
: /* write the child's text space */
if ((i
= suiword((caddr_t
)ipc
.ip_addr
, ipc
.ip_data
)) < 0) {
sa
= trunc_page((vm_offset_t
)ipc
.ip_addr
);
ea
= round_page((vm_offset_t
)ipc
.ip_addr
+sizeof(int));
rv
= vm_map_protect(&p
->p_vmspace
->vm_map
, sa
, ea
,
if (rv
== KERN_SUCCESS
) {
i
= suiword((caddr_t
)ipc
.ip_addr
, ipc
.ip_data
);
(void) vm_map_protect(&p
->p_vmspace
->vm_map
,
sa
, ea
, VM_PROT_READ
|VM_PROT_EXECUTE
,
case PT_WRITE_D
: /* write the child's data space */
if (suword((caddr_t
)ipc
.ip_addr
, 0) < 0)
(void) suword((caddr_t
)ipc
.ip_addr
, ipc
.ip_data
);
case PT_WRITE_U
: /* write the child's u. */
if (p
->p_addr
->u_pcb
.pcb_flags
& PCB_HPUXTRACE
)
i
= hpuxtobsduoff(ipc
.ip_addr
);
poff
= (int *)PHYSOFF(curproc
->p_addr
, i
);
poff
= (int *)PHYSOFF(kstack
, i
);
for (i
=0; i
<NIPCREG
; i
++)
if (poff
== &p
->p_md
.md_regs
[ipcreg
[i
]])
if (poff
== &p
->p_md
.md_regs
[PS
]) {
ipc
.ip_data
|= PSL_USERSET
;
ipc
.ip_data
&= ~PSL_USERCLR
;
if (ipc
.ip_data
& PSL_CM
)
ipc
.ip_data
&= ~PSL_CM_CLR
;
#if defined(hp300) || defined(luna68k)
if (poff
>= (int *)&((struct user
*)kstack
)->u_pcb
.pcb_fpregs
.fpf_regs
&&
poff
<= (int *)&((struct user
*)kstack
)->u_pcb
.pcb_fpregs
.fpf_fpiar
)
case PT_STEP
: /* single step the child */
case PT_CONTINUE
: /* continue the child */
if ((unsigned)ipc
.ip_data
>= NSIG
)
if ((int)ipc
.ip_addr
!= 1)
p
->p_md
.md_regs
[PC
] = (int)ipc
.ip_addr
;
p
->p_xstat
= ipc
.ip_data
; /* see issig */
/* need something more machine independent here... */
p
->p_md
.md_regs
[PS
] |= PSL_T
;
case PT_KILL
: /* kill the child process */
exit(p
, (int)p
->p_xstat
);
case PT_DETACH
: /* stop tracing the child */
if ((unsigned)ipc
.ip_data
>= NSIG
)
if ((int)ipc
.ip_addr
!= 1)
p
->p_md
.md_regs
[PC
] = (int)ipc
.ip_addr
;
p
->p_xstat
= ipc
.ip_data
; /* see issig */
if (p
->p_oppid
!= p
->p_pptr
->p_pid
) {
register struct proc
*pp
= pfind(p
->p_oppid
);