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