db_trace.c revision 85246
1/*- 2 * Copyright (c) 2001 Jake Burkholder. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/sys/sparc64/sparc64/db_trace.c 85246 2001-10-20 17:10:34Z jake $ 27 */ 28 29#include <sys/param.h> 30#include <sys/systm.h> 31#include <sys/linker_set.h> 32#include <sys/proc.h> 33#include <sys/user.h> 34 35#include <vm/vm.h> 36#include <vm/vm_page.h> 37#include <vm/vm_map.h> 38 39#include <machine/cpu.h> 40#include <machine/trap.h> 41#include <machine/vmparam.h> 42 43#include <ddb/ddb.h> 44#include <ddb/db_access.h> 45#include <ddb/db_sym.h> 46#include <ddb/db_variables.h> 47#include <ddb/db_watch.h> 48 49static db_varfcn_t db_show_in0; 50static db_varfcn_t db_show_in1; 51static db_varfcn_t db_show_in2; 52static db_varfcn_t db_show_in3; 53static db_varfcn_t db_show_in4; 54static db_varfcn_t db_show_in5; 55static db_varfcn_t db_show_in6; 56static db_varfcn_t db_show_in7; 57static db_varfcn_t db_show_local0; 58static db_varfcn_t db_show_local1; 59static db_varfcn_t db_show_local2; 60static db_varfcn_t db_show_local3; 61static db_varfcn_t db_show_local4; 62static db_varfcn_t db_show_local5; 63static db_varfcn_t db_show_local6; 64static db_varfcn_t db_show_local7; 65 66static int db_print_trap(struct trapframe *); 67 68extern char _start[]; 69extern char _end[]; 70 71#define INKERNEL(va) \ 72 ((va) >= (u_long)_start && (va) <= (u_long)_end) 73 74struct db_variable db_regs[] = { 75 { "g0", &ddb_regs.tf_global[0], FCN_NULL }, 76 { "g1", &ddb_regs.tf_global[1], FCN_NULL }, 77 { "g2", &ddb_regs.tf_global[2], FCN_NULL }, 78 { "g3", &ddb_regs.tf_global[3], FCN_NULL }, 79 { "g4", &ddb_regs.tf_global[4], FCN_NULL }, 80 { "g5", &ddb_regs.tf_global[5], FCN_NULL }, 81 { "g6", &ddb_regs.tf_global[6], FCN_NULL }, 82 { "g7", &ddb_regs.tf_global[7], FCN_NULL }, 83 { "i0", NULL, db_show_in0 }, 84 { "i1", NULL, db_show_in1 }, 85 { "i2", NULL, db_show_in2 }, 86 { "i3", NULL, db_show_in3 }, 87 { "i4", NULL, db_show_in4 }, 88 { "i5", NULL, db_show_in5 }, 89 { "i6", NULL, db_show_in6 }, 90 { "i7", NULL, db_show_in7 }, 91 { "l0", NULL, db_show_local0 }, 92 { "l1", NULL, db_show_local1 }, 93 { "l2", NULL, db_show_local2 }, 94 { "l3", NULL, db_show_local3 }, 95 { "l4", NULL, db_show_local4 }, 96 { "l5", NULL, db_show_local5 }, 97 { "l6", NULL, db_show_local6 }, 98 { "l7", NULL, db_show_local7 }, 99 { "tstate", &ddb_regs.tf_tstate, FCN_NULL }, 100 { "tpc", &ddb_regs.tf_tpc, FCN_NULL }, 101 { "tnpc", &ddb_regs.tf_tnpc, FCN_NULL } 102}; 103struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); 104 105void 106db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, 107 char *modif) 108{ 109 struct trapframe *tf; 110 struct kdbframe *kfp; 111 struct frame *fp; 112 const char *name; 113 c_db_sym_t sym; 114 db_expr_t offset; 115 db_expr_t value; 116 db_addr_t nfp; 117 db_addr_t npc; 118 db_addr_t pc; 119 int trap; 120 int user; 121 122 trap = 0; 123 user = 0; 124 npc = 0; 125 if (count == -1) 126 count = 1024; 127 if (!have_addr) { 128 kfp = (struct kdbframe *)DDB_REGS->tf_arg; 129 fp = (struct frame *)(kfp->kf_cfp + SPOFF); 130 } else 131 fp = (struct frame *)(addr + SPOFF); 132 while (count-- && !user) { 133 pc = (db_addr_t)db_get_value((db_addr_t)&fp->f_pc, 134 sizeof(db_addr_t), FALSE); 135 if (trap) { 136 pc = npc; 137 trap = 0; 138 } 139 if (!INKERNEL((vm_offset_t)pc)) 140 break; 141 sym = db_search_symbol(pc, DB_STGY_ANY, &offset); 142 if (sym == C_DB_SYM_NULL) { 143 value = 0; 144 name = NULL; 145 } else 146 db_symbol_values(sym, &name, &value); 147 if (name == NULL) 148 name = "(null)"; 149 if (bcmp(name, "tl0_", 4) == 0 || 150 bcmp(name, "tl1_", 4) == 0) { 151 nfp = db_get_value((db_addr_t)&fp->f_fp, 152 sizeof(u_long), FALSE) + SPOFF; 153 tf = (struct trapframe *)(nfp + sizeof(*fp)); 154 npc = db_get_value((db_addr_t)&tf->tf_tpc, 155 sizeof(u_long), FALSE); 156 user = db_print_trap(tf); 157 trap = 1; 158 } else { 159 db_printf("%s() at ", name); 160 db_printsym(pc, DB_STGY_PROC); 161 db_printf("\n"); 162 } 163 fp = (struct frame *)(db_get_value((db_addr_t)&fp->f_fp, 164 sizeof(u_long), FALSE) + SPOFF); 165 } 166} 167 168static int 169db_print_trap(struct trapframe *tf) 170{ 171 struct mmuframe *mf; 172 u_long type; 173 u_long va; 174 175 type = db_get_value((db_addr_t)&tf->tf_type, sizeof(u_long), FALSE); 176 db_printf("-- %s trap (%s) -- ", type & T_KERNEL ? "kernel" : "user", 177 trap_msg[type & ~T_KERNEL]); 178 if ((type & T_KERNEL) == 0) 179 db_printf("tpc=0x%lx, tnpc=0x%lx ", tf->tf_tpc, tf->tf_tnpc); 180 switch (type & ~T_KERNEL) { 181 case T_ALIGN: 182 mf = (struct mmuframe *)db_get_value((db_addr_t)&tf->tf_arg, 183 sizeof(void *), FALSE); 184 va = (u_long)db_get_value((db_addr_t)&mf->mf_sfar, 185 sizeof(u_long), FALSE); 186 db_printf("va=%#lx", va); 187 break; 188 default: 189 break; 190 } 191 db_printf("\n"); 192 return ((type & T_KERNEL) == 0); 193} 194 195DB_COMMAND(down, db_frame_down) 196{ 197 struct kdbframe *kfp; 198 struct frame *fp; 199 u_long cfp; 200 u_long ofp; 201 202 kfp = (struct kdbframe *)DDB_REGS->tf_arg; 203 fp = (struct frame *)(kfp->kf_fp + SPOFF); 204 cfp = kfp->kf_cfp; 205 for (;;) { 206 if (!INKERNEL((u_long)fp)) { 207 db_printf("already at bottom\n"); 208 break; 209 } 210 ofp = db_get_value((db_addr_t)&fp->f_fp, sizeof(u_long), 211 FALSE); 212 if (ofp == cfp) { 213 kfp->kf_cfp = (u_long)fp - SPOFF; 214 break; 215 } 216 fp = (struct frame *)(ofp + SPOFF); 217 } 218} 219 220DB_COMMAND(up, db_frame_up) 221{ 222 struct kdbframe *kfp; 223 struct frame *cfp; 224 225 kfp = (struct kdbframe *)DDB_REGS->tf_arg; 226 cfp = (struct frame *)(kfp->kf_cfp + SPOFF); 227 if (!INKERNEL((u_long)cfp)) { 228 db_printf("already at top\n"); 229 return; 230 } 231 kfp->kf_cfp = db_get_value((db_addr_t)&cfp->f_fp, sizeof(u_long), 232 FALSE); 233} 234 235#define DB_SHOW_REG(name, num) \ 236static int \ 237db_show_ ## name ## num(struct db_variable *dp, db_expr_t *vp, int op) \ 238{ \ 239 struct kdbframe *kfp; \ 240 struct frame *fp; \ 241 \ 242 kfp = (struct kdbframe *)DDB_REGS->tf_arg; \ 243 fp = (struct frame *)(kfp->kf_cfp + SPOFF); \ 244 if (op == DB_VAR_GET) \ 245 *vp = db_get_value((db_addr_t)&fp->f_ ## name ## [num], \ 246 sizeof(u_long), FALSE); \ 247 else \ 248 db_put_value((db_addr_t)&fp->f_ ## name ## [num], \ 249 sizeof(u_long), *vp); \ 250 return (0); \ 251} 252 253DB_SHOW_REG(in, 0) 254DB_SHOW_REG(in, 1) 255DB_SHOW_REG(in, 2) 256DB_SHOW_REG(in, 3) 257DB_SHOW_REG(in, 4) 258DB_SHOW_REG(in, 5) 259DB_SHOW_REG(in, 6) 260DB_SHOW_REG(in, 7) 261DB_SHOW_REG(local, 0) 262DB_SHOW_REG(local, 1) 263DB_SHOW_REG(local, 2) 264DB_SHOW_REG(local, 3) 265DB_SHOW_REG(local, 4) 266DB_SHOW_REG(local, 5) 267DB_SHOW_REG(local, 6) 268DB_SHOW_REG(local, 7) 269