1 /* $OpenBSD: db_trace.c,v 1.11 2024/11/07 16:02:29 miod Exp $ */ 2 /* $NetBSD: db_trace.c,v 1.19 2006/01/21 22:10:59 uwe Exp $ */ 3 4 /*- 5 * Copyright (c) 2000 Tsubai Masanari. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 33 #include <machine/db_machdep.h> 34 35 #include <ddb/db_access.h> 36 #include <ddb/db_interface.h> 37 #include <ddb/db_output.h> 38 #include <ddb/db_sym.h> 39 #include <ddb/db_variables.h> 40 41 #ifdef TRACE_DEBUG 42 # define DPRINTF printf 43 #else 44 # define DPRINTF while (/* CONSTCOND */ 0) printf 45 #endif 46 47 extern char start[], etext[]; 48 void db_nextframe(vaddr_t, vaddr_t *, vaddr_t *); 49 50 struct db_variable db_regs[] = { 51 { "r0", (long *)&ddb_regs.tf_r0, FCN_NULL }, 52 { "r1", (long *)&ddb_regs.tf_r1, FCN_NULL }, 53 { "r2", (long *)&ddb_regs.tf_r2, FCN_NULL }, 54 { "r3", (long *)&ddb_regs.tf_r3, FCN_NULL }, 55 { "r4", (long *)&ddb_regs.tf_r4, FCN_NULL }, 56 { "r5", (long *)&ddb_regs.tf_r5, FCN_NULL }, 57 { "r6", (long *)&ddb_regs.tf_r6, FCN_NULL }, 58 { "r7", (long *)&ddb_regs.tf_r7, FCN_NULL }, 59 { "r8", (long *)&ddb_regs.tf_r8, FCN_NULL }, 60 { "r9", (long *)&ddb_regs.tf_r9, FCN_NULL }, 61 { "r10", (long *)&ddb_regs.tf_r10, FCN_NULL }, 62 { "r11", (long *)&ddb_regs.tf_r11, FCN_NULL }, 63 { "r12", (long *)&ddb_regs.tf_r12, FCN_NULL }, 64 { "r13", (long *)&ddb_regs.tf_r13, FCN_NULL }, 65 { "r14", (long *)&ddb_regs.tf_r14, FCN_NULL }, 66 { "r15", (long *)&ddb_regs.tf_r15, FCN_NULL }, 67 { "pr", (long *)&ddb_regs.tf_pr, FCN_NULL }, 68 { "spc", (long *)&ddb_regs.tf_spc, FCN_NULL }, 69 { "ssr", (long *)&ddb_regs.tf_ssr, FCN_NULL }, 70 { "mach", (long *)&ddb_regs.tf_mach, FCN_NULL }, 71 { "macl", (long *)&ddb_regs.tf_macl, FCN_NULL }, 72 }; 73 74 struct db_variable *db_eregs = db_regs + nitems(db_regs); 75 76 void 77 db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count, 78 char *modif, int (*print)(const char *, ...)) 79 { 80 vaddr_t callpc, frame, lastframe; 81 uint32_t vbr; 82 83 if (have_addr) { 84 (*print)("sh trace requires a trap frame... giving up\n"); 85 return; 86 } 87 88 __asm volatile("stc vbr, %0" : "=r"(vbr)); 89 90 frame = ddb_regs.tf_r14; 91 callpc = ddb_regs.tf_spc; 92 93 if (count == 0 || count == -1) 94 count = INT_MAX; 95 96 lastframe = 0; 97 while (count > 0 && frame != 0) { 98 /* Are we crossing a trap frame? */ 99 if ((callpc & ~PAGE_MASK) == vbr) { 100 struct trapframe *tf = (void *)frame; 101 102 frame = tf->tf_r14; 103 callpc = tf->tf_spc; 104 105 (*print)("(EXPEVT %03x; SSR=%08x) at ", 106 tf->tf_expevt, tf->tf_ssr); 107 db_printsym(callpc, DB_STGY_PROC, print); 108 (*print)("\n"); 109 110 /* XXX: don't venture into the userland yet */ 111 if ((tf->tf_ssr & PSL_MD) == 0) 112 break; 113 } else { 114 const char *name; 115 db_expr_t offset; 116 Elf_Sym *sym; 117 118 119 DPRINTF(" (1)newpc 0x%lx, newfp 0x%lx\n", 120 callpc, frame); 121 122 sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); 123 db_symbol_values(sym, &name, NULL); 124 125 if (name == NULL) 126 (*print)("%lx()", callpc); 127 else 128 (*print)("%s() at ", name); 129 130 db_printsym(callpc, DB_STGY_PROC, print); 131 (*print)("\n"); 132 133 if (lastframe == 0 && offset == 0) { 134 callpc = ddb_regs.tf_pr; 135 continue; 136 } 137 138 db_nextframe(callpc - offset, &frame, &callpc); 139 DPRINTF(" (2)newpc 0x%lx, newfp 0x%lx\n", 140 callpc, frame); 141 142 if (callpc == 0 && lastframe == 0) 143 callpc = (vaddr_t)ddb_regs.tf_pr; 144 DPRINTF(" (3)newpc 0x%lx, newfp 0x%lx\n", 145 callpc, frame); 146 } 147 148 count--; 149 lastframe = frame; 150 } 151 } 152 153 void 154 db_nextframe( 155 vaddr_t pc, /* in: entry address of current function */ 156 vaddr_t *fp, /* in: current fp, out: parent fp */ 157 vaddr_t *pr) /* out: parent pr */ 158 { 159 int *frame = (void *)*fp; 160 int i, inst; 161 int depth, prdepth, fpdepth; 162 163 depth = 0; 164 prdepth = fpdepth = -1; 165 166 if (pc < (vaddr_t)start || pc > (vaddr_t)etext) 167 goto out; 168 169 for (i = 0; i < 30; i++) { 170 inst = db_get_value(pc, 2, 0); 171 pc += 2; 172 173 if (inst == 0x6ef3) /* mov r15,r14 -- end of prologue */ 174 break; 175 176 if (inst == 0x4f22) { /* sts.l pr,@-r15 */ 177 prdepth = depth; 178 depth++; 179 continue; 180 } 181 if (inst == 0x2fe6) { /* mov.l r14,@-r15 */ 182 fpdepth = depth; 183 depth++; 184 continue; 185 } 186 if ((inst & 0xff0f) == 0x2f06) { /* mov.l r?,@-r15 */ 187 depth++; 188 continue; 189 } 190 if ((inst & 0xff00) == 0x7f00) { /* add #n,r15 */ 191 int8_t n = inst & 0xff; 192 193 if (n >= 0) { 194 printf("add #n,r15 (n > 0)\n"); 195 break; 196 } 197 198 depth += -n/4; 199 continue; 200 } 201 if ((inst & 0xf000) == 0x9000) { 202 if (db_get_value(pc, 2, 0) == 0x3f38) { 203 /* "mov #n,r3; sub r3,r15" */ 204 unsigned int disp = (int)(inst & 0xff); 205 int r3; 206 207 r3 = db_get_value(pc + 4 - 2 + (disp << 1), 208 2, 0); 209 if ((r3 & 0x00008000) == 0) 210 r3 &= 0x0000ffff; 211 else 212 r3 |= 0xffff0000; 213 depth += (r3 / 4); 214 215 pc += 2; 216 continue; 217 } 218 } 219 220 #ifdef TRACE_DEBUG 221 printf("unknown instruction in prologue\n"); 222 db_disasm(pc - 2, 0); 223 #endif 224 } 225 226 out: 227 #ifdef TRACE_DEBUG 228 printf("depth=%x fpdepth=0x%x prdepth=0x%x\n", depth, fpdepth, prdepth); 229 #endif 230 if (fpdepth != -1) 231 *fp = frame[depth - fpdepth - 1]; 232 else 233 *fp = 0; 234 235 if (prdepth != -1) 236 *pr = frame[depth - prdepth - 1]; 237 else 238 *pr = 0; 239 } 240