1 /* $NetBSD: db_trace.c,v 1.27 2010/07/01 02:38:26 rmind Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * This code is derived from software contributed to The NetBSD Foundation 12 * by Ross Harvey. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 37 38 __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.27 2010/07/01 02:38:26 rmind Exp $"); 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/proc.h> 43 44 #include <machine/alpha.h> 45 #include <machine/db_machdep.h> 46 47 #include <alpha/alpha/db_instruction.h> 48 49 #include <ddb/db_sym.h> 50 #include <ddb/db_access.h> 51 #include <ddb/db_variables.h> 52 #include <ddb/db_output.h> 53 #include <ddb/db_interface.h> 54 55 /* 56 * Information about the `standard' Alpha function prologue. 57 */ 58 struct prologue_info { 59 int pi_reg_offset[32]; /* offset of registers in stack frame */ 60 u_int32_t pi_regmask; /* which registers are in frame */ 61 int pi_frame_size; /* frame size */ 62 }; 63 64 /* 65 * We use several symbols to take special action: 66 * 67 * Trap vectors, which use a different (fixed-size) stack frame: 68 * 69 * XentArith 70 * XentIF 71 * XentInt 72 * XentMM 73 * XentSys 74 * XentUna 75 */ 76 77 static struct special_symbol { 78 vaddr_t ss_val; 79 const char *ss_note; 80 } special_symbols[] = { 81 { (vaddr_t)&XentArith, "arithmetic trap" }, 82 { (vaddr_t)&XentIF, "instruction fault" }, 83 { (vaddr_t)&XentInt, "interrupt" }, 84 { (vaddr_t)&XentMM, "memory management fault" }, 85 { (vaddr_t)&XentSys, "syscall" }, 86 { (vaddr_t)&XentUna, "unaligned access fault" }, 87 { (vaddr_t)&XentRestart, "console restart" }, 88 { 0 } 89 }; 90 91 /* 92 * Decode the function prologue for the function we're in, and note 93 * which registers are stored where, and how large the stack frame is. 94 */ 95 static void 96 decode_prologue(db_addr_t callpc, db_addr_t func, 97 struct prologue_info *pi, void (*pr)(const char *, ...)) 98 { 99 long signed_immediate; 100 alpha_instruction ins; 101 db_expr_t pc; 102 103 pi->pi_regmask = 0; 104 pi->pi_frame_size = 0; 105 106 #define CHECK_FRAMESIZE \ 107 do { \ 108 if (pi->pi_frame_size != 0) { \ 109 (*pr)("frame size botch: adjust register offsets?\n"); \ 110 } \ 111 } while (0) 112 113 for (pc = func; pc < callpc; pc += sizeof(alpha_instruction)) { 114 ins.bits = *(unsigned int *)pc; 115 116 if (ins.mem_format.opcode == op_lda && 117 ins.mem_format.ra == 30 && 118 ins.mem_format.rb == 30) { 119 /* 120 * GCC 2.7-style stack adjust: 121 * 122 * lda sp, -64(sp) 123 */ 124 signed_immediate = (long)ins.mem_format.displacement; 125 /* 126 * The assumption here is that a positive 127 * stack offset is the function epilogue, 128 * which may come before callpc when an 129 * agressive optimizer (like GCC 3.3 or later) 130 * has moved part of the function "out of 131 * line", past the epilogue. Therefore, ignore 132 * the positive offset so that 133 * pi->pi_frame_size has the correct value 134 * when we reach callpc. 135 */ 136 if (signed_immediate <= 0) { 137 CHECK_FRAMESIZE; 138 pi->pi_frame_size += -signed_immediate; 139 } 140 } else if (ins.operate_lit_format.opcode == op_arit && 141 ins.operate_lit_format.function == op_subq && 142 ins.operate_lit_format.ra == 30 && 143 ins.operate_lit_format.rc == 30) { 144 /* 145 * EGCS-style stack adjust: 146 * 147 * subq sp, 64, sp 148 */ 149 CHECK_FRAMESIZE; 150 pi->pi_frame_size += ins.operate_lit_format.literal; 151 } else if (ins.mem_format.opcode == op_stq && 152 ins.mem_format.rb == 30 && 153 ins.mem_format.ra != 31) { 154 /* Store of (non-zero) register onto the stack. */ 155 signed_immediate = (long)ins.mem_format.displacement; 156 pi->pi_regmask |= 1 << ins.mem_format.ra; 157 pi->pi_reg_offset[ins.mem_format.ra] = signed_immediate; 158 } 159 } 160 } 161 162 static int 163 sym_is_trapsymbol(vaddr_t v) 164 { 165 int i; 166 167 for (i = 0; special_symbols[i].ss_val != 0; ++i) 168 if (v == special_symbols[i].ss_val) 169 return 1; 170 return 0; 171 } 172 173 static void 174 decode_syscall(int number, struct proc *p, void (*pr)(const char *, ...)) 175 { 176 177 (*pr)(" (%d)", number); 178 } 179 180 void 181 db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, 182 const char *modif, void (*pr)(const char *, ...)) 183 { 184 db_addr_t callpc, frame, symval; 185 struct prologue_info pi; 186 db_expr_t diff; 187 db_sym_t sym; 188 int i; 189 u_long tfps; 190 const char *symname; 191 struct pcb *pcbp; 192 const char *cp = modif; 193 struct trapframe *tf; 194 bool ra_from_tf; 195 u_long last_ipl = ~0L; 196 struct proc *p = NULL; 197 struct lwp *l = NULL; 198 char c; 199 bool trace_thread = false; 200 bool lwpaddr = false; 201 202 while ((c = *cp++) != 0) { 203 trace_thread |= c == 't'; 204 trace_thread |= c == 'a'; 205 lwpaddr |= c == 'a'; 206 } 207 208 if (!have_addr) { 209 p = curproc; 210 addr = DDB_REGS->tf_regs[FRAME_SP] - FRAME_SIZE * 8; 211 tf = (struct trapframe *)addr; 212 callpc = tf->tf_regs[FRAME_PC]; 213 frame = (db_addr_t)tf + FRAME_SIZE * 8; 214 ra_from_tf = true; 215 } else { 216 if (trace_thread) { 217 if (lwpaddr) { 218 l = (struct lwp *)addr; 219 p = l->l_proc; 220 (*pr)("trace: pid %d ", p->p_pid); 221 } else { 222 (*pr)("trace: pid %d ", (int)addr); 223 p = proc_find_raw(addr); 224 if (p == NULL) { 225 (*pr)("not found\n"); 226 return; 227 } 228 l = LIST_FIRST(&p->p_lwps); 229 KASSERT(l != NULL); 230 } 231 (*pr)("lid %d ", l->l_lid); 232 pcbp = lwp_getpcb(l); 233 addr = (db_expr_t)pcbp->pcb_hw.apcb_ksp; 234 callpc = pcbp->pcb_context[7]; 235 (*pr)("at 0x%lx\n", addr); 236 } else { 237 (*pr)("alpha trace requires known PC =eject=\n"); 238 return; 239 } 240 frame = addr; 241 tf = NULL; 242 ra_from_tf = false; 243 } 244 245 while (count--) { 246 sym = db_search_symbol(callpc, DB_STGY_ANY, &diff); 247 if (sym == DB_SYM_NULL) 248 break; 249 250 db_symbol_values(sym, &symname, (db_expr_t *)&symval); 251 252 if (callpc < symval) { 253 (*pr)("symbol botch: callpc 0x%lx < " 254 "func 0x%lx (%s)\n", callpc, symval, symname); 255 return; 256 } 257 258 /* 259 * XXX Printing out arguments is Hard. We'd have to 260 * keep lots of state as we traverse the frame, figuring 261 * out where the arguments to the function are stored 262 * on the stack. 263 * 264 * Even worse, they may be stored to the stack _after_ 265 * being modified in place; arguments are passed in 266 * registers. 267 * 268 * So, in order for this to work reliably, we pretty much 269 * have to have a kernel built with `cc -g': 270 * 271 * - The debugging symbols would tell us where the 272 * arguments are, how many there are, if there were 273 * any passed on the stack, etc. 274 * 275 * - Presumably, the compiler would be careful to 276 * store the argument registers on the stack before 277 * modifying the registers, so that a debugger could 278 * know what those values were upon procedure entry. 279 * 280 * Because of this, we don't bother. We've got most of the 281 * benefit of back tracking without the arguments, and we 282 * could get the arguments if we use a remote source-level 283 * debugger (for serious debugging). 284 */ 285 (*pr)("%s() at ", symname); 286 db_printsym(callpc, DB_STGY_PROC, pr); 287 (*pr)("\n"); 288 289 /* 290 * If we are in a trap vector, frame points to a 291 * trapframe. 292 */ 293 if (sym_is_trapsymbol(symval)) { 294 tf = (struct trapframe *)frame; 295 296 for (i = 0; special_symbols[i].ss_val != 0; ++i) 297 if (symval == special_symbols[i].ss_val) 298 (*pr)("--- %s", 299 special_symbols[i].ss_note); 300 301 tfps = tf->tf_regs[FRAME_PS]; 302 if (symval == (vaddr_t)&XentSys) 303 decode_syscall(tf->tf_regs[FRAME_V0], p, pr); 304 if ((tfps & ALPHA_PSL_IPL_MASK) != last_ipl) { 305 last_ipl = tfps & ALPHA_PSL_IPL_MASK; 306 if (symval != (vaddr_t)&XentSys) 307 (*pr)(" (from ipl %ld)", last_ipl); 308 } 309 (*pr)(" ---\n"); 310 if (tfps & ALPHA_PSL_USERMODE) { 311 (*pr)("--- user mode ---\n"); 312 break; /* Terminate search. */ 313 } 314 callpc = tf->tf_regs[FRAME_PC]; 315 frame = (db_addr_t)tf + FRAME_SIZE * 8; 316 ra_from_tf = true; 317 continue; 318 } 319 320 /* 321 * This is a bit trickier; we must decode the function 322 * prologue to find the saved RA. 323 * 324 * XXX How does this interact w/ alloca()?! 325 */ 326 decode_prologue(callpc, symval, &pi, pr); 327 if ((pi.pi_regmask & (1 << 26)) == 0) { 328 /* 329 * No saved RA found. We might have RA from 330 * the trap frame, however (e.g trap occurred 331 * in a leaf call). If not, we've found the 332 * root of the call graph. 333 */ 334 if (ra_from_tf) 335 callpc = tf->tf_regs[FRAME_RA]; 336 else { 337 (*pr)("--- root of call graph ---\n"); 338 break; 339 } 340 } else 341 callpc = *(u_long *)(frame + pi.pi_reg_offset[26]); 342 frame += pi.pi_frame_size; 343 ra_from_tf = false; 344 } 345 } 346