1 /* $OpenBSD: db_trace.c,v 1.24 2024/11/07 16:02:29 miod Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Niklas Hallqvist. All rights reserved. 5 * Copyright (c) 1997 Theo de Raadt. 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 31 #include <uvm/uvm_extern.h> 32 33 #include <machine/db_machdep.h> 34 #include <machine/frame.h> 35 36 #include <ddb/db_access.h> 37 #include <ddb/db_command.h> 38 #include <ddb/db_output.h> 39 #include <ddb/db_sym.h> 40 #include <ddb/db_variables.h> 41 #include <ddb/db_extern.h> 42 #include <ddb/db_interface.h> 43 44 extern int etext; 45 46 struct opcode opcode[] = { 47 { OPC_PAL, "call_pal", 0 }, /* 00 */ 48 { OPC_RES, "opc01", 0 }, /* 01 */ 49 { OPC_RES, "opc02", 0 }, /* 02 */ 50 { OPC_RES, "opc03", 0 }, /* 03 */ 51 { OPC_RES, "opc04", 0 }, /* 04 */ 52 { OPC_RES, "opc05", 0 }, /* 05 */ 53 { OPC_RES, "opc06", 0 }, /* 06 */ 54 { OPC_RES, "opc07", 0 }, /* 07 */ 55 { OPC_MEM, "lda", 1 }, /* 08 */ 56 { OPC_MEM, "ldah", 1 }, /* 09 */ 57 { OPC_RES, "opc0a", 0 }, /* 0A */ 58 { OPC_MEM, "ldq_u", 1 }, /* 0B */ 59 { OPC_RES, "opc0c", 0 }, /* 0C */ 60 { OPC_RES, "opc0d", 0 }, /* 0D */ 61 { OPC_RES, "opc0e", 0 }, /* 0E */ 62 { OPC_MEM, "stq_u", 1 }, /* 0F */ 63 { OPC_OP, "inta", 0 }, /* 10 */ 64 { OPC_OP, "intl", 0 }, /* 11 */ 65 { OPC_OP, "ints", 0 }, /* 12 */ 66 { OPC_OP, "intm", 0 }, /* 13 */ 67 { OPC_RES, "opc14", 0 }, /* 14 */ 68 { OPC_OP, "fltv", 1 }, /* 15 */ 69 { OPC_OP, "flti", 1 }, /* 16 */ 70 { OPC_OP, "fltl", 1 }, /* 17 */ 71 { OPC_MEM, "misc", 0 }, /* 18 */ 72 { OPC_PAL, "pal19", 0 }, /* 19 */ 73 { OPC_MEM, "jsr", 0 }, /* 1A */ 74 { OPC_PAL, "pal1b", 0 }, /* 1B */ 75 { OPC_RES, "opc1c", 0 }, /* 1C */ 76 { OPC_PAL, "pal1d", 0 }, /* 1D */ 77 { OPC_PAL, "pal1e", 0 }, /* 1E */ 78 { OPC_PAL, "pal1f", 0 }, /* 1F */ 79 { OPC_MEM, "ldf", 1 }, /* 20 */ 80 { OPC_MEM, "ldg", 1 }, /* 21 */ 81 { OPC_MEM, "lds", 1 }, /* 22 */ 82 { OPC_MEM, "ldt", 1 }, /* 23 */ 83 { OPC_MEM, "stf", 1 }, /* 24 */ 84 { OPC_MEM, "stg", 1 }, /* 25 */ 85 { OPC_MEM, "sts", 1 }, /* 26 */ 86 { OPC_MEM, "stt", 1 }, /* 27 */ 87 { OPC_MEM, "ldl", 1 }, /* 28 */ 88 { OPC_MEM, "ldq", 1 }, /* 29 */ 89 { OPC_MEM, "ldl_l", 1 }, /* 2A */ 90 { OPC_MEM, "ldq_l", 1 }, /* 2B */ 91 { OPC_MEM, "stl", 1 }, /* 2C */ 92 { OPC_MEM, "stq", 1 }, /* 2D */ 93 { OPC_MEM, "stl_c", 1 }, /* 2E */ 94 { OPC_MEM, "stq_c", 1 }, /* 2F */ 95 { OPC_BR, "br", 1 }, /* 30 */ 96 { OPC_BR, "fbeq", 1 }, /* 31 */ 97 { OPC_BR, "fblt", 1 }, /* 32 */ 98 { OPC_BR, "fble", 1 }, /* 33 */ 99 { OPC_BR, "bsr", 1 }, /* 34 */ 100 { OPC_BR, "fbne", 1 }, /* 35 */ 101 { OPC_BR, "fbge", 1 }, /* 36 */ 102 { OPC_BR, "fbgt", 1 }, /* 37 */ 103 { OPC_BR, "blbc", 1 }, /* 38 */ 104 { OPC_BR, "beq", 1 }, /* 39 */ 105 { OPC_BR, "blt", 1 }, /* 3A */ 106 { OPC_BR, "ble", 1 }, /* 3B */ 107 { OPC_BR, "blbs", 1 }, /* 3C */ 108 { OPC_BR, "bne", 1 }, /* 3D */ 109 { OPC_BR, "bge", 1 }, /* 3E */ 110 { OPC_BR, "bgt", 1 }, /* 3F */ 111 }; 112 113 static __inline int sext(u_int); 114 static __inline int rega(u_int); 115 static __inline int regb(u_int); 116 static __inline int regc(u_int); 117 static __inline int disp(u_int); 118 119 static __inline int 120 sext(u_int x) 121 { 122 return ((x & 0x8000) ? -(-x & 0xffff) : (x & 0xffff)); 123 } 124 125 static __inline int 126 rega(u_int x) 127 { 128 return ((x >> 21) & 0x1f); 129 } 130 131 static __inline int 132 regb(u_int x) 133 { 134 return ((x >> 16) & 0x1f); 135 } 136 137 static __inline int 138 regc(u_int x) 139 { 140 return (x & 0x1f); 141 } 142 143 static __inline int 144 disp(u_int x) 145 { 146 return (sext(x & 0xffff)); 147 } 148 149 /* 150 * XXX There are a couple of problems with this code: 151 * 152 * The argument list printout code is likely to get confused. 153 * 154 * It relies on the conventions of gcc code generation. 155 * 156 * It uses heuristics to calculate the framesize, and might get it wrong. 157 * 158 * It doesn't yet use the framepointer if available. 159 * 160 * The address argument can only be used for pointing at trapframes 161 * since a frame pointer of its own serves no good on the alpha, 162 * you need a pc value too. 163 * 164 * The heuristics used for tracing through a trap relies on having 165 * symbols available. 166 */ 167 void 168 db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count, 169 char *modif, int (*pr)(const char *, ...)) 170 { 171 u_long *frame; 172 int i, framesize; 173 vaddr_t pc, ra; 174 u_int inst; 175 const char *name; 176 db_expr_t offset; 177 db_regs_t *regs; 178 u_long *slot[32]; 179 180 bzero(slot, sizeof(slot)); 181 if (count == -1) 182 count = 65535; 183 184 if (have_addr) { 185 (*pr)("alpha trace requires a trap frame... giving up.\n"); 186 return; 187 } 188 regs = &ddb_regs; 189 trapframe: 190 /* remember where various registers are stored */ 191 for (i = 0; i < 31; i++) 192 slot[i] = ®s->tf_regs[0] + 193 ((u_long *)db_regs[i].valuep - &ddb_regs.tf_regs[0]); 194 frame = (u_long *)regs->tf_regs[FRAME_SP]; 195 pc = (vaddr_t)regs->tf_regs[FRAME_PC]; 196 ra = (vaddr_t)regs->tf_regs[FRAME_RA]; 197 198 while (count-- && pc >= (vaddr_t)KERNBASE && pc < (vaddr_t)&etext) { 199 db_find_sym_and_offset(pc, &name, &offset); 200 201 if (name == NULL) { 202 (*pr)("%lx(", pc); 203 /* Limit the search for procedure start */ 204 offset = 65536; 205 } else { 206 (*pr)("%s(", name); 207 } 208 209 framesize = 0; 210 for (i = sizeof (int); i <= offset; i += sizeof (int)) { 211 inst = *(u_int *)(pc - i); 212 213 /* 214 * If by chance we don't have any symbols we have to 215 * get out somehow anyway. Check for the preceding 216 * procedure return in that case. 217 */ 218 if (name[0] == '?' && inst_return(inst)) 219 break; 220 221 /* 222 * Disassemble to get the needed info for the frame. 223 */ 224 if ((inst & 0xffff0000) == 0x23de0000) 225 /* lda sp,n(sp) */ 226 framesize -= disp(inst) / sizeof (u_long); 227 else if ((inst & 0xfc1f0000) == 0xb41e0000) 228 /* stq X,n(sp) */ 229 slot[rega(inst)] = 230 frame + disp(inst) / sizeof (u_long); 231 else if ((inst & 0xfc000fe0) == 0x44000400 && 232 rega(inst) == regb(inst)) { 233 /* bis X,X,Y (aka mov X,Y) */ 234 /* zero is hardwired */ 235 if (rega(inst) != 31) 236 slot[rega(inst)] = slot[regc(inst)]; 237 slot[regc(inst)] = 0; 238 /* 239 * XXX In here we might special case a frame 240 * pointer setup, i.e. mov sp, fp. 241 */ 242 } else if (db_inst_load(inst)) 243 /* clobbers a register */ 244 slot[rega(inst)] = 0; 245 else if (opcode[inst >> 26].opc_fmt == OPC_OP) 246 /* clobbers a register */ 247 slot[regc(inst)] = 0; 248 /* 249 * XXX Recognize more reg clobbering instructions and 250 * set slot[reg] = 0 then too. 251 */ 252 } 253 254 /* 255 * Try to print the 6 quads that might hold the args. 256 * We print 6 of them even if there are fewer, cause we don't 257 * know the number. Maybe we could skip the last ones 258 * that never got used. If we cannot know the value, print 259 * a question mark. 260 */ 261 for (i = 0; i < 6; i++) { 262 if (i > 0) 263 (*pr)(", "); 264 if (slot[16 + i]) 265 (*pr)("%lx", *slot[16 + i]); 266 else 267 (*pr)("?"); 268 } 269 270 #if 0 271 /* 272 * XXX This will go eventually when I trust the argument 273 * printout heuristics. 274 * 275 * Print the stack frame contents. 276 */ 277 (*pr)(") [%p: ", frame); 278 if (framesize > 1) { 279 for (i = 0; i < framesize - 1; i++) 280 (*pr)("%lx, ", frame[i]); 281 (*pr)("%lx", frame[i]); 282 } 283 (*pr)("] at "); 284 #else 285 (*pr)(") at "); 286 #endif 287 db_printsym(pc, DB_STGY_PROC, pr); 288 (*pr)("\n"); 289 290 /* 291 * If we are looking at a Xent* routine we are in a trap 292 * context. 293 */ 294 if (strncmp(name, "Xent", sizeof("Xent") - 1) == 0) { 295 regs = (db_regs_t *)frame; 296 goto trapframe; 297 } 298 299 /* Look for the return address if recorded. */ 300 if (slot[26]) 301 ra = *(vaddr_t *)slot[26]; 302 else 303 break; 304 305 /* Advance to the next frame, if any. */ 306 frame += framesize; 307 if (ra == pc) 308 break; 309 pc = ra; 310 } 311 } 312