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 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
38 #include <sys/types.h>
39 #include <sys/termio.h>
45 * Routines related to interprocess communication
46 * among the truss processes which are controlling
47 * multiple traced processes.
51 * Function prototypes for static routines in this module.
57 * Ensure everyone keeps out of each other's way
58 * while writing lines of trace output.
64 * Except for regions bounded by Eserialize()/Xserialize(),
65 * this is the only place anywhere in the program where a
66 * write() to the trace output file takes place, so here
67 * is where we detect errors writing to the output.
73 (void) fflush(stdout
);
76 if (ferror(stdout
) && errno
) /* error on write(), probably EPIPE */
77 interrupt
= SIGTERM
; /* post an interrupt */
81 * Eserialize() and Xserialize() are used to bracket
82 * a region which may produce large amounts of output,
83 * such as showargs()/dumpargs().
89 /* serialize output */
96 (void) fflush(stdout
);
101 * Enter critical region --- Wait on mutex, lock out other processes.
102 * Lock zero is used to serialize output in situations where multiple processes
103 * may be writing to stdout/stderr and order must be preserved. Most of these
105 * Lock one is used to protect the table of processes currently being traced
106 * every time a pid is added or removed from the table Ecritical(1)/Xcritical(1)
115 rv
= mutex_lock(&gps
->ps_mutex0
);
117 rv
= mutex_lock(&gps
->ps_mutex1
);
119 abend("Invalid mutex specified", NULL
);
127 errmsg("cannot grab mutex #", mnum
);
132 * Exit critical region ---
133 * Release other processes waiting on mutex.
141 rv
= mutex_unlock(&gps
->ps_mutex0
);
143 rv
= mutex_unlock(&gps
->ps_mutex1
);
145 abend("Invalid mutex specified", NULL
);
154 errmsg("cannot release mutex #", mnum
);
159 * Add process to set of those being traced.
162 procadd(pid_t spid
, const char *lwplist
)
171 for (i
= 0; i
< sizeof (gps
->tpid
) / sizeof (gps
->tpid
[0]); i
++) {
172 if (gps
->tpid
[i
] == 0) {
173 if (j
== -1) /* remember first vacant slot */
175 if (gps
->spid
[i
] == 0) /* this slot is better */
179 if (i
< sizeof (gps
->tpid
) / sizeof (gps
->tpid
[0]))
182 gps
->tpid
[j
] = getpid();
184 gps
->lwps
[j
] = lwplist
;
190 * Delete process from set of those being traced.
204 for (i
= 0; i
< sizeof (gps
->tpid
) / sizeof (gps
->tpid
[0]); i
++) {
205 if (gps
->tpid
[i
] == tpid
) {
214 * Determine if the lwp for this process should be traced.
217 lwptrace(pid_t spid
, lwpid_t lwpid
)
229 for (i
= 0; i
< sizeof (gps
->tpid
) / sizeof (gps
->tpid
[0]); i
++) {
230 if (gps
->tpid
[i
] == tpid
&&
231 gps
->spid
[i
] == spid
)
237 return (proc_lwp_in_set(lwps
, lwpid
));
241 * Check for open of a /proc/nnnnn file.
242 * Return 0 if this is not an open of a /proc file.
243 * Return 1 if the process opened itself.
244 * Return 2 if the process failed to open another process
245 * in truss's set of controlled processes.
246 * Return 3 if the process successfully opened another process
247 * in truss's set of controlled processes.
248 * We notify and wait for the other controlling truss process
249 * to terminate before returning in cases 2 and 3.
253 checkproc(private_t
*pri
)
255 char *path
= pri
->sys_path
;
256 const pstatus_t
*Psp
= Pstatus(Proc
);
257 struct ps_lwphandle
*Lwp
= pri
->Lwp
;
258 const lwpstatus_t
*Lsp
= pri
->lwpstat
;
259 int what
= Lsp
->pr_what
; /* one of the SYS_open* syscalls */
260 int err
= Lsp
->pr_errno
;
270 * A bit heuristic ...
271 * Test for the cases:
279 * .../1234/lwp/24/lwpctl
280 * Insert a '\0', if necessary, so the path becomes ".../1234".
282 * Along the way, watch out for /proc/self and /proc/1234/lwp/agent
284 if ((sp1
= strrchr(path
, '/')) == NULL
) /* last component */
286 else if (isdigit(*(sp1
+1))) {
288 while (--sp1
> path
&& isdigit(*sp1
))
292 } else if (strcmp(sp1
+1, "as") == 0 ||
293 strcmp(sp1
+1, "ctl") == 0) {
295 } else if (strcmp(sp1
+1, "lwpctl") == 0) {
297 * .../1234/lwp/24/lwpctl
298 * ............ ^-- sp1
300 if (sp1
-6 >= path
&& strncmp(sp1
-6, "/agent", 6) == 0)
303 while (--sp1
> path
&& isdigit(*sp1
))
307 (sp1
-= 4) <= path
||
308 strncmp(sp1
, "/lwp", 4) != 0)
311 } else if (strcmp(sp1
+1, "self") != 0) {
315 if ((sp2
= strrchr(path
, '/')) == NULL
)
320 if (strcmp(dirname
, "self") == 0) {
322 } else if ((pid
= strtol(dirname
, &next
, 10)) < 0 ||
323 *next
!= '\0') { /* dirname not a number */
335 if (!Pisprocdir(Proc
, dirname
) || /* file not in a /proc directory */
336 pid
== getpid() || /* process opened truss's /proc file */
337 pid
== 0) { /* process opened process 0 */
350 * Process did open a /proc file ---
352 if (pid
== Psp
->pr_pid
) { /* process opened its own /proc file */
354 * In SunOS 5.6 and beyond, self-opens always succeed.
360 * Search for a matching pid in our set of controlled processes.
362 for (i
= 0; i
< sizeof (gps
->tpid
)/sizeof (gps
->tpid
[0]); i
++) {
363 if (gps
->spid
[i
] == pid
) {
368 if (i
>= sizeof (gps
->tpid
) / sizeof (gps
->tpid
[0])) {
370 * The process opened a /proc file, but not one we care about.
376 * Notify and wait for the controlling process to terminate.
378 while (pid
&& gps
->tpid
[i
] == pid
) {
379 if (kill(pid
, SIGUSR1
) == -1)
381 (void) usleep(1000000);
384 if (gps
->tpid
[i
] == 0)
388 if (err
) { /* prepare to reissue the failed open() system call */
390 (void) Lgetareg(Lwp
, R_PC
, &pc
);
391 if (pri
->sys_indirect
) {
392 (void) Lputareg(Lwp
, R_G1
, (prgreg_t
)SYS_syscall
);
393 (void) Lputareg(Lwp
, R_O0
, (prgreg_t
)what
);
394 for (i
= 0; i
< 5; i
++)
395 (void) Lputareg(Lwp
, R_O1
+i
, pri
->sys_args
[i
]);
397 (void) Lputareg(Lwp
, R_G1
, (prgreg_t
)what
);
398 for (i
= 0; i
< 6; i
++)
399 (void) Lputareg(Lwp
, R_O0
+i
, pri
->sys_args
[i
]);
401 (void) Lputareg(Lwp
, R_nPC
, pc
);
402 #elif defined(__amd64)
403 (void) Lgetareg(Lwp
, R_PC
, &pc
);
404 (void) Lputareg(Lwp
, REG_RAX
, (prgreg_t
)what
);
405 #elif defined(__i386)
406 (void) Lgetareg(Lwp
, R_PC
, &pc
);
407 (void) Lputareg(Lwp
, EAX
, (prgreg_t
)what
);
409 #error "unrecognized architecture"
411 (void) Pissyscall_prev(Proc
, pc
, (uintptr_t *)&pc
);
412 (void) Lputareg(Lwp
, R_PC
, pc
);