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