4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * ptrace(2) interface built on top of proc(4).
31 #pragma ident "%Z%%M% %I% %E% SMI"
33 #pragma weak _ptrace = ptrace
43 #include <sys/types.h>
46 #include <sys/siginfo.h>
47 #include <sys/fault.h>
48 #include <sys/syscall.h>
53 * mtlib.h must precede thread.h
59 static mutex_t pt_lock
= DEFAULTMUTEX
;
67 typedef struct cstatus
{
68 struct cstatus
*next
; /* linked list */
69 pid_t pid
; /* process-id */
70 int asfd
; /* /proc/<pid>/as */
71 int ctlfd
; /* /proc/<pid>/ctl */
72 int statusfd
; /* /proc/<pid>/status */
73 int flags
; /* see below */
74 pstatus_t pstatus
; /* from /proc/<pid>/status */
75 user_t user
; /* manufactured u-block */
79 #define CS_SETREGS 0x01 /* set registers on run */
80 #define CS_PSARGS 0x02 /* u_psargs[] has been fetched */
81 #define CS_SIGNAL 0x04 /* u_signal[] has been fetched */
83 #define NULLCP ((cstatus_t *)0)
85 static cstatus_t
*childp
= NULLCP
;
87 /* fake u-block offsets */
88 #define UP ((user_t *)NULL)
89 #define U_REG ((int)(&UP->u_reg[0]))
90 #define U_AR0 ((int)(&UP->u_ar0))
91 #define U_PSARGS ((int)(&UP->u_psargs[0]))
92 #define U_SIGNAL ((int)(&UP->u_signal[0]))
93 #define U_CODE ((int)(&UP->u_code))
94 #define U_ADDR ((int)(&UP->u_addr))
95 #define U_END ((int)sizeof (user_t))
96 #define REGADDR 0xffff0000 /* arbitrary kernel address for u_ar0 */
98 /* external routines defined in this module */
99 extern int ptrace(int, pid_t
, int, int);
100 /* static routines defined in this module */
101 static cstatus_t
*FindProc(pid_t
);
102 static void CheckAllProcs(void);
103 static int Dupfd(int, int);
104 static void MakeProcName(char *, pid_t
);
105 static int OpenProc(cstatus_t
*);
106 static void CloseProc(cstatus_t
*);
107 static cstatus_t
*GrabProc(pid_t
);
108 static void ReleaseProc(cstatus_t
*);
109 static int ProcUpdate(cstatus_t
*);
110 static void MakeUser(cstatus_t
*);
111 static void GetPsargs(cstatus_t
*);
112 static void GetSignal(cstatus_t
*);
119 static char name
[20];
122 case 0: return ("PTRACE_TRACEME");
123 case 1: return ("PTRACE_PEEKTEXT");
124 case 2: return ("PTRACE_PEEKDATA");
125 case 3: return ("PTRACE_PEEKUSER");
126 case 4: return ("PTRACE_POKETEXT");
127 case 5: return ("PTRACE_POKEDATA");
128 case 6: return ("PTRACE_POKEUSER");
129 case 7: return ("PTRACE_CONT");
130 case 8: return ("PTRACE_KILL");
131 case 9: return ("PTRACE_SINGLESTEP");
133 (void) sprintf(name
, "%d", request
);
139 ptrace(int request
, pid_t pid
, int addr
, int data
)
156 fprintf(stderr
, " ptrace(%s, 0x%X, 0x%X, 0x%X)\n",
157 map(request
), pid
, addr
, data
);
160 (void) mutex_lock(&pt_lock
);
162 if (request
== 0) { /* PTRACE_TRACEME, executed by traced process */
164 * Set stop-on-all-signals and nothing else.
165 * Turn off inherit-on-fork flag (grandchildren run away).
166 * Set ptrace-compatible flag.
168 char procname
[64]; /* /proc/<pid>/ctl */
171 MakeProcName(procname
, getpid());
172 (void) strcat(procname
, "/ctl");
173 if ((fd
= open(procname
, O_WRONLY
, 0)) < 0)
176 prfillset(&ctl
.arg
.signals
);
177 if (write(fd
, (char *)&ctl
, sizeof (long)+sizeof (sigset_t
))
178 != sizeof (long)+sizeof (sigset_t
))
181 premptyset(&ctl
.arg
.faults
);
182 if (write(fd
, (char *)&ctl
, sizeof (long)+sizeof (fltset_t
))
183 != sizeof (long)+sizeof (fltset_t
))
186 premptyset(&ctl
.arg
.syscalls
);
187 if (write(fd
, (char *)&ctl
, sizeof (long)+sizeof (sysset_t
))
188 != sizeof (long)+sizeof (sysset_t
))
191 premptyset(&ctl
.arg
.syscalls
);
192 if (write(fd
, (char *)&ctl
, sizeof (long)+sizeof (sysset_t
))
193 != sizeof (long)+sizeof (sysset_t
))
196 ctl
.arg
.flags
= PR_FORK
;
197 if (write(fd
, (char *)&ctl
, sizeof (long)+sizeof (long))
198 != sizeof (long)+sizeof (long))
201 ctl
.arg
.flags
= PR_PTRACE
;
202 if (write(fd
, (char *)&ctl
, sizeof (long)+sizeof (long))
203 != sizeof (long)+sizeof (long))
208 (void) mutex_unlock(&pt_lock
);
215 /* find the cstatus structure corresponding to pid */
216 if ((cp
= GrabProc(pid
)) == NULLCP
)
220 if (!(ps
->pr_flags
& PR_ISTOP
)) {
221 if (ProcUpdate(cp
) != 0) {
225 if (!(ps
->pr_flags
& PR_ISTOP
))
230 * Process the request.
234 case 1: /* PTRACE_PEEKTEXT */
235 case 2: /* PTRACE_PEEKDATA */
238 if (pread(cp
->asfd
, (char *)&data
, sizeof (data
), (off_t
)addr
)
240 (void) mutex_unlock(&pt_lock
);
245 case 3: /* PTRACE_PEEKUSER */
249 if (xaddr
>= REGADDR
&& xaddr
< REGADDR
+sizeof (gregset_t
))
250 xaddr
-= REGADDR
-U_REG
;
251 if (xaddr
>= U_PSARGS
&& xaddr
< U_PSARGS
+sizeof (UP
->u_psargs
))
253 if (xaddr
>= U_SIGNAL
&& xaddr
< U_SIGNAL
+sizeof (UP
->u_signal
))
255 if ((int)xaddr
>= 0 && xaddr
< U_END
) {
256 /* LINTED pointer alignment */
257 data
= *((int *)((caddr_t
)(&cp
->user
) + xaddr
));
258 (void) mutex_unlock(&pt_lock
);
263 case 4: /* PTRACE_POKETEXT */
264 case 5: /* PTRACE_POKEDATA */
267 if (pwrite(cp
->asfd
, (char *)&data
, sizeof (data
), (off_t
)addr
)
269 (void) mutex_unlock(&pt_lock
);
274 case 6: /* PTRACE_POKEUSER */
278 if (xaddr
>= REGADDR
&& xaddr
< REGADDR
+sizeof (gregset_t
))
279 xaddr
-= REGADDR
-U_REG
;
280 if ((int)xaddr
>= U_REG
&& xaddr
< U_REG
+sizeof (gregset_t
)) {
281 int rx
= (xaddr
-U_REG
)/sizeof (greg_t
);
283 data
= (cp
->user
.u_reg
[EFL
] & ~PSL_USERMASK
) |
284 (data
& PSL_USERMASK
);
285 cp
->user
.u_reg
[rx
] = data
;
286 cp
->flags
|= CS_SETREGS
;
287 (void) mutex_unlock(&pt_lock
);
292 case 7: /* PTRACE_CONT */
293 case 9: /* PTRACE_SINGLESTEP */
297 if (cp
->flags
& CS_SETREGS
) {
301 ps
->pr_lwp
.pr_reg
[GS
] = cp
->user
.u_reg
[GS
];
302 ps
->pr_lwp
.pr_reg
[FS
] = cp
->user
.u_reg
[FS
];
303 ps
->pr_lwp
.pr_reg
[ES
] = cp
->user
.u_reg
[ES
];
304 ps
->pr_lwp
.pr_reg
[DS
] = cp
->user
.u_reg
[DS
];
305 ps
->pr_lwp
.pr_reg
[EDI
] = cp
->user
.u_reg
[EDI
];
306 ps
->pr_lwp
.pr_reg
[ESI
] = cp
->user
.u_reg
[ESI
];
307 ps
->pr_lwp
.pr_reg
[EBP
] = cp
->user
.u_reg
[EBP
];
308 ps
->pr_lwp
.pr_reg
[ESP
] = cp
->user
.u_reg
[ESP
];
309 ps
->pr_lwp
.pr_reg
[EBX
] = cp
->user
.u_reg
[EBX
];
310 ps
->pr_lwp
.pr_reg
[EDX
] = cp
->user
.u_reg
[EDX
];
311 ps
->pr_lwp
.pr_reg
[ECX
] = cp
->user
.u_reg
[ECX
];
312 ps
->pr_lwp
.pr_reg
[EAX
] = cp
->user
.u_reg
[EAX
];
313 ps
->pr_lwp
.pr_reg
[TRAPNO
] = cp
->user
.u_reg
[TRAPNO
];
314 ps
->pr_lwp
.pr_reg
[ERR
] = cp
->user
.u_reg
[ERR
];
315 ps
->pr_lwp
.pr_reg
[EIP
] = cp
->user
.u_reg
[EIP
];
316 ps
->pr_lwp
.pr_reg
[CS
] = cp
->user
.u_reg
[CS
];
317 ps
->pr_lwp
.pr_reg
[EFL
] = cp
->user
.u_reg
[EFL
];
318 ps
->pr_lwp
.pr_reg
[UESP
] = cp
->user
.u_reg
[UESP
];
319 ps
->pr_lwp
.pr_reg
[SS
] = cp
->user
.u_reg
[SS
];
321 iov
[0].iov_base
= (caddr_t
)&cmd
;
322 iov
[0].iov_len
= sizeof (long);
323 iov
[1].iov_base
= (caddr_t
)&ps
->pr_lwp
.pr_reg
[0];
324 iov
[1].iov_len
= sizeof (ps
->pr_lwp
.pr_reg
);
325 if (writev(cp
->ctlfd
, iov
, 2) < 0)
328 if (addr
!= 1 && /* new virtual address */
329 addr
!= cp
->user
.u_reg
[EIP
]) {
330 runctl
[0] = PCSVADDR
;
332 if (write(cp
->ctlfd
, (char *)runctl
, 2*sizeof (long))
336 /* make data the current signal */
337 if (data
!= 0 && data
!= ps
->pr_lwp
.pr_cursig
) {
338 (void) memset((char *)&ctl
.arg
.siginfo
, 0,
340 ctl
.arg
.siginfo
.si_signo
= data
;
342 if (write(cp
->ctlfd
, (char *)&ctl
,
343 sizeof (long)+sizeof (siginfo_t
))
344 != sizeof (long)+sizeof (siginfo_t
))
352 runctl
[2] = (request
== 9)? PRSTEP
: 0;
353 if (write(cp
->ctlfd
, (char *)runctl
, 3*sizeof (long))
354 != 3*sizeof (long)) {
355 if (errno
== ENOENT
) {
356 /* current signal must have killed it */
358 (void) mutex_unlock(&pt_lock
);
363 (void) memset((char *)ps
, 0, sizeof (pstatus_t
));
365 (void) mutex_unlock(&pt_lock
);
369 case 8: /* PTRACE_KILL */
371 (void) memset((char *)&ctl
.arg
.siginfo
, 0, sizeof (siginfo_t
));
372 ctl
.arg
.siginfo
.si_signo
= SIGKILL
;
374 (void) write(cp
->ctlfd
, (char *)&ctl
,
375 sizeof (long)+sizeof (siginfo_t
));
376 (void) kill(pid
, SIGKILL
);
378 (void) mutex_unlock(&pt_lock
);
386 if (errno
== EAGAIN
) {
387 if (OpenProc(cp
) == 0)
393 (void) mutex_unlock(&pt_lock
);
397 (void) mutex_unlock(&pt_lock
);
402 * Find the cstatus structure corresponding to pid.
409 for (cp
= childp
; cp
!= NULLCP
; cp
= cp
->next
)
417 * Check every proc for existence, release those that are gone.
418 * Be careful about the linked list; ReleaseProc() changes it.
423 cstatus_t
*cp
= childp
;
425 while (cp
!= NULLCP
) {
426 cstatus_t
*next
= cp
->next
;
428 if (ProcUpdate(cp
) != 0)
435 * Utility for OpenProc().
438 Dupfd(int fd
, int dfd
)
441 * Make sure fd not one of 0, 1, or 2 to avoid stdio interference.
442 * Also, if dfd is greater than 2, dup fd to be exactly dfd.
444 if (dfd
> 2 || (0 <= fd
&& fd
<= 2)) {
445 if (dfd
> 2 && fd
!= dfd
)
450 dfd
= fcntl(fd
, F_DUPFD
, (intptr_t)dfd
);
456 * Mark filedescriptor close-on-exec.
457 * Should also be close-on-return-from-fork-in-child.
459 (void) fcntl(fd
, F_SETFD
, (intptr_t)1);
464 * Construct the /proc directory name: "/proc/<pid>"
465 * The name buffer passed by the caller must be large enough.
468 MakeProcName(char *procname
, pid_t pid
)
470 (void) sprintf(procname
, "/proc/%ld", pid
);
474 * Open/reopen the /proc/<pid> files.
477 OpenProc(cstatus_t
*cp
)
479 char procname
[64]; /* /proc/nnnnn/fname */
484 MakeProcName(procname
, cp
->pid
);
485 fname
= procname
+ strlen(procname
);
488 * Use exclusive-open only if this is the first open.
490 omode
= (cp
->asfd
> 0)? O_RDWR
: (O_RDWR
|O_EXCL
);
491 (void) strcpy(fname
, "/as");
492 if ((fd
= open(procname
, omode
, 0)) < 0 ||
493 (cp
->asfd
= Dupfd(fd
, cp
->asfd
)) < 0)
496 (void) strcpy(fname
, "/ctl");
497 if ((fd
= open(procname
, O_WRONLY
, 0)) < 0 ||
498 (cp
->ctlfd
= Dupfd(fd
, cp
->ctlfd
)) < 0)
501 (void) strcpy(fname
, "/status");
502 if ((fd
= open(procname
, O_RDONLY
, 0)) < 0 ||
503 (cp
->statusfd
= Dupfd(fd
, cp
->statusfd
)) < 0)
514 * Close the /proc/<pid> files.
517 CloseProc(cstatus_t
*cp
)
520 (void) close(cp
->asfd
);
522 (void) close(cp
->ctlfd
);
523 if (cp
->statusfd
> 0)
524 (void) close(cp
->statusfd
);
531 * Take control of a child process.
543 if ((cp
= FindProc(pid
)) != NULLCP
) /* already grabbed */
546 CheckAllProcs(); /* clean up before grabbing new process */
548 cp
= (cstatus_t
*)malloc(sizeof (cstatus_t
));
551 (void) memset((char *)cp
, 0, sizeof (cstatus_t
));
555 while (OpenProc(cp
) == 0) {
560 if (pread(cp
->statusfd
, (char *)&cp
->pstatus
,
561 sizeof (cp
->pstatus
), (off_t
)0) == sizeof (cp
->pstatus
) &&
562 cp
->pstatus
.pr_ppid
== ppid
&&
563 (cp
->pstatus
.pr_flags
& PR_PTRACE
) &&
564 write(cp
->ctlfd
, (char *)ctl
, 2*sizeof (long))
565 == 2*sizeof (long)) {
581 * Close the /proc/<pid> file, if open.
582 * Deallocate the memory used by the cstatus_t structure.
585 ReleaseProc(cstatus_t
*cp
)
594 for (pcp
= childp
; pcp
!= NULLCP
; pcp
= pcp
->next
) {
595 if (pcp
->next
== cp
) {
596 pcp
->next
= cp
->next
;
606 * Update process information from /proc.
607 * Return 0 on success, -1 on failure.
610 ProcUpdate(cstatus_t
*cp
)
612 pstatus_t
*ps
= &cp
->pstatus
;
614 if (cp
->flags
& CS_SETREGS
) {
618 ps
->pr_lwp
.pr_reg
[GS
] = cp
->user
.u_reg
[GS
];
619 ps
->pr_lwp
.pr_reg
[FS
] = cp
->user
.u_reg
[FS
];
620 ps
->pr_lwp
.pr_reg
[ES
] = cp
->user
.u_reg
[ES
];
621 ps
->pr_lwp
.pr_reg
[DS
] = cp
->user
.u_reg
[DS
];
622 ps
->pr_lwp
.pr_reg
[EDI
] = cp
->user
.u_reg
[EDI
];
623 ps
->pr_lwp
.pr_reg
[ESI
] = cp
->user
.u_reg
[ESI
];
624 ps
->pr_lwp
.pr_reg
[EBP
] = cp
->user
.u_reg
[EBP
];
625 ps
->pr_lwp
.pr_reg
[ESP
] = cp
->user
.u_reg
[ESP
];
626 ps
->pr_lwp
.pr_reg
[EBX
] = cp
->user
.u_reg
[EBX
];
627 ps
->pr_lwp
.pr_reg
[EDX
] = cp
->user
.u_reg
[EDX
];
628 ps
->pr_lwp
.pr_reg
[ECX
] = cp
->user
.u_reg
[ECX
];
629 ps
->pr_lwp
.pr_reg
[EAX
] = cp
->user
.u_reg
[EAX
];
630 ps
->pr_lwp
.pr_reg
[TRAPNO
] = cp
->user
.u_reg
[TRAPNO
];
631 ps
->pr_lwp
.pr_reg
[ERR
] = cp
->user
.u_reg
[ERR
];
632 ps
->pr_lwp
.pr_reg
[EIP
] = cp
->user
.u_reg
[EIP
];
633 ps
->pr_lwp
.pr_reg
[CS
] = cp
->user
.u_reg
[CS
];
634 ps
->pr_lwp
.pr_reg
[EFL
] = cp
->user
.u_reg
[EFL
];
635 ps
->pr_lwp
.pr_reg
[UESP
] = cp
->user
.u_reg
[UESP
];
636 ps
->pr_lwp
.pr_reg
[SS
] = cp
->user
.u_reg
[SS
];
638 iov
[0].iov_base
= (caddr_t
)&cmd
;
639 iov
[0].iov_len
= sizeof (long);
640 iov
[1].iov_base
= (caddr_t
)&ps
->pr_lwp
.pr_reg
[0];
641 iov
[1].iov_len
= sizeof (ps
->pr_lwp
.pr_reg
);
642 (void) writev(cp
->ctlfd
, iov
, 2);
643 cp
->flags
&= ~CS_SETREGS
;
646 while (pread(cp
->statusfd
, (char *)ps
, sizeof (*ps
), (off_t
)0) < 0) {
647 /* attempt to regain control */
648 if (errno
!= EINTR
&&
649 !(errno
== EAGAIN
&& OpenProc(cp
) == 0))
653 if (ps
->pr_flags
& PR_ISTOP
)
656 (void) memset((char *)ps
, 0, sizeof (pstatus_t
));
662 * Manufacture the contents of the fake u-block.
665 MakeUser(cstatus_t
*cp
)
667 pstatus_t
*ps
= &cp
->pstatus
;
669 cp
->user
.u_reg
[GS
] = ps
->pr_lwp
.pr_reg
[GS
];
670 cp
->user
.u_reg
[FS
] = ps
->pr_lwp
.pr_reg
[FS
];
671 cp
->user
.u_reg
[ES
] = ps
->pr_lwp
.pr_reg
[ES
];
672 cp
->user
.u_reg
[DS
] = ps
->pr_lwp
.pr_reg
[DS
];
673 cp
->user
.u_reg
[EDI
] = ps
->pr_lwp
.pr_reg
[EDI
];
674 cp
->user
.u_reg
[ESI
] = ps
->pr_lwp
.pr_reg
[ESI
];
675 cp
->user
.u_reg
[EBP
] = ps
->pr_lwp
.pr_reg
[EBP
];
676 cp
->user
.u_reg
[ESP
] = ps
->pr_lwp
.pr_reg
[ESP
];
677 cp
->user
.u_reg
[EBX
] = ps
->pr_lwp
.pr_reg
[EBX
];
678 cp
->user
.u_reg
[EDX
] = ps
->pr_lwp
.pr_reg
[EDX
];
679 cp
->user
.u_reg
[ECX
] = ps
->pr_lwp
.pr_reg
[ECX
];
680 cp
->user
.u_reg
[EAX
] = ps
->pr_lwp
.pr_reg
[EAX
];
681 cp
->user
.u_reg
[TRAPNO
] = ps
->pr_lwp
.pr_reg
[TRAPNO
];
682 cp
->user
.u_reg
[ERR
] = ps
->pr_lwp
.pr_reg
[ERR
];
683 cp
->user
.u_reg
[EIP
] = ps
->pr_lwp
.pr_reg
[EIP
];
684 cp
->user
.u_reg
[CS
] = ps
->pr_lwp
.pr_reg
[CS
];
685 cp
->user
.u_reg
[EFL
] = ps
->pr_lwp
.pr_reg
[EFL
];
686 cp
->user
.u_reg
[UESP
] = ps
->pr_lwp
.pr_reg
[UESP
];
687 cp
->user
.u_reg
[SS
] = ps
->pr_lwp
.pr_reg
[SS
];
688 cp
->user
.u_ar0
= (greg_t
*)REGADDR
;
689 cp
->user
.u_code
= ps
->pr_lwp
.pr_info
.si_code
;
690 cp
->user
.u_addr
= ps
->pr_lwp
.pr_info
.si_addr
;
691 cp
->flags
&= ~(CS_PSARGS
|CS_SIGNAL
);
695 * Fetch the contents of u_psargs[].
698 GetPsargs(cstatus_t
*cp
)
700 char procname
[64]; /* /proc/<pid>/psinfo */
703 MakeProcName(procname
, cp
->pid
);
704 (void) strcat(procname
, "/psinfo");
705 if ((fd
= open(procname
, O_RDONLY
, 0)) < 0) {
706 (void) memset(cp
->user
.u_psargs
, 0, PSARGSZ
);
709 (void) pread(fd
, cp
->user
.u_psargs
, PSARGSZ
,
710 (off_t
)((psinfo_t
*)0)->pr_psargs
);
713 cp
->flags
|= CS_PSARGS
;
717 * Fetch the contents of u_signal[].
720 GetSignal(cstatus_t
*cp
)
722 char procname
[64]; /* /proc/<pid>/sigact */
724 struct sigaction action
[MAXSIG
];
727 MakeProcName(procname
, cp
->pid
);
728 (void) strcat(procname
, "/sigact");
729 (void) memset((char *)action
, 0, sizeof (action
));
730 if ((fd
= open(procname
, O_RDONLY
, 0)) >= 0) {
731 (void) read(fd
, (char *)action
, sizeof (action
));
734 for (i
= 0; i
< MAXSIG
; i
++)
735 cp
->user
.u_signal
[i
] = action
[i
].sa_handler
;
736 cp
->flags
|= CS_SIGNAL
;