Home | History | Annotate | Download | only in diskomizer
      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 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"@(#)libstack_trace.c	1.13	09/05/26 SMI"
     28 
     29 /*
     30  * print a SPARC user land stack from a dynamic program.
     31  *
     32  *	Chris Gerhard - Computer Systems CTE - Sun Microsystems
     33  *	Chris.Gerhard (at) uk.sun.com
     34  */
     35 #ifndef _LARGEFILE64_SOURCE
     36 #define	_LARGEFILE64_SOURCE
     37 #endif
     38 
     39 #include <sys/stack.h>
     40 #include <dlfcn.h>
     41 #include <ucontext.h>
     42 #include <stdio.h>
     43 #include <diskomizer/stack_trace.h>
     44 #include <diskomizer/assert.h>
     45 #ifdef __sparc
     46 #include <demangle.h>
     47 #include "sparc_asm.h"
     48 #define	FRAME_SP 6
     49 #ifndef STACK_BIAS
     50 #define	STACK_BIAS 0
     51 #endif
     52 
     53 struct frame {
     54 	void *l[8];
     55 	void *i[8];
     56 };
     57 void
     58 ftraceback(int (*func)(void *arg, const char *fmt, ...),
     59 	void *out, ucontext_t *ucp)
     60 {
     61 	Dl_info dli;
     62 	struct frame *f;
     63 	const char *x;
     64 	ulong_t diff;
     65 	char buf[1024];
     66 	ulong_t stack;
     67 #define	pc  ucp->uc_mcontext.gregs[REG_PC]
     68 	flush_windows();
     69 	if (dladdr((void *)ucp->uc_mcontext.gregs[REG_PC], &dli) <= 0) {
     70 		func(out,
     71 		    "pc %#x %s:%#x "
     72 		    "(%#x, %#x, %#x, %#x, %#x, %#x)\n",
     73 		    pc, "unknown", pc,
     74 		    ucp->uc_mcontext.gregs[REG_O0],
     75 		    ucp->uc_mcontext.gregs[REG_O1],
     76 		    ucp->uc_mcontext.gregs[REG_O2],
     77 		    ucp->uc_mcontext.gregs[REG_O3],
     78 		    ucp->uc_mcontext.gregs[REG_O4],
     79 		    ucp->uc_mcontext.gregs[REG_O5]);
     80 	} else {
     81 		diff = (ulong_t)pc - (ulong_t)dli.dli_saddr;
     82 
     83 		if (cplus_demangle(dli.dli_sname, buf, sizeof (buf)) !=
     84 		    DEMANGLE_ESPACE)
     85 			x = &buf[0];
     86 		else
     87 			x = dli.dli_sname;
     88 
     89 		if (diff)
     90 			func(out,
     91 			    "pc %#lx %s:%s+%#lx "
     92 			    "(%#lx, %#lx, %#lx, %#lx, %#lx, %#lx)\n",
     93 			    ucp->uc_mcontext.gregs[REG_PC],
     94 			    dli.dli_fname, x, diff,
     95 			    ucp->uc_mcontext.gregs[REG_O0],
     96 			    ucp->uc_mcontext.gregs[REG_O1],
     97 			    ucp->uc_mcontext.gregs[REG_O2],
     98 			    ucp->uc_mcontext.gregs[REG_O3],
     99 			    ucp->uc_mcontext.gregs[REG_O4],
    100 			    ucp->uc_mcontext.gregs[REG_O5]);
    101 		else
    102 			func(out,
    103 			    "pc %#lx %s:%s "
    104 			    "(%#lx, %#lx, %#lx, %#lx, %#lx, %#lx)\n",
    105 			    ucp->uc_mcontext.gregs[REG_PC],
    106 			    dli.dli_fname, x,
    107 			    ucp->uc_mcontext.gregs[REG_O0],
    108 			    ucp->uc_mcontext.gregs[REG_O1],
    109 			    ucp->uc_mcontext.gregs[REG_O2],
    110 			    ucp->uc_mcontext.gregs[REG_O3],
    111 			    ucp->uc_mcontext.gregs[REG_O4],
    112 			    ucp->uc_mcontext.gregs[REG_O5]);
    113 	}
    114 #undef pc
    115 #define	pc f->i[7]
    116 	stack = (ulong_t)ucp->uc_mcontext.gregs[REG_SP];
    117 	f = (struct frame *)(stack + STACK_BIAS);
    118 
    119 	for (stack = (ulong_t)ucp->uc_mcontext.gregs[REG_SP]; stack != 0 &&
    120 	    pc != 0; stack  = (ulong_t)f->i[FRAME_SP]) {
    121 		f = (struct frame *)(stack + STACK_BIAS);
    122 		if (dladdr(pc, &dli) <= 0) {
    123 			func(out,
    124 			    "pc %#lx %s:%#lx "
    125 			    "(%#lx, %#lx, %#lx, %#lx, %#lx, %#lx)\n",
    126 			    pc, "unknown", pc, diff,
    127 			    f->i[0], f->i[1], f->i[2], f->i[3],
    128 			    f->i[4], f->i[5]);
    129 			continue;
    130 		}
    131 		diff = (ulong_t)pc - (ulong_t)dli.dli_saddr;
    132 
    133 		if (cplus_demangle(dli.dli_sname, buf, sizeof (buf)) !=
    134 		    DEMANGLE_ESPACE)
    135 			x = &buf[0];
    136 		else
    137 			x = dli.dli_sname;
    138 
    139 		if (diff)
    140 			func(out,
    141 			    "pc %#lx %s:%s+%#lx "
    142 			    "(%#lx, %#lx, %#lx, %#lx, %#lx, %#lx)\n",
    143 			    pc, dli.dli_fname, x, diff,
    144 			    f->i[0], f->i[1], f->i[2], f->i[3],
    145 			    f->i[4], f->i[5]);
    146 		else
    147 			func(out,
    148 			    "pc %#lx %s:%s "
    149 			    "(%#lx, %#lx, %#lx, %#lx, %#lx, %#lx)\n",
    150 			    pc, dli.dli_fname, x,
    151 			    f->i[0], f->i[1], f->i[2], f->i[3],
    152 			    f->i[4], f->i[5]);
    153 	}
    154 #undef pc
    155 }
    156 #else /* Intel */
    157 #include <strings.h>
    158 
    159 /*
    160  * A not totally random guess at the length of the call instruction
    161  * used. This needs to be subtracted from the return address to
    162  * give an accurate picture of whence we came.
    163  */
    164 
    165 #define	CALL_LEN	5UL
    166 #define	ARGC_MAX	6
    167 
    168 void
    169 ftraceback(int (*func)(void *arg, const char *fmt, ...),
    170     void *out, ucontext_t *ucp)
    171 {
    172 	Dl_info dli;
    173 	ulong_t **ebp, **oebp;
    174 	ulong_t *args, *ret;
    175 	ulong_t nargs, pc, diff;
    176 	const char *x;
    177 #ifdef DO_DEMANGLE
    178 	char buf[128];
    179 #endif
    180 
    181 	ebp = (ulong_t **)(ucp->uc_mcontext.gregs[6]);
    182 	pc = ((ulong_t)(ucp->uc_mcontext.gregs[14])-CALL_LEN);
    183 
    184 	while (*ebp) {
    185 		char tmp[1024];
    186 		tmp[0] = NULL;
    187 		oebp = (ulong_t **)*ebp;
    188 		ret = ((ulong_t *)ebp + 1);
    189 
    190 		args = ret + 1;
    191 		nargs = ((ulong_t *)oebp) - args;
    192 
    193 		if (dladdr((void *)pc, &dli) <= 0) {
    194 			snprintf(tmp, sizeof (tmp), "pc %#x %s:%#x ",
    195 			    pc, "unknown", pc);
    196 		} else {
    197 			diff = (ulong_t)pc - (ulong_t)dli.dli_saddr;
    198 
    199 			/*
    200 			 * A bug in the libdemangle.so on Intel
    201 			 * means we currently don't handle mangled
    202 			 * c++ object names.
    203 			 */
    204 #ifdef DO_DEMANGLE
    205 			if (cplus_demangle(dli.dli_sname, buf,
    206 			    sizeof (buf)) != *DEMANGLE_ESPACE) {
    207 				x = &buf[0];
    208 			} else {
    209 				x = dli.dli_sname;
    210 			}
    211 #else
    212 			x = dli.dli_sname;
    213 #endif
    214 
    215 			if (diff) {
    216 				snprintf(tmp, sizeof (tmp),
    217 				    "pc %#lx %s:%s+%#lx ",
    218 				    pc, dli.dli_fname, x, diff);
    219 			} else {
    220 				snprintf(tmp, sizeof (tmp), "pc %#lx %s:%s ",
    221 				    pc, dli.dli_fname, x);
    222 			}
    223 		}
    224 
    225 		if (!nargs) {
    226 			int l = strlen(tmp);
    227 			snprintf(&tmp[l], sizeof (tmp) - l, "%s", "()");
    228 		} else {
    229 			int i, l;
    230 			l = strlen(tmp);
    231 			snprintf(&tmp[l], sizeof (tmp) - l, "(");
    232 			for (i = 0; i < ARGC_MAX && nargs; i++) {
    233 				l = strlen(tmp);
    234 				if (snprintf(&tmp[l], sizeof (tmp) - l,
    235 				    "%#x%s", *args, --nargs ? ", ": ")") >
    236 				    sizeof (tmp) - l)
    237 						break;
    238 				args += 1;
    239 			}
    240 		}
    241 		func(out, "%s\n", tmp);
    242 
    243 		ebp = oebp;
    244 		pc = (*ret)-CALL_LEN;
    245 	}
    246 }
    247 #endif /* Intel */
    248 void
    249 traceback(FILE *out, ucontext_t *ucp)
    250 {
    251 	ftraceback((int (*)(void *, const char *, ...))fprintf, (void *)out,
    252 	    ucp);
    253 	(void) fflush(out);
    254 }
    255 #ifdef  __cplusplus
    256 extern "C" {
    257 #endif
    258 void
    259 fprint_stack_trace(int (*out)(void *, const char *, ...),
    260 	void *arg)
    261 {
    262 	ucontext_t context;
    263 
    264 #ifdef __sparc
    265 	flush_windows();
    266 #endif
    267 	if (getcontext(&context) == -1)
    268 		return;
    269 
    270 	ftraceback(out, arg, &context);
    271 }
    272 void
    273 print_stack_trace(FILE *out)
    274 {
    275 	fprint_stack_trace((int (*)(void *, const char *, ...))fprintf,
    276 	    (void *)out);
    277 }
    278 #ifdef  __cplusplus
    279 }
    280 #endif
    281