xref: /titanic_44/usr/src/cmd/ptools/psig/psig.c (revision 1cb6af97c6f66f456d4f726ef056e1ebc0f73305)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <ctype.h>
33 #include <fcntl.h>
34 #include <string.h>
35 #include <signal.h>
36 #include <stddef.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <libproc.h>
40 
41 /* evil knowledge of libc internals */
42 #include "../../../lib/libc/inc/thr_uberdata.h"
43 
44 #define	MAX_SYMNAMLEN	1024	/* Recommended max symbol name length */
45 
46 static	char	*sigflags(int, int);
47 static	int	look(char *);
48 static	void	perr(char *);
49 static	int	usage(void);
50 static	uintptr_t deinterpose(int, void *, psinfo_t *, struct sigaction *);
51 
52 static	char	*command;
53 static	char	*procname;
54 static	int	all_flag = 0;
55 static	int	lookuphandlers_flag = 1;
56 
57 int
58 main(int argc, char **argv)
59 {
60 	int rc = 0;
61 	int c;
62 	struct rlimit rlim;
63 
64 	if ((command = strrchr(argv[0], '/')) != NULL)
65 		command++;
66 	else
67 		command = argv[0];
68 
69 	while ((c = getopt(argc, argv, "an")) != EOF) {
70 		switch (c) {
71 		case 'a':
72 			all_flag = 1;
73 			break;
74 		case 'n':
75 			lookuphandlers_flag = 0;
76 			break;
77 		default:
78 			return (usage());
79 		}
80 	}
81 
82 	if (argc - optind < 1) {
83 		return (usage());
84 	}
85 
86 	/*
87 	 * Make sure we'll have enough file descriptors to handle a target
88 	 * that has many many mappings.
89 	 */
90 	if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
91 		rlim.rlim_cur = rlim.rlim_max;
92 		(void) setrlimit(RLIMIT_NOFILE, &rlim);
93 	}
94 
95 	for (; optind != argc; optind++) {
96 		rc += look(argv[optind]);
97 	}
98 
99 	return (rc);
100 }
101 
102 static int
103 usage(void)
104 {
105 	(void) fprintf(stderr, "usage:\t%s [-n] pid ...\n", command);
106 	(void) fprintf(stderr, "  (report process signal actions)\n");
107 
108 	return (2);
109 }
110 
111 static uintptr_t
112 uberdata_addr(struct ps_prochandle *Pr, char dmodel)
113 {
114 	GElf_Sym sym;
115 
116 	if (Plookup_by_name(Pr, "libc.so", "_tdb_bootstrap", &sym) < 0)
117 		return (NULL);
118 #ifdef _LP64
119 	if (dmodel != PR_MODEL_NATIVE) {
120 		caddr32_t uaddr;
121 		caddr32_t addr;
122 
123 		if (Pread(Pr, &addr, sizeof (addr), sym.st_value)
124 		    == sizeof (addr) &&
125 		    addr != 0 &&
126 		    Pread(Pr, &uaddr, sizeof (uaddr), (uintptr_t)addr)
127 		    == sizeof (uaddr) &&
128 		    uaddr != 0)
129 			return ((uintptr_t)uaddr);
130 	}
131 #endif
132 	if (dmodel == PR_MODEL_NATIVE) {
133 		uintptr_t uaddr;
134 		uintptr_t addr;
135 
136 		if (Pread(Pr, &addr, sizeof (addr), sym.st_value)
137 		    == sizeof (addr) &&
138 		    addr != 0 &&
139 		    Pread(Pr, &uaddr, sizeof (uaddr), addr)
140 		    == sizeof (uaddr) &&
141 		    uaddr != 0)
142 			return (uaddr);
143 	}
144 	if (Plookup_by_name(Pr, "libc.so", "_uberdata", &sym) < 0)
145 		return (0);
146 	return (sym.st_value);
147 }
148 
149 /*
150  * Iterator function used to generate the process sigmask
151  * from the individual lwp sigmasks.
152  */
153 static int
154 lwp_iter(void *cd, const lwpstatus_t *lwpstatus)
155 {
156 	sigset_t *ssp = cd;
157 
158 	ssp->__sigbits[0] &= lwpstatus->pr_lwphold.__sigbits[0];
159 	ssp->__sigbits[1] &= lwpstatus->pr_lwphold.__sigbits[1];
160 	ssp->__sigbits[2] &= lwpstatus->pr_lwphold.__sigbits[2];
161 	ssp->__sigbits[3] &= lwpstatus->pr_lwphold.__sigbits[3];
162 
163 	/*
164 	 * Return non-zero to terminate the iteration
165 	 * if the sigmask has become all zeros.
166 	 */
167 	return ((ssp->__sigbits[0] | ssp->__sigbits[1] |
168 	    ssp->__sigbits[2] | ssp->__sigbits[3]) == 0);
169 }
170 
171 static int
172 look(char *arg)
173 {
174 	char pathname[100];
175 	struct stat statb;
176 	int fd = -1;
177 	int sig, gcode;
178 	sigset_t holdmask;
179 	int maxsig;
180 	struct sigaction *action = NULL;
181 	psinfo_t psinfo;
182 	const psinfo_t *psinfop;
183 	struct ps_prochandle *Pr = NULL;
184 	uintptr_t uberaddr;
185 	uintptr_t aharraddr;
186 	uintptr_t intfnaddr;
187 	size_t aharrlen;
188 	void *aharr = NULL;
189 	int error = 1;
190 
191 	procname = arg;		/* for perr() */
192 	if ((Pr = proc_arg_grab(arg, PR_ARG_PIDS, PGRAB_RDONLY|PGRAB_FORCE,
193 	    &gcode)) == NULL || (psinfop = Ppsinfo(Pr)) == NULL) {
194 		(void) fprintf(stderr, "%s: cannot examine %s: %s\n",
195 		    command, arg, Pgrab_error(gcode));
196 		goto look_error;
197 	}
198 	(void) memcpy(&psinfo, psinfop, sizeof (psinfo_t));
199 	proc_unctrl_psinfo(&psinfo);
200 
201 	(void) sprintf(pathname, "/proc/%d/sigact", (int)psinfo.pr_pid);
202 	if ((fd = open(pathname, O_RDONLY)) < 0) {
203 		perr("open sigact");
204 		goto look_error;
205 	}
206 
207 	if (fstat(fd, &statb) != 0) {
208 		perr("fstat sigact");
209 		goto look_error;
210 	}
211 	maxsig = statb.st_size / sizeof (struct sigaction);
212 	action = malloc(maxsig * sizeof (struct sigaction));
213 	if (action == NULL) {
214 		(void) fprintf(stderr,
215 		"%s: cannot malloc() space for %d sigaction structures\n",
216 			command, maxsig);
217 		goto look_error;
218 	}
219 	if (read(fd, (char *)action, maxsig * sizeof (struct sigaction)) !=
220 	    maxsig * sizeof (struct sigaction)) {
221 		perr("read sigact");
222 		goto look_error;
223 	}
224 	(void) close(fd);
225 	fd = -1;
226 
227 	(void) printf("%d:\t%.70s\n", (int)psinfo.pr_pid, psinfo.pr_psargs);
228 
229 	(void) sigfillset(&holdmask);
230 	(void) Plwp_iter(Pr, lwp_iter, &holdmask);
231 
232 	if ((uberaddr = uberdata_addr(Pr, psinfo.pr_dmodel)) == 0) {
233 		aharraddr = 0;
234 		aharrlen = 0;
235 		intfnaddr = 0;
236 	} else {
237 #ifdef _LP64
238 		if (psinfo.pr_dmodel != PR_MODEL_NATIVE) {
239 			caddr32_t addr;
240 			aharraddr = uberaddr +
241 				offsetof(uberdata32_t, siguaction);
242 			aharrlen = sizeof (siguaction32_t) * NSIG;
243 			(void) Pread(Pr, &addr, sizeof (addr),
244 			    uberaddr + offsetof(uberdata32_t, sigacthandler));
245 			intfnaddr = (uintptr_t)addr;
246 		} else
247 #endif
248 		{
249 			aharraddr = uberaddr +
250 				offsetof(uberdata_t, siguaction);
251 			aharrlen = sizeof (siguaction_t) * NSIG;
252 			(void) Pread(Pr, &intfnaddr, sizeof (intfnaddr),
253 			    uberaddr + offsetof(uberdata_t, sigacthandler));
254 		}
255 	}
256 
257 	if (aharraddr) {
258 		aharr = malloc(aharrlen);
259 		if (aharr == NULL) {
260 			(void) fprintf(stderr,
261 			"%s: cannot malloc() space for actual handler array\n",
262 			    command);
263 			goto look_error;
264 		}
265 
266 		if (Pread(Pr, aharr, aharrlen, aharraddr) != aharrlen) {
267 			(void) fprintf(stderr,
268 			    "%s: signal handler data at %p cannot be read.\n",
269 			    command, (void *)aharraddr);
270 			free(aharr);
271 			aharr = NULL;
272 		}
273 	}
274 
275 	for (sig = 1; sig <= maxsig; sig++) {
276 		struct sigaction *sp = &action[sig - 1];
277 		int caught = 0;
278 		char buf[SIG2STR_MAX];
279 		char *s;
280 
281 		/* proc_signame() returns "SIG..."; skip the "SIG" part */
282 		(void) printf("%s\t", proc_signame(sig, buf, sizeof (buf)) + 3);
283 
284 		if (prismember(&holdmask, sig))
285 			(void) printf("blocked,");
286 
287 		if (sp->sa_handler == SIG_DFL)
288 			(void) printf("default");
289 		else if (sp->sa_handler == SIG_IGN)
290 			(void) printf("ignored");
291 		else
292 			caught = 1;
293 
294 		if (caught || all_flag) {
295 			uintptr_t haddr;
296 			GElf_Sym hsym;
297 			char hname[MAX_SYMNAMLEN];
298 			char buf[PRSIGBUFSZ];
299 
300 			haddr = (uintptr_t)sp->sa_handler;
301 
302 			if (aharr && intfnaddr && haddr == intfnaddr)
303 				haddr = deinterpose(sig, aharr, &psinfo, sp);
304 
305 			if (haddr == (uintptr_t)SIG_DFL) {
306 				if (caught)
307 					(void) printf("default");
308 				caught = 0;
309 			} else if (haddr == (uintptr_t)SIG_IGN) {
310 				if (caught)
311 					(void) printf("ignored");
312 				caught = 0;
313 			} else {
314 				if (caught)
315 					(void) printf("caught");
316 			}
317 
318 			if (caught || all_flag) {
319 				if (lookuphandlers_flag && haddr > 1 &&
320 				    Plookup_by_addr(Pr, haddr, hname,
321 				    sizeof (hname), &hsym) == 0)
322 					(void) printf("\t%-8s", hname);
323 				else
324 					(void) printf("\t0x%-8lx",
325 						(ulong_t)haddr);
326 
327 				s = sigflags(sig, sp->sa_flags);
328 				(void) printf("%s", (*s != '\0')? s : "\t0");
329 				(void) proc_sigset2str(&sp->sa_mask, ",", 1,
330 				    buf, sizeof (buf));
331 				if (buf[0] != '\0')
332 					(void) printf("\t%s", buf);
333 			}
334 		} else if (sig == SIGCLD) {
335 			s = sigflags(sig,
336 				sp->sa_flags & (SA_NOCLDWAIT|SA_NOCLDSTOP));
337 			if (*s != '\0')
338 				(void) printf("\t\t%s", s);
339 		}
340 		(void) printf("\n");
341 	}
342 
343 	error = 0;
344 
345 look_error:
346 	if (fd >= 0)
347 		(void) close(fd);
348 	if (aharr)
349 		free(aharr);
350 	if (action)
351 		free(action);
352 	if (Pr)
353 		Prelease(Pr, 0);
354 	return (error);
355 }
356 
357 static void
358 perr(char *s)
359 {
360 	if (s)
361 		(void) fprintf(stderr, "%s: ", procname);
362 	else
363 		s = procname;
364 	perror(s);
365 }
366 
367 static char *
368 sigflags(int sig, int flags)
369 {
370 	static char code_buf[100];
371 	char *str = code_buf;
372 	int flagmask =
373 		(SA_ONSTACK|SA_RESETHAND|SA_RESTART|SA_SIGINFO|SA_NODEFER);
374 
375 	if (sig == SIGCLD)
376 		flagmask |= (SA_NOCLDSTOP|SA_NOCLDWAIT);
377 
378 	*str = '\0';
379 	if (flags & ~flagmask)
380 		(void) sprintf(str, ",0x%x,", flags & ~flagmask);
381 	else if (flags == 0)
382 		return (str);
383 
384 	if (flags & SA_RESTART)
385 		(void) strcat(str, ",RESTART");
386 	if (flags & SA_RESETHAND)
387 		(void) strcat(str, ",RESETHAND");
388 	if (flags & SA_ONSTACK)
389 		(void) strcat(str, ",ONSTACK");
390 	if (flags & SA_SIGINFO)
391 		(void) strcat(str, ",SIGINFO");
392 	if (flags & SA_NODEFER)
393 		(void) strcat(str, ",NODEFER");
394 
395 	if (sig == SIGCLD) {
396 		if (flags & SA_NOCLDWAIT)
397 			(void) strcat(str, ",NOCLDWAIT");
398 		if (flags & SA_NOCLDSTOP)
399 			(void) strcat(str, ",NOCLDSTOP");
400 	}
401 
402 	*str = '\t';
403 
404 	return (str);
405 }
406 
407 /*ARGSUSED2*/
408 static uintptr_t
409 deinterpose(int sig, void *aharr, psinfo_t *psinfo, struct sigaction *sp)
410 {
411 	if (sp->sa_handler == SIG_DFL || sp->sa_handler == SIG_IGN)
412 		return ((uintptr_t)sp->sa_handler);
413 #ifdef _LP64
414 	if (psinfo->pr_dmodel != PR_MODEL_NATIVE) {
415 		struct sigaction32 *sa32 = (struct sigaction32 *)
416 			((uintptr_t)aharr + sig * sizeof (siguaction32_t) +
417 			offsetof(siguaction32_t, sig_uaction));
418 
419 		sp->sa_flags = sa32->sa_flags;
420 		sp->sa_handler = (void (*)())(uintptr_t)sa32->sa_handler;
421 		(void) memcpy(&sp->sa_mask, &sa32->sa_mask,
422 			sizeof (sp->sa_mask));
423 	} else
424 #endif
425 	{
426 		struct sigaction *sa = (struct sigaction *)
427 			((uintptr_t)aharr + sig * sizeof (siguaction_t) +
428 			offsetof(siguaction_t, sig_uaction));
429 
430 		sp->sa_flags = sa->sa_flags;
431 		sp->sa_handler = sa->sa_handler;
432 		sp->sa_mask = sa->sa_mask;
433 	}
434 	return ((uintptr_t)sp->sa_handler);
435 }
436