1 /* $NetBSD: db_trace.c,v 1.4 2008/04/28 20:23:25 martin Exp $ */ 2 3 /* Inspired by reading alpha/db_trace.c */ 4 5 /*- 6 * Copyright (c) 2006 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * Author: Cherry G. Mathew 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 34 #include "opt_ddb.h" 35 36 #include <sys/param.h> 37 #include <sys/proc.h> 38 #include <sys/systm.h> 39 40 #include <machine/cpufunc.h> 41 #include <machine/md_var.h> 42 #include <machine/db_machdep.h> 43 44 #include <ddb/db_sym.h> 45 #include <ddb/db_access.h> 46 #include <ddb/db_output.h> 47 #include <ddb/db_variables.h> 48 #include <ddb/db_interface.h> 49 50 #include <ia64/unwind/decode.h> 51 #include <ia64/unwind/stackframe.h> 52 53 #if 0 54 #define UNWIND_DIAGNOSTIC 55 #endif 56 57 #define debug_frame_dump_XXX(uwf) \ 58 printf("Frame Dump: \n bsp = 0x%lx \n pfs = 0x%lx, SOL(pfs) = %lu \n rp = 0x%lx \n", \ 59 uwf->bsp, uwf->pfs, IA64_CFM_SOL(uwf->pfs), uwf->rp); \ 60 61 void 62 initunwindframe(struct unwind_frame *uwf, struct trapframe *tf); 63 void 64 rewindframe(struct unwind_frame *uwf, db_addr_t ip); 65 66 void 67 db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, 68 const char *modif, void (*pr)(const char *, ...)) 69 { 70 char c; 71 const char *cp = modif; 72 bool trace_thread = false; 73 bool trace_user = false; 74 struct trapframe *tf; 75 struct unwind_frame current_frame; 76 db_addr_t ip; 77 const char *name; 78 db_sym_t sym; 79 db_expr_t offset; 80 81 while ((c = *cp++) != 0) { 82 trace_thread |= c == 't'; 83 trace_user |= c == 'u'; 84 } 85 86 if (trace_user) { 87 (*pr)("User-space stack tracing not implemented yet. \n"); 88 return; 89 } 90 if (!have_addr) { 91 (*pr)("--Kernel Call Trace-- \n"); 92 93 tf = DDB_REGS; 94 ip = tf->tf_special.iip + ((tf->tf_special.psr >> 41) & 3); 95 96 initunwindframe(¤t_frame, tf); 97 98 #ifdef UNWIND_DIAGNOSTIC 99 struct unwind_frame *uwf = ¤t_frame; 100 debug_frame_dump_XXX(uwf); 101 #endif 102 patchunwindframe(¤t_frame, ip - kernstart, kernstart); 103 #ifdef UNWIND_DIAGNOSTIC 104 debug_frame_dump_XXX(uwf); 105 #endif 106 /* Get into unwind loop. */ 107 108 while(ip) { 109 sym = db_search_symbol(ip, DB_STGY_ANY, &offset); 110 db_symbol_values(sym, &name, NULL); 111 (*pr)("%s(...)\n", name); 112 113 ip = current_frame.rp; 114 115 if(!ip) break; 116 117 rewindframe(¤t_frame, ip); 118 } 119 120 return; 121 122 123 } else (*pr) ("Unwind from arbitrary addresses unimplemented. \n"); 124 125 126 if (trace_thread) { 127 (*pr)("trace by pid unimplemented. \n"); 128 return; 129 } 130 else { 131 (*pr)("trace from arbitrary trap frame address unimplemented. \n"); 132 } 133 134 } 135 136 extern db_addr_t ia64_unwindtab; 137 extern vsize_t ia64_unwindtablen; 138 139 140 /* Generates initial unwind frame context based on the contents 141 * of the trap frame, by consulting the Unwind library 142 * staterecord. If a register is of type enum UNSAVED, we fetch 143 * the live value of the register from the trapframe. 144 */ 145 146 void 147 initunwindframe(struct unwind_frame *uwf, struct trapframe *tf) 148 149 { 150 151 uwf->rp = tf->tf_special.rp; 152 153 /* ndirty = bsp - bspstore: , not the same as the definition in the spec. 154 * Gave me hell for a day! 155 * see: ia64/exception.S: exception_save_restore: */ 156 157 uwf->bsp = tf->tf_special.bspstore + tf->tf_special.ndirty; 158 uwf->bsp = ia64_bsp_adjust_ret(uwf->bsp, IA64_CFM_SOF(tf->tf_special.cfm)); 159 #ifdef UNWIND_DIAGNOSTIC 160 printf("inituwframe(): SOF(cfm) = %lu \n", IA64_CFM_SOF(tf->tf_special.cfm)); 161 #endif 162 uwf->pfs = tf->tf_special.pfs; 163 uwf->sp = uwf->psp = tf->tf_special.sp; 164 165 166 } 167 168 169 170 /* Single step the frame backward. 171 * Assumes unwind_frame is setup already. 172 */ 173 174 void 175 rewindframe(struct unwind_frame *uwf, db_addr_t ip) 176 { 177 /* XXX: Check for a stack switch */ 178 179 uwf->bsp = ia64_bsp_adjust_ret(uwf->bsp, IA64_CFM_SOL(uwf->pfs)); 180 uwf->sp = uwf->psp; 181 182 /* Pre-stomp frame dump */ 183 #ifdef UNWIND_DIAGNOSTIC 184 debug_frame_dump_XXX(uwf); 185 #endif 186 187 /* Stomp on rp and pfs 188 */ 189 patchunwindframe(uwf, ip - kernstart, kernstart); 190 191 #ifdef UNWIND_DIAGNOSTIC 192 debug_frame_dump_XXX(uwf); 193 #endif 194 195 } 196