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