1 /* $NetBSD: db_trace.c,v 1.37 2019/04/06 16:22:01 thorpej Exp $ */ 2 3 /* 4 * Mach Operating System 5 * Copyright (c) 1991,1990 Carnegie Mellon University 6 * All Rights Reserved. 7 * 8 * Permission to use, copy, modify and distribute this software and its 9 * documentation is hereby granted, provided that both the copyright 10 * notice and this permission notice appear in all copies of the 11 * software, derivative works or modified versions, and any portions 12 * thereof, and that both notices appear in supporting documentation. 13 * 14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 * 18 * Carnegie Mellon requests users of this software to return to 19 * 20 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 21 * School of Computer Science 22 * Carnegie Mellon University 23 * Pittsburgh PA 15213-3890 24 * 25 * any improvements or extensions that they make and grant Carnegie the 26 * rights to redistribute these changes. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.37 2019/04/06 16:22:01 thorpej Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/proc.h> 34 #include <sys/cpu.h> 35 #include <sys/systm.h> 36 37 #include <machine/db_machdep.h> 38 39 #include <ddb/db_access.h> 40 #include <ddb/db_user.h> 41 #include <ddb/db_sym.h> 42 #include <ddb/db_interface.h> 43 #include <ddb/db_output.h> 44 45 #define INKERNEL(va) (((vaddr_t)(va)) >= USRSTACK) 46 #ifdef _KERNEL 47 #define ONINTSTACK(fr) ( \ 48 (u_int)(fr) < (u_int)ddb_cpuinfo->eintstack && \ 49 (u_int)(fr) >= (u_int)ddb_cpuinfo->eintstack - INT_STACK_SIZE \ 50 ) 51 #else 52 #define ONINTSTACK(fr) (0) 53 #endif 54 55 #ifdef _KERNEL 56 static db_addr_t 57 db_fetch_word(const void *uaddr) 58 { 59 u_int val; 60 61 if (ufetch_int(uaddr, &val) != 0) 62 val = (u_int)-1; 63 return val; 64 } 65 #endif /* _KERNEL */ 66 67 void 68 db_stack_trace_print(db_expr_t addr, bool have_addr, 69 db_expr_t count, const char *modif, 70 void (*pr)(const char *, ...)) 71 { 72 struct frame *frame, *prevframe; 73 db_addr_t pc; 74 bool kernel_only = true; 75 bool trace_thread = false; 76 bool lwpaddr = false; 77 const char *cp = modif; 78 char c; 79 80 #ifdef _KERNEL 81 if (ddb_cpuinfo == NULL) 82 ddb_cpuinfo = curcpu(); 83 #endif 84 85 while ((c = *cp++) != 0) { 86 if (c == 'a') { 87 lwpaddr = true; 88 trace_thread = true; 89 } 90 if (c == 't') 91 trace_thread = true; 92 if (c == 'u') 93 kernel_only = false; 94 } 95 96 if (!have_addr) { 97 frame = (struct frame *)DDB_TF->tf_out[6]; 98 pc = DDB_TF->tf_pc; 99 } else { 100 if (trace_thread) { 101 struct proc *p; 102 struct pcb *pcb; 103 struct lwp *l; 104 if (lwpaddr) { 105 l = (struct lwp *)addr; 106 p = l->l_proc; 107 (*pr)("trace: pid %d ", p->p_pid); 108 } else { 109 (*pr)("trace: pid %d ", (int)addr); 110 #ifdef _KERNEL 111 p = proc_find_raw(addr); 112 if (p == NULL) { 113 (*pr)("not found\n"); 114 return; 115 } 116 l = LIST_FIRST(&p->p_lwps); 117 KASSERT(l != NULL); 118 #else 119 (*pr)("no proc_find_raw() in crash\n"); 120 return; 121 #endif 122 } 123 (*pr)("lid %d ", l->l_lid); 124 pcb = lwp_getpcb(l); 125 frame = (struct frame *)pcb->pcb_sp; 126 pc = pcb->pcb_pc; 127 (*pr)("at %p\n", frame); 128 } else { 129 frame = (struct frame *)addr; 130 pc = 0; 131 } 132 } 133 134 while (count--) { 135 int i; 136 db_expr_t offset; 137 const char *name; 138 db_addr_t prevpc; 139 140 #ifdef _KERNEL 141 #define FR(framep,field) (INKERNEL(framep) \ 142 ? (u_int)(framep)->field \ 143 : db_fetch_word(&(framep)->field)) 144 #else 145 /* XXX fix me, this is probably wrong */ 146 #define FR(framep,field) ((u_int)(framep)->field) 147 #endif 148 149 /* Fetch return address and arguments frame */ 150 prevpc = (db_addr_t)FR(frame, fr_pc); 151 prevframe = (struct frame *)FR(frame, fr_fp); 152 153 /* 154 * Switch to frame that contains arguments 155 */ 156 if (prevframe == NULL || (!INKERNEL(prevframe) && kernel_only)) 157 return; 158 159 if ((ONINTSTACK(frame) && !ONINTSTACK(prevframe)) || 160 (INKERNEL(frame) && !INKERNEL(prevframe))) { 161 /* We're crossing a trap frame; pc = %l1 */ 162 prevpc = (db_addr_t)FR(frame, fr_local[1]); 163 } 164 165 name = NULL; 166 if (INKERNEL(pc)) 167 db_find_sym_and_offset(pc, &name, &offset); 168 if (name == NULL) 169 (*pr)("0x%lx(", pc); 170 else 171 (*pr)("%s(", name); 172 173 /* 174 * Print %i0..%i5, hope these still reflect the 175 * actual arguments somewhat... 176 */ 177 for (i = 0; i < 6; i++) 178 (*pr)("0x%x%s", FR(frame, fr_arg[i]), 179 (i < 5) ? ", " : ") at "); 180 if (INKERNEL(prevpc)) 181 db_printsym(prevpc, DB_STGY_PROC, pr); 182 else 183 (*pr)("0x%lx", prevpc); 184 (*pr)("\n"); 185 186 pc = prevpc; 187 frame = prevframe; 188 } 189 } 190