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 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD$"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/kdb.h> 33#include <sys/proc.h> 34#include <sys/stack.h> 35#include <sys/sysent.h> 36 37#include <vm/vm.h> 38#include <vm/vm_page.h> 39#include <vm/vm_map.h> 40 41#include <machine/cpu.h> 42#include <machine/pcb.h> 43#include <machine/stack.h> 44#include <machine/trap.h> 45#include <machine/vmparam.h> 46 47#include <ddb/ddb.h> 48#include <ddb/db_access.h> 49#include <ddb/db_sym.h> 50#include <ddb/db_variables.h> 51#include <ddb/db_watch.h> 52 53static db_varfcn_t db_frame; 54 55#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) 56struct db_variable db_regs[] = { 57 { "g0", DB_OFFSET(tf_global[0]), db_frame }, 58 { "g1", DB_OFFSET(tf_global[1]), db_frame }, 59 { "g2", DB_OFFSET(tf_global[2]), db_frame }, 60 { "g3", DB_OFFSET(tf_global[3]), db_frame }, 61 { "g4", DB_OFFSET(tf_global[4]), db_frame }, 62 { "g5", DB_OFFSET(tf_global[5]), db_frame }, 63 { "g6", DB_OFFSET(tf_global[6]), db_frame }, 64 { "g7", DB_OFFSET(tf_global[7]), db_frame }, 65 { "i0", DB_OFFSET(tf_out[0]), db_frame }, 66 { "i1", DB_OFFSET(tf_out[1]), db_frame }, 67 { "i2", DB_OFFSET(tf_out[2]), db_frame }, 68 { "i3", DB_OFFSET(tf_out[3]), db_frame }, 69 { "i4", DB_OFFSET(tf_out[4]), db_frame }, 70 { "i5", DB_OFFSET(tf_out[5]), db_frame }, 71 { "i6", DB_OFFSET(tf_out[6]), db_frame }, 72 { "i7", DB_OFFSET(tf_out[7]), db_frame }, 73 { "tnpc", DB_OFFSET(tf_tnpc), db_frame }, 74 { "tpc", DB_OFFSET(tf_tpc), db_frame }, 75 { "tstate", DB_OFFSET(tf_tstate), db_frame }, 76}; 77struct db_variable *db_eregs = db_regs + nitems(db_regs); 78 79static int 80db_frame(struct db_variable *vp, db_expr_t *valuep, int op) 81{ 82 uint64_t *reg; 83 84 if (kdb_frame == NULL) 85 return (0); 86 reg = (uint64_t*)((uintptr_t)kdb_frame + (uintptr_t)vp->valuep); 87 if (op == DB_VAR_GET) 88 *valuep = *reg; 89 else 90 *reg = *valuep; 91 return (1); 92} 93 94/* 95 * User stack trace (debugging aid). 96 */ 97static void 98db_utrace(struct thread *td, struct trapframe *tf, int count) 99{ 100 struct pcb *pcb; 101 db_addr_t sp, rsp, o7, pc; 102 int i, found; 103 104 pcb = td->td_pcb; 105 sp = db_get_value((db_addr_t)&tf->tf_sp, sizeof(tf->tf_sp), FALSE); 106 o7 = db_get_value((db_addr_t)&tf->tf_out[7], sizeof(tf->tf_out[7]), 107 FALSE); 108 pc = db_get_value((db_addr_t)&tf->tf_tpc, sizeof(tf->tf_tpc), FALSE); 109 db_printf("user trace: trap %%o7=%#lx\n", o7); 110 while (count-- && sp != 0 && !db_pager_quit) { 111 db_printf("pc %#lx, sp %#lx\n", pc, sp); 112 /* First, check whether the frame is in the pcb. */ 113 found = 0; 114 for (i = 0; i < pcb->pcb_nsaved; i++) { 115 if (pcb->pcb_rwsp[i] == sp) { 116 found = 1; 117 sp = pcb->pcb_rw[i].rw_in[6]; 118 pc = pcb->pcb_rw[i].rw_in[7]; 119 break; 120 } 121 } 122 if (!found) { 123 rsp = sp + SPOFF; 124 sp = 0; 125 if (copyin((void *)(rsp + offsetof(struct frame, fr_fp)), 126 &sp, sizeof(sp)) != 0 || 127 copyin((void *)(rsp + offsetof(struct frame, fr_pc)), 128 &pc, sizeof(pc)) != 0) 129 break; 130 } 131 } 132 db_printf("done\n"); 133} 134 135static int 136db_print_trap(struct thread *td, struct trapframe *tf, int count) 137{ 138 struct proc *p; 139 const char *symname; 140 c_db_sym_t sym; 141 db_expr_t diff; 142 db_addr_t func; 143 db_addr_t tpc; 144 u_long type; 145 u_long sfar; 146 u_long sfsr; 147 u_long tar; 148 u_long level; 149 u_long pil; 150 u_long code; 151 u_long o7; 152 int user; 153 154 p = td->td_proc; 155 type = db_get_value((db_addr_t)&tf->tf_type, 156 sizeof(tf->tf_type), FALSE); 157 db_printf("-- %s", trap_msg[type & ~T_KERNEL]); 158 switch (type & ~T_KERNEL) { 159 case T_DATA_PROTECTION: 160 tar = (u_long)db_get_value((db_addr_t)&tf->tf_tar, 161 sizeof(tf->tf_tar), FALSE); 162 db_printf(" tar=%#lx", tar); 163 /* fall through */ 164 case T_DATA_EXCEPTION: 165 case T_INSTRUCTION_EXCEPTION: 166 case T_MEM_ADDRESS_NOT_ALIGNED: 167 sfar = (u_long)db_get_value((db_addr_t)&tf->tf_sfar, 168 sizeof(tf->tf_sfar), FALSE); 169 sfsr = (u_long)db_get_value((db_addr_t)&tf->tf_sfsr, 170 sizeof(tf->tf_sfsr), FALSE); 171 db_printf(" sfar=%#lx sfsr=%#lx", sfar, sfsr); 172 break; 173 case T_DATA_MISS: 174 case T_INSTRUCTION_MISS: 175 tar = (u_long)db_get_value((db_addr_t)&tf->tf_tar, 176 sizeof(tf->tf_tar), FALSE); 177 db_printf(" tar=%#lx", tar); 178 break; 179 case T_SYSCALL: 180 code = db_get_value((db_addr_t)&tf->tf_global[1], 181 sizeof(tf->tf_global[1]), FALSE); 182 db_printf(" (%ld", code); 183 if (code >= 0 && code < p->p_sysent->sv_size) { 184 func = (db_addr_t)p->p_sysent->sv_table[code].sy_call; 185 sym = db_search_symbol(func, DB_STGY_ANY, &diff); 186 if (sym != DB_SYM_NULL && diff == 0) { 187 db_symbol_values(sym, &symname, NULL); 188 db_printf(", %s, %s", p->p_sysent->sv_name, 189 symname); 190 } 191 db_printf(")"); 192 } 193 break; 194 case T_INTERRUPT: 195 level = (u_long)db_get_value((db_addr_t)&tf->tf_level, 196 sizeof(tf->tf_level), FALSE); 197 pil = (u_long)db_get_value((db_addr_t)&tf->tf_pil, 198 sizeof(tf->tf_pil), FALSE); 199 db_printf(" level=%#lx pil=%#lx", level, pil); 200 break; 201 default: 202 break; 203 } 204 o7 = (u_long)db_get_value((db_addr_t)&tf->tf_out[7], 205 sizeof(tf->tf_out[7]), FALSE); 206 db_printf(" %%o7=%#lx --\n", o7); 207 user = (type & T_KERNEL) == 0; 208 if (user) { 209 tpc = db_get_value((db_addr_t)&tf->tf_tpc, 210 sizeof(tf->tf_tpc), FALSE); 211 db_printf("userland() at "); 212 db_printsym(tpc, DB_STGY_PROC); 213 db_printf("\n"); 214 db_utrace(td, tf, count); 215 } 216 return (user); 217} 218 219static int 220db_backtrace(struct thread *td, struct frame *fp, int count) 221{ 222 struct trapframe *tf; 223 const char *name; 224 c_db_sym_t sym; 225 db_expr_t offset; 226 db_expr_t value; 227 db_addr_t npc; 228 db_addr_t pc; 229 int trap; 230 int user; 231 232 if (count == -1) 233 count = 1024; 234 235 trap = 0; 236 user = 0; 237 npc = 0; 238 while (count-- && !user && !db_pager_quit) { 239 pc = (db_addr_t)db_get_value((db_addr_t)&fp->fr_pc, 240 sizeof(fp->fr_pc), FALSE); 241 if (trap) { 242 pc = npc; 243 trap = 0; 244 } 245 if (!INKERNEL((vm_offset_t)pc)) 246 break; 247 sym = db_search_symbol(pc, DB_STGY_ANY, &offset); 248 if (sym == C_DB_SYM_NULL) { 249 value = 0; 250 name = NULL; 251 } else 252 db_symbol_values(sym, &name, &value); 253 if (name == NULL) 254 name = "(null)"; 255 fp = (struct frame *)(db_get_value((db_addr_t)&fp->fr_fp, 256 sizeof(fp->fr_fp), FALSE) + SPOFF); 257 if ((value > (u_long)tl_trap_begin && 258 value < (u_long)tl_trap_end) || 259 (value > (u_long)tl_text_begin && 260 value < (u_long)tl_text_end)) { 261 tf = (struct trapframe *)(fp + 1); 262 npc = db_get_value((db_addr_t)&tf->tf_tpc, 263 sizeof(tf->tf_tpc), FALSE); 264 user = db_print_trap(td, tf, count); 265 trap = 1; 266 } else { 267 db_printf("%s() at ", name); 268 db_printsym(pc, DB_STGY_PROC); 269 db_printf("\n"); 270 } 271 } 272 return (0); 273} 274 275void 276db_trace_self(void) 277{ 278 279 db_backtrace(curthread, 280 (struct frame *)__builtin_frame_address(1), -1); 281} 282 283int 284db_trace_thread(struct thread *td, int count) 285{ 286 struct pcb *ctx; 287 288 ctx = kdb_thr_ctx(td); 289 return (db_backtrace(td, 290 (struct frame *)(ctx->pcb_sp + SPOFF), count)); 291} 292