1 /* $NetBSD: db_trace.c,v 1.33 2018/01/24 09:04:44 skrll Exp $ */ 2 3 /* 4 * Copyright (c) 2000, 2001 Ben Harris 5 * Copyright (c) 1996 Scott K. Stevens 6 * 7 * Mach Operating System 8 * Copyright (c) 1991,1990 Carnegie Mellon University 9 * All Rights Reserved. 10 * 11 * Permission to use, copy, modify and distribute this software and its 12 * documentation is hereby granted, provided that both the copyright 13 * notice and this permission notice appear in all copies of the 14 * software, derivative works or modified versions, and any portions 15 * thereof, and that both notices appear in supporting documentation. 16 * 17 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 18 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 19 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 20 * 21 * Carnegie Mellon requests users of this software to return to 22 * 23 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 24 * School of Computer Science 25 * Carnegie Mellon University 26 * Pittsburgh PA 15213-3890 27 * 28 * any improvements or extensions that they make and grant Carnegie the 29 * rights to redistribute these changes. 30 */ 31 32 #include <sys/param.h> 33 34 __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.33 2018/01/24 09:04:44 skrll Exp $"); 35 36 #include <sys/proc.h> 37 #include <arm/armreg.h> 38 #include <arm/cpufunc.h> 39 #include <arm/pcb.h> 40 #include <machine/db_machdep.h> 41 #include <machine/vmparam.h> 42 43 #include <ddb/db_access.h> 44 #include <ddb/db_interface.h> 45 #include <ddb/db_sym.h> 46 #include <ddb/db_proc.h> 47 #include <ddb/db_output.h> 48 49 #define INKERNEL(va) (((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS) 50 51 /* 52 * APCS stack frames are awkward beasts, so I don't think even trying to use 53 * a structure to represent them is a good idea. 54 * 55 * Here's the diagram from the APCS. Increasing address is _up_ the page. 56 * 57 * save code pointer [fp] <- fp points to here 58 * return link value [fp, #-4] 59 * return sp value [fp, #-8] 60 * return fp value [fp, #-12] 61 * [saved v7 value] 62 * [saved v6 value] 63 * [saved v5 value] 64 * [saved v4 value] 65 * [saved v3 value] 66 * [saved v2 value] 67 * [saved v1 value] 68 * [saved a4 value] 69 * [saved a3 value] 70 * [saved a2 value] 71 * [saved a1 value] 72 * 73 * The save code pointer points twelve bytes beyond the start of the 74 * code sequence (usually a single STM) that created the stack frame. 75 * We have to disassemble it if we want to know which of the optional 76 * fields are actually present. 77 */ 78 79 #define FR_SCP (0) 80 #define FR_RLV (-1) 81 #define FR_RSP (-2) 82 #define FR_RFP (-3) 83 84 void 85 db_stack_trace_print(db_expr_t addr, bool have_addr, 86 db_expr_t count, const char *modif, 87 void (*pr)(const char *, ...)) 88 { 89 struct trapframe *tf = NULL; 90 uint32_t *frame, *lastframe; 91 const char *cp = modif; 92 char c; 93 bool kernel_only = true; 94 bool trace_thread = false; 95 bool trace_full = false; 96 bool lwpaddr = false; 97 db_addr_t scp, pc; 98 int scp_offset; 99 100 while ((c = *cp++) != 0) { 101 if (c == 'a') { 102 lwpaddr = true; 103 trace_thread = true; 104 } 105 if (c == 'u') 106 kernel_only = false; 107 if (c == 't') 108 trace_thread = true; 109 if (c == 'f') 110 trace_full = true; 111 } 112 113 #ifdef _KERNEL 114 if (!have_addr) 115 frame = (uint32_t *)(DDB_REGS->tf_r11); 116 else 117 #endif 118 { 119 if (trace_thread) { 120 struct pcb *pcb; 121 proc_t p; 122 lwp_t l; 123 124 if (lwpaddr) { 125 db_read_bytes(addr, sizeof(l), 126 (char *)&l); 127 db_read_bytes((db_addr_t)l.l_proc, 128 sizeof(p), (char *)&p); 129 (*pr)("trace: pid %d ", p.p_pid); 130 } else { 131 proc_t *pp; 132 133 (*pr)("trace: pid %d ", (int)addr); 134 if ((pp = db_proc_find((pid_t)addr)) == 0) { 135 (*pr)("not found\n"); 136 return; 137 } 138 db_read_bytes((db_addr_t)pp, sizeof(p), (char *)&p); 139 addr = (db_addr_t)p.p_lwps.lh_first; 140 db_read_bytes(addr, sizeof(l), (char *)&l); 141 } 142 (*pr)("lid %d ", l.l_lid); 143 pcb = lwp_getpcb(&l); 144 tf = lwp_trapframe(&l); 145 #ifndef _KERNEL 146 struct pcb pcbb; 147 db_read_bytes((db_addr_t)pcb, sizeof(*pcb), 148 (char *)&pcbb); 149 pcb = &pcbb; 150 #endif 151 frame = (uint32_t *)(pcb->pcb_r11); 152 (*pr)("at %p\n", frame); 153 } else 154 frame = (uint32_t *)(addr); 155 } 156 scp_offset = -(get_pc_str_offset() >> 2); 157 158 if (frame == NULL) 159 return; 160 161 lastframe = frame; 162 #ifndef _KERNEL 163 uint32_t frameb[4]; 164 db_read_bytes((db_addr_t)(frame - 3), sizeof(frameb), 165 (char *)frameb); 166 frame = frameb + 3; 167 #endif 168 169 /* 170 * In theory, the SCP isn't guaranteed to be in the function 171 * that generated the stack frame. We hope for the best. 172 */ 173 scp = frame[FR_SCP]; 174 pc = scp; 175 176 while (count--) { 177 uint32_t savecode; 178 int r; 179 uint32_t *rp; 180 const char *sep; 181 182 scp = frame[FR_SCP]; 183 (*pr)("%p: ", lastframe); 184 185 db_printsym(pc, DB_STGY_PROC, pr); 186 if (trace_full) { 187 (*pr)("\n\t"); 188 (*pr)("pc =0x%08x rlv=0x%08x (", pc, frame[FR_RLV]); 189 db_printsym(frame[FR_RLV], DB_STGY_PROC, pr); 190 (*pr)(")\n"); 191 (*pr)("\trsp=0x%08x rfp=0x%08x", frame[FR_RSP], 192 frame[FR_RFP]); 193 } 194 195 #ifndef _KERNEL 196 db_read_bytes((db_addr_t)((uint32_t *)scp + scp_offset), 197 sizeof(savecode), (void *)&savecode); 198 #else 199 if ((scp & 3) == 0) { 200 savecode = ((uint32_t *)scp)[scp_offset]; 201 } else { 202 savecode = 0; 203 } 204 #endif 205 if (trace_full && 206 (savecode & 0x0e100000) == 0x08000000) { 207 /* Looks like an STM */ 208 rp = frame - 4; 209 sep = "\n\t"; 210 for (r = 10; r >= 0; r--) { 211 if (savecode & (1 << r)) { 212 (*pr)("%sr%d=0x%08x", 213 sep, r, *rp--); 214 sep = (frame - rp) % 4 == 2 ? 215 "\n\t" : " "; 216 } 217 } 218 } 219 220 (*pr)("\n"); 221 /* 222 * Switch to next frame up 223 */ 224 if (frame[FR_RFP] == 0) 225 break; /* Top of stack */ 226 pc = frame[FR_RLV]; 227 228 frame = (uint32_t *)(frame[FR_RFP]); 229 230 if (frame == NULL) 231 break; 232 233 if (INKERNEL((int)frame)) { 234 /* staying in kernel */ 235 if (frame <= lastframe) { 236 (*pr)("Bad frame pointer: %p\n", frame); 237 break; 238 } 239 } else if (INKERNEL((int)lastframe)) { 240 if (trace_thread) { 241 (*pr)("--- tf %p ---\n", tf); 242 } 243 /* switch from user to kernel */ 244 if (kernel_only) 245 break; /* kernel stack only */ 246 } else { 247 /* in user */ 248 if (frame <= lastframe) { 249 (*pr)("Bad user frame pointer: %p\n", 250 frame); 251 break; 252 } 253 } 254 lastframe = frame; 255 #ifndef _KERNEL 256 db_read_bytes((db_addr_t)(frame - 3), sizeof(frameb), 257 (char *)frameb); 258 frame = frameb + 3; 259 #endif 260 } 261 } 262