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