1 /* $NetBSD: db_trace.c,v 1.7 2002/04/10 19:35:22 thorpej 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@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.7 2002/04/10 19:35:22 thorpej Exp $"); 35 36 #include <sys/proc.h> 37 #include <sys/user.h> 38 #include <arm/armreg.h> 39 #include <arm/cpufunc.h> 40 #include <machine/db_machdep.h> 41 42 #include <ddb/db_access.h> 43 #include <ddb/db_interface.h> 44 #include <ddb/db_sym.h> 45 #include <ddb/db_output.h> 46 47 #define INKERNEL(va) (((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS) 48 49 /* 50 * APCS stack frames are awkward beasts, so I don't think even trying to use 51 * a structure to represent them is a good idea. 52 * 53 * Here's the diagram from the APCS. Increasing address is _up_ the page. 54 * 55 * save code pointer [fp] <- fp points to here 56 * return link value [fp, #-4] 57 * return sp value [fp, #-8] 58 * return fp value [fp, #-12] 59 * [saved v7 value] 60 * [saved v6 value] 61 * [saved v5 value] 62 * [saved v4 value] 63 * [saved v3 value] 64 * [saved v2 value] 65 * [saved v1 value] 66 * [saved a4 value] 67 * [saved a3 value] 68 * [saved a2 value] 69 * [saved a1 value] 70 * 71 * The save code pointer points twelve bytes beyond the start of the 72 * code sequence (usually a single STM) that created the stack frame. 73 * We have to disassemble it if we want to know which of the optional 74 * fields are actually present. 75 */ 76 77 #define FR_SCP (0) 78 #define FR_RLV (-1) 79 #define FR_RSP (-2) 80 #define FR_RFP (-3) 81 82 void 83 db_stack_trace_print(addr, have_addr, count, modif, pr) 84 db_expr_t addr; 85 int have_addr; 86 db_expr_t count; 87 char *modif; 88 void (*pr) __P((const char *, ...)); 89 { 90 u_int32_t *frame, *lastframe; 91 char c, *cp = modif; 92 boolean_t kernel_only = TRUE; 93 boolean_t trace_thread = FALSE; 94 int scp_offset; 95 96 while ((c = *cp++) != 0) { 97 if (c == 'u') 98 kernel_only = FALSE; 99 if (c == 't') 100 trace_thread = TRUE; 101 } 102 103 if (!have_addr) 104 frame = (u_int32_t *)(DDB_REGS->tf_r11); 105 else { 106 if (trace_thread) { 107 struct proc *p; 108 struct user *u; 109 (*pr) ("trace: pid %d ", (int)addr); 110 p = pfind(addr); 111 if (p == NULL) { 112 (*pr)("not found\n"); 113 return; 114 } 115 if (!(p->p_flag & P_INMEM)) { 116 (*pr)("swapped out\n"); 117 return; 118 } 119 u = p->p_addr; 120 #ifdef acorn26 121 frame = (u_int32_t *)(u->u_pcb.pcb_sf->sf_r11); 122 #else 123 frame = (u_int32_t *)(u->u_pcb.pcb_un.un_32.pcb32_r11); 124 #endif 125 (*pr)("at %p\n", frame); 126 } else 127 frame = (u_int32_t *)(addr); 128 } 129 lastframe = NULL; 130 scp_offset = -(get_pc_str_offset() >> 2); 131 132 while (count-- && frame != NULL) { 133 db_addr_t scp; 134 u_int32_t savecode; 135 int r; 136 u_int32_t *rp; 137 const char *sep; 138 139 /* 140 * In theory, the SCP isn't guaranteed to be in the function 141 * that generated the stack frame. We hope for the best. 142 */ 143 #ifdef __PROG26 144 scp = frame[FR_SCP] & R15_PC; 145 #else 146 scp = frame[FR_SCP]; 147 #endif 148 149 db_printsym(scp, DB_STGY_PROC, pr); 150 (*pr)("\n\t"); 151 #ifdef __PROG26 152 (*pr)("scp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV] & R15_PC); 153 db_printsym(frame[FR_RLV] & R15_PC, DB_STGY_PROC, pr); 154 (*pr)(")\n"); 155 #else 156 (*pr)("scp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV]); 157 db_printsym(frame[FR_RLV], DB_STGY_PROC, pr); 158 (*pr)(")\n"); 159 #endif 160 (*pr)("\trsp=0x%08x rfp=0x%08x", frame[FR_RSP], frame[FR_RFP]); 161 162 savecode = ((u_int32_t *)scp)[scp_offset]; 163 if ((savecode & 0x0e100000) == 0x08000000) { 164 /* Looks like an STM */ 165 rp = frame - 4; 166 sep = "\n\t"; 167 for (r = 10; r >= 0; r--) { 168 if (savecode & (1 << r)) { 169 (*pr)("%sr%d=0x%08x", 170 sep, r, *rp--); 171 sep = (frame - rp) % 4 == 2 ? 172 "\n\t" : " "; 173 } 174 } 175 } 176 177 (*pr)("\n"); 178 179 /* 180 * Switch to next frame up 181 */ 182 if (frame[FR_RFP] == 0) 183 break; /* Top of stack */ 184 185 lastframe = frame; 186 frame = (u_int32_t *)(frame[FR_RFP]); 187 188 if (INKERNEL((int)frame)) { 189 /* staying in kernel */ 190 if (frame <= lastframe) { 191 (*pr)("Bad frame pointer: %p\n", frame); 192 break; 193 } 194 } else if (INKERNEL((int)lastframe)) { 195 /* switch from user to kernel */ 196 if (kernel_only) 197 break; /* kernel stack only */ 198 } else { 199 /* in user */ 200 if (frame <= lastframe) { 201 (*pr)("Bad user frame pointer: %p\n", 202 frame); 203 break; 204 } 205 } 206 } 207 } 208