xref: /titanic_44/usr/src/lib/libc/port/gen/walkstack.c (revision 99ebb4ca412cb0a19d77a3899a87c055b9c30fa8)
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  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * This file provides a general purpose mechanism
30  * for a user thread to walk its own call stack,
31  * calling a user-specified iterator function for each
32  * stack frame.  Special handling is provided to indicate
33  * kernel-constructed signal handler frames.
34  *
35  * Adapted from usr/src/lib/libproc/common/Pstack.c:
36  *
37  * A signal handler frame is essentially a set of data pushed on to the user
38  * stack by the kernel prior to returning to the user program in one of the
39  * pre-defined signal handlers.  The signal handler itself receives the signal
40  * number, an optional pointer to a siginfo_t, and a pointer to the interrupted
41  * ucontext as arguments.
42  *
43  * When performing a stack backtrace, we would like to
44  * detect these frames so that we can correctly return the interrupted program
45  * counter and frame pointer as a separate frame.
46  *
47  * The stack layout for a signal handler frame is as follows:
48  *
49  * SPARC v7/v9:                           Intel ia32:
50  * +--------------+ -        high         +--------------+ -
51  * |  struct fq   | ^        addrs        |  siginfo_t   | optional
52  * +--------------+ |          ^          +--------------+ -
53  * |  gwindows_t  |            |          |  ucontext_t  | ^
54  * +--------------+ optional              +--------------+ |
55  * |  siginfo_t   |                       | ucontext_t * | |
56  * +--------------+ |          |          +--------------+
57  * |  xregs data  | v          v          |  siginfo_t * | mandatory
58  * +--------------+ -         low         +--------------+
59  * |  ucontext_t  | ^        addrs        |  int (signo) | |
60  * +--------------+ mandatory             +--------------+ |
61  * | struct frame | v                     | struct frame | v
62  * +--------------+ - <- %sp on resume    +--------------+ - <- %esp on resume
63  *
64  * amd64 (64-bit)
65  * +--------------+ -
66  * |  siginfo_t   | optional
67  * +--------------+ -
68  * |  ucontext_t  | ^
69  * +--------------+ |
70  * |  siginfo_t * |
71  * +--------------+ mandatory
72  * |  int (signo) |
73  * +--------------+ |
74  * | struct frame | v
75  * +--------------+ - <- %rsp on resume
76  *
77  * The bottom-most struct frame is actually constructed by the kernel by
78  * copying the previous stack frame, allowing naive backtrace code to simply
79  * skip over the interrupted frame.  The copied frame is never really used,
80  * since it is presumed the libc or libthread signal handler wrapper function
81  * will explicitly setcontext(2) to the interrupted context if the user
82  * program's handler returns.  If we detect a signal handler frame, we simply
83  * read the interrupted context structure from the stack, use its embedded
84  * gregs to construct the register set for the interrupted frame, and then
85  * continue our backtrace.  Detecting the frame itself is easy according to
86  * the diagram ("oldcontext" represents any element in the uc_link chain):
87  *
88  * On SPARC v7 or v9:
89  * %fp + sizeof (struct frame) == oldcontext
90  *
91  * On i386:
92  * %ebp + sizeof (struct frame) + (3 words) == oldcontext
93  *
94  * On amd64:
95  * %rbp + sizeof (struct frame) + (2 words) == oldcontext
96  *
97  * Since we want to provide the signal number that generated a signal stack
98  * frame and on sparc this information isn't written to the stack by the kernel
99  * the way it's done on i386, we're forced to read the signo from the stack as
100  * one of the arguments to the signal handler.  What we hope is that no one has
101  * used __sigaction directly; if we're not linked with libthread
102  * (_thr_sighndlrinfo is NULL) then we attempt to read the signo directly from
103  * the register window. Otherwise we use the _thr_sighndlrinfo interface to find
104  * the correct frame.
105  *
106  */
107 
108 #pragma weak walkcontext = _walkcontext
109 #pragma weak printstack = _printstack
110 
111 #include "synonyms.h"
112 #include <assert.h>
113 #include <dlfcn.h>
114 #include <fcntl.h>
115 #include <link.h>
116 #include <procfs.h>
117 #include <strings.h>
118 #include <signal.h>
119 #include <sys/frame.h>
120 #include <sys/regset.h>
121 #include <sys/types.h>
122 #include <sys/uio.h>
123 #include <thread.h>
124 #include <ucontext.h>
125 #include <unistd.h>
126 #include <stdarg.h>
127 #include <sys/stack.h>
128 #include <errno.h>
129 #include <stdio.h>
130 #include <alloca.h>
131 #include <limits.h>
132 
133 #ifdef _LP64
134 #define	_ELF64
135 #endif
136 
137 #include <sys/machelf.h>
138 
139 
140 #if defined(__sparc)
141 #define	FRAME_PTR_REGISTER REG_SP
142 #define	PC_REGISTER REG_PC
143 #define	CHECK_FOR_SIGFRAME(fp, oldctx) ((fp) + SA(sizeof (struct frame)) \
144 	== (oldctx))
145 
146 #elif defined(__amd64)
147 #define	FRAME_PTR_REGISTER	REG_RBP
148 #define	PC_REGISTER		REG_RIP
149 #define	CHECK_FOR_SIGFRAME(fp, oldctx) ((((fp) + sizeof (struct frame)) + \
150 	2 * sizeof (long) == (oldctx)) && \
151 	(((struct frame *)fp)->fr_savpc == (greg_t)-1))
152 
153 #elif defined(__i386)
154 #define	FRAME_PTR_REGISTER EBP
155 #define	PC_REGISTER EIP
156 #define	CHECK_FOR_SIGFRAME(fp, oldctx) ((((fp) + sizeof (struct frame)) + \
157 	3 * sizeof (int) == (oldctx)) && \
158 	(((struct frame *)fp)->fr_savpc == (greg_t)-1))
159 #else
160 #error no arch defined
161 #endif
162 
163 
164 /*
165  * use /proc/self/as to safely dereference pointers so we don't
166  * die in the case of a stack smash
167  */
168 
169 static int
170 read_safe(int fd, struct frame *fp, struct frame **savefp, uintptr_t *savepc)
171 {
172 
173 	uintptr_t newfp;
174 
175 	if ((uintptr_t)fp & (sizeof (void *) - 1))
176 		return (-1); /* misaligned */
177 
178 	if ((pread(fd, (void *)&newfp, sizeof (fp->fr_savfp),
179 	    (off_t)&fp->fr_savfp) != sizeof (fp->fr_savfp)) ||
180 	    pread(fd, (void *)savepc, sizeof (fp->fr_savpc),
181 	    (off_t)&fp->fr_savpc) != sizeof (fp->fr_savpc))
182 		return (-1);
183 
184 	/*
185 	 * handle stack bias on sparcv9
186 	 */
187 
188 	if (newfp != 0)
189 		newfp += STACK_BIAS;
190 
191 	*savefp = (struct frame *)newfp;
192 
193 	return (0);
194 }
195 
196 int
197 walkcontext(const ucontext_t *uptr, int (*operate_func)(uintptr_t, int, void *),
198     void *usrarg)
199 {
200 	ucontext_t *oldctx = uptr->uc_link;
201 
202 	int	fd;
203 	int 	sig;
204 #if defined(__sparc)
205 	int 	signo = 0;
206 #endif
207 
208 	struct frame *savefp;
209 	uintptr_t savepc;
210 
211 	/*
212 	 * snag frame point from ucontext... we'll see caller of
213 	 * getucontext since we'll start by working up the call
214 	 * stack by one
215 	 */
216 
217 	struct frame *fp = (struct frame *)
218 	    ((uintptr_t)uptr->uc_mcontext.gregs[FRAME_PTR_REGISTER] +
219 	    STACK_BIAS);
220 
221 	/*
222 	 * Since we don't write signo to the stack on sparc, we need
223 	 * to extract signo from the stack frames.  This is problematic
224 	 * in the case of libthread (libc has deterministic behavior)
225 	 * since we're not sure where we can do that safely.  An awkward
226 	 * interface was provided for this purpose in libthread:
227 	 * _thr_sighndlrinfo; this is documented in
228 	 * /shared/sac/PSARC/1999/024.  When called, this function
229 	 * returns the PC of a special function (and its size) that
230 	 * will be present in the stack frame if a signal was
231 	 * delivered and will have the following signature
232 	 * __sighndlr(int sig, siginfo_t *si, ucontex_t *uc,
233 	 *	void (*hndlr)())
234 	 * Since this function is written in assembler and doesn't
235 	 * perturb its registers, we can then read sig out of arg0
236 	 * when the saved pc is inside this function.
237 	 *
238 	 */
239 #if defined(__sparc)
240 
241 	uintptr_t special_pc = NULL;
242 	int special_size = 0;
243 
244 	extern void _thr_sighndlrinfo(void (**func)(), int *funcsize);
245 
246 #pragma weak _thr_sighndlrinfo
247 
248 	if (_thr_sighndlrinfo != NULL) {
249 		_thr_sighndlrinfo((void (**)())&special_pc, &special_size);
250 	}
251 #endif /* sparc */
252 
253 
254 	if ((fd = open("/proc/self/as", O_RDONLY)) < 0)
255 		return (-1);
256 
257 	while (fp != NULL) {
258 
259 		sig = 0;
260 
261 		/*
262 		 * get value of saved fp and pc w/o crashing
263 		 */
264 
265 		if (read_safe(fd, fp, &savefp, &savepc) != 0) {
266 			(void) close(fd);
267 			return (-1);
268 		}
269 
270 		if (savefp == NULL)
271 			break;
272 
273 		/*
274 		 * note that the following checks to see if we've got a
275 		 * special signal stack frame present; this allows us to
276 		 * detect signals and pass that info to the user stack walker
277 		 */
278 
279 		if (oldctx != NULL &&
280 		    CHECK_FOR_SIGFRAME((uintptr_t)savefp, (uintptr_t)oldctx)) {
281 
282 #if defined(__i386) || defined(__amd64)
283 			/*
284 			 * i386 and amd64 store signo on stack;
285 			 * simple to detect and use
286 			 */
287 			sig = *((int *)(savefp + 1));
288 #endif
289 
290 #if defined(__sparc)
291 			/*
292 			 * with sparc we need to handle
293 			 * single and multi-threaded cases
294 			 * separately
295 			 * If we're single threaded, the trampoline
296 			 * in libc will have the signo as the first
297 			 * argumment; we can snag that directly.
298 			 * In the case of threads, since there are multiple
299 			 * complex routines between kernel and user handler,
300 			 * we need to figure out where we can read signal from
301 			 * using _thr_sighndlrinfo - which we've already done
302 			 * for this signal, since it appeared on the stack
303 			 * before the signal frame.... sigh.
304 			 */
305 
306 			if (_thr_sighndlrinfo == NULL) /* single threaded */
307 				sig = fp->fr_arg[0];
308 			else
309 				sig = signo; /* already read - see below */
310 #endif
311 			/*
312 			 * this is the special signal frame, so cons up
313 			 * the saved fp & pc to pass to user's function
314 			 */
315 
316 			savefp = (struct frame *)
317 			    ((uintptr_t)oldctx->
318 			    uc_mcontext.gregs[FRAME_PTR_REGISTER] +
319 			    STACK_BIAS);
320 			savepc = oldctx->uc_mcontext.gregs[PC_REGISTER];
321 
322 			oldctx = oldctx->uc_link; /* handle nested signals */
323 		}
324 #if defined(__sparc)
325 
326 		/*
327 		 * lookahead code to find right spot to read signo from...
328 		 */
329 
330 		if (_thr_sighndlrinfo &&
331 		    savepc >= special_pc && savepc <
332 		    (special_pc + special_size))
333 			signo = fp->fr_arg[0];
334 #endif
335 
336 		/*
337 		 * call user-supplied function and quit if non-zero return.
338 		 */
339 
340 		if (operate_func((uintptr_t)savepc, sig, usrarg) != 0)
341 			break;
342 
343 		fp = savefp; /* up one in the call stack */
344 	}
345 
346 	(void) close(fd);
347 	return (0);
348 }
349 
350 static size_t
351 ulongtos(char *buffer, unsigned long x, int base)
352 {
353 	char local[80];
354 	static const char digits[] = "0123456789abcdef";
355 
356 	unsigned int n = sizeof (local) - 1;
357 	unsigned long rem;
358 	unsigned int  mod;
359 
360 	local[n] = 0;
361 
362 	rem = x;
363 
364 	do {
365 		switch (base) {
366 		case 10:
367 			mod = rem % 10;
368 			rem = rem / 10;
369 			break;
370 
371 		case 16:
372 			mod = rem & 15;
373 			rem = rem >> 4;
374 			break;
375 		default:
376 			return (0);
377 		}
378 		local[--n] = digits[mod];
379 	} while (rem != 0);
380 
381 	(void) strcpy(buffer, local + n);
382 
383 	return (sizeof (local) - n - 1);
384 }
385 
386 static void
387 async_filenoprintf(int filenum, const char *format, ...)
388 {
389 	const char *src = format;
390 	va_list ap;
391 	long i;
392 	struct iovec *iov;
393 	int cnt;
394 	int iter = 0;
395 
396 	/*
397 	 * count # of %'s.. max # of iovs is 2n + 1
398 	 */
399 
400 	for (cnt = i = 0; src[i] != '\0'; i++)
401 		if (src[i] == '%')
402 			cnt++;
403 
404 	iov = alloca((2 * cnt + 1) * sizeof (struct iovec));
405 
406 	va_start(ap, format);
407 
408 
409 	while (*src) {
410 
411 		iov[iter].iov_base = (char *)src;
412 		iov[iter].iov_len = 0;
413 
414 		while (*src && *src != '%') {
415 			iov[iter].iov_len++;
416 			src++;
417 		}
418 
419 		if (iov[iter].iov_len != 0)
420 			iter++;
421 
422 		if (*src == '%') {
423 			switch (*++src) {
424 			case 's':
425 				iov[iter].iov_base = va_arg(ap, char *);
426 				iov[iter].iov_len = strlen(iov[iter].iov_base);
427 				iter++;
428 				break;
429 			case 'd':
430 				iov[iter].iov_base = alloca(24);
431 
432 				i = va_arg(ap, long);
433 				if (i < 0) {
434 					*iov[iter].iov_base = '-';
435 					iov[iter].iov_len =
436 					    ulongtos(iov[iter].iov_base + 1,
437 					    -i, 10) + 1;
438 				} else
439 					iov[iter].iov_len =
440 					    ulongtos(iov[iter].iov_base,
441 					    i, 10);
442 				iter++;
443 				break;
444 			case 'x':
445 				iov[iter].iov_base = alloca(24);
446 				iov[iter].iov_len = ulongtos(iov[iter].iov_base,
447 				    va_arg(ap, unsigned long), 16);
448 				iter++;
449 				break;
450 
451 			case '%':
452 				iov[iter].iov_base = (char *)src;
453 				iov[iter].iov_len = 1;
454 				iter++;
455 				break;
456 			}
457 			src++;
458 		}
459 	}
460 	va_end(ap);
461 
462 	(void) writev(filenum, iov, iter);
463 
464 }
465 
466 static int
467 display_stack_info(uintptr_t pc, int signo, void *arg)
468 {
469 	Dl_info info;
470 
471 	char sigbuf[SIG2STR_MAX];
472 
473 	Sym *sym;
474 
475 	int filenum = (intptr_t)arg;
476 
477 	if (signo) {
478 		if (sig2str(signo, sigbuf) != 0)
479 			(void) strcpy(sigbuf, "?");
480 	}
481 
482 	if (dladdr1((void *) pc, &info, (void**) &sym, RTLD_DL_SYMENT) == 0) {
483 		/* no info at all */
484 		if (signo == 0)
485 			async_filenoprintf(filenum, "0x%x\n", pc);
486 		else
487 			async_filenoprintf(filenum,
488 			    "0x%x [ Signal %d (%s)]\n", pc,
489 			    (ulong_t)signo, sigbuf);
490 
491 	} else if ((pc - (unsigned long)info.dli_saddr) <
492 	    sym->st_size) {
493 		/* found a global symbol */
494 		if (signo == 0)
495 			async_filenoprintf(filenum, "%s:%s+0x%x\n",
496 			    info.dli_fname,
497 			    info.dli_sname,
498 			    pc - (unsigned long)info.dli_saddr);
499 		else
500 			async_filenoprintf(filenum,
501 			    "%s:%s+0x%x [ Signal %d (%s)]\n",
502 			    info.dli_fname,
503 			    info.dli_sname,
504 			    pc - (unsigned long)info.dli_saddr,
505 			    (ulong_t)signo, sigbuf);
506 	} else {
507 		/* found a static symbol */
508 		if (signo == 0)
509 			async_filenoprintf(filenum, "%s:0x%x\n",
510 			    info.dli_fname,
511 			    pc - (unsigned long)info.dli_fbase);
512 		else
513 			async_filenoprintf(filenum,
514 			    "%s:0x%x [ Signal %d (%s)]\n",
515 			    info.dli_fname,
516 			    pc - (unsigned long)info.dli_fbase,
517 			    (ulong_t)signo, sigbuf);
518 	}
519 
520 	return (0);
521 }
522 
523 int
524 printstack(int dofd)
525 {
526 	ucontext_t u;
527 
528 	if (getcontext(&u) < 0)
529 		return (-1);
530 
531 	return (walkcontext(&u, display_stack_info, (void*)(intptr_t)dofd));
532 }
533