1 /* $OpenBSD: db_interface.c,v 1.51 2024/11/07 16:02:29 miod Exp $ */ 2 3 /* 4 * Copyright (c) 1999-2003 Michael Shalayeff 5 * 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 OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #undef DDB_DEBUG 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/stacktrace.h> 34 35 #include <machine/db_machdep.h> 36 #include <machine/frame.h> 37 #include <machine/cpufunc.h> 38 39 #include <ddb/db_access.h> 40 #include <ddb/db_command.h> 41 #include <ddb/db_output.h> 42 #include <ddb/db_run.h> 43 #include <ddb/db_sym.h> 44 #include <ddb/db_var.h> 45 #include <ddb/db_variables.h> 46 #include <ddb/db_extern.h> 47 #include <ddb/db_interface.h> 48 49 #include <dev/cons.h> 50 51 void kdbprinttrap(int, int); 52 53 extern char *trap_type[]; 54 extern int trap_types; 55 56 db_regs_t ddb_regs; 57 struct db_variable db_regs[] = { 58 { "flags", (long *)&ddb_regs.tf_flags, FCN_NULL }, 59 { "r1", (long *)&ddb_regs.tf_r1, FCN_NULL }, 60 { "rp", (long *)&ddb_regs.tf_rp, FCN_NULL }, 61 { "r3", (long *)&ddb_regs.tf_r3, FCN_NULL }, 62 { "r4", (long *)&ddb_regs.tf_r4, FCN_NULL }, 63 { "r5", (long *)&ddb_regs.tf_r5, FCN_NULL }, 64 { "r6", (long *)&ddb_regs.tf_r6, FCN_NULL }, 65 { "r7", (long *)&ddb_regs.tf_r7, FCN_NULL }, 66 { "r8", (long *)&ddb_regs.tf_r8, FCN_NULL }, 67 { "r9", (long *)&ddb_regs.tf_r9, FCN_NULL }, 68 { "r10", (long *)&ddb_regs.tf_r10, FCN_NULL }, 69 { "r11", (long *)&ddb_regs.tf_r11, FCN_NULL }, 70 { "r12", (long *)&ddb_regs.tf_r12, FCN_NULL }, 71 { "r13", (long *)&ddb_regs.tf_r13, FCN_NULL }, 72 { "r14", (long *)&ddb_regs.tf_r14, FCN_NULL }, 73 { "r15", (long *)&ddb_regs.tf_r15, FCN_NULL }, 74 { "r16", (long *)&ddb_regs.tf_r16, FCN_NULL }, 75 { "r17", (long *)&ddb_regs.tf_r17, FCN_NULL }, 76 { "r18", (long *)&ddb_regs.tf_r18, FCN_NULL }, 77 { "r19", (long *)&ddb_regs.tf_t4, FCN_NULL }, 78 { "r20", (long *)&ddb_regs.tf_t3, FCN_NULL }, 79 { "r21", (long *)&ddb_regs.tf_t2, FCN_NULL }, 80 { "r22", (long *)&ddb_regs.tf_t1, FCN_NULL }, 81 { "r23", (long *)&ddb_regs.tf_arg3, FCN_NULL }, 82 { "r24", (long *)&ddb_regs.tf_arg2, FCN_NULL }, 83 { "r25", (long *)&ddb_regs.tf_arg1, FCN_NULL }, 84 { "r26", (long *)&ddb_regs.tf_arg0, FCN_NULL }, 85 { "r27", (long *)&ddb_regs.tf_dp, FCN_NULL }, 86 { "r28", (long *)&ddb_regs.tf_ret0, FCN_NULL }, 87 { "r29", (long *)&ddb_regs.tf_ret1, FCN_NULL }, 88 { "r30", (long *)&ddb_regs.tf_sp, FCN_NULL }, 89 { "r31", (long *)&ddb_regs.tf_r31, FCN_NULL }, 90 { "sar", (long *)&ddb_regs.tf_sar, FCN_NULL }, 91 92 { "rctr", (long *)&ddb_regs.tf_rctr, FCN_NULL }, 93 { "ccr", (long *)&ddb_regs.tf_ccr, FCN_NULL }, 94 { "eirr", (long *)&ddb_regs.tf_eirr, FCN_NULL }, 95 { "eiem", (long *)&ddb_regs.tf_eiem, FCN_NULL }, 96 { "iir", (long *)&ddb_regs.tf_iir, FCN_NULL }, 97 { "isr", (long *)&ddb_regs.tf_isr, FCN_NULL }, 98 { "ior", (long *)&ddb_regs.tf_ior, FCN_NULL }, 99 { "ipsw", (long *)&ddb_regs.tf_ipsw, FCN_NULL }, 100 { "iisqh", (long *)&ddb_regs.tf_iisq_head, FCN_NULL }, 101 { "iioqh", (long *)&ddb_regs.tf_iioq_head, FCN_NULL }, 102 { "iisqt", (long *)&ddb_regs.tf_iisq_tail, FCN_NULL }, 103 { "iioqt", (long *)&ddb_regs.tf_iioq_tail, FCN_NULL }, 104 105 { "sr0", (long *)&ddb_regs.tf_sr0, FCN_NULL }, 106 { "sr1", (long *)&ddb_regs.tf_sr1, FCN_NULL }, 107 { "sr2", (long *)&ddb_regs.tf_sr2, FCN_NULL }, 108 { "sr3", (long *)&ddb_regs.tf_sr3, FCN_NULL }, 109 { "sr4", (long *)&ddb_regs.tf_sr4, FCN_NULL }, 110 { "sr5", (long *)&ddb_regs.tf_sr5, FCN_NULL }, 111 { "sr6", (long *)&ddb_regs.tf_sr6, FCN_NULL }, 112 { "sr7", (long *)&ddb_regs.tf_sr7, FCN_NULL }, 113 114 { "pidr1", (long *)&ddb_regs.tf_pidr1, FCN_NULL }, 115 { "pidr2", (long *)&ddb_regs.tf_pidr2, FCN_NULL }, 116 #ifdef pbably_not_worth_it 117 { "pidr3", (long *)&ddb_regs.tf_pidr3, FCN_NULL }, 118 { "pidr4", (long *)&ddb_regs.tf_pidr4, FCN_NULL }, 119 #endif 120 121 { "vtop", (long *)&ddb_regs.tf_vtop, FCN_NULL }, 122 { "cr28", (long *)&ddb_regs.tf_cr28, FCN_NULL }, 123 { "cr30", (long *)&ddb_regs.tf_cr30, FCN_NULL }, 124 }; 125 struct db_variable *db_eregs = db_regs + nitems(db_regs); 126 127 void 128 db_enter(void) 129 { 130 extern int kernelmapped; /* from locore.S */ 131 if (kernelmapped) 132 __asm volatile ("break %0, %1" 133 :: "i" (HPPA_BREAK_KERNEL), "i" (HPPA_BREAK_KGDB)); 134 } 135 136 void 137 db_read_bytes(vaddr_t addr, size_t size, void *datap) 138 { 139 char *data = datap; 140 register char *src = (char *)addr; 141 142 while (size--) 143 *data++ = *src++; 144 } 145 146 void 147 db_write_bytes(vaddr_t addr, size_t size, void *datap) 148 { 149 char *data = datap; 150 register char *dst = (char *)addr; 151 152 while (size--) 153 *dst++ = *data++; 154 155 /* unfortunately ddb does not provide any hooks for these */ 156 ficache(HPPA_SID_KERNEL, (vaddr_t)data, size); 157 fdcache(HPPA_SID_KERNEL, (vaddr_t)data, size); 158 } 159 160 161 /* 162 * Print trap reason. 163 */ 164 void 165 kdbprinttrap(int type, int code) 166 { 167 type &= ~T_USER; /* just in case */ 168 db_printf("kernel: "); 169 if (type >= trap_types || type < 0) 170 db_printf("type 0x%x", type); 171 else 172 db_printf("%s", trap_type[type]); 173 db_printf(" trap, code=0x%x\n", code); 174 } 175 176 /* 177 * db_ktrap - field a BPT trap 178 */ 179 int 180 db_ktrap(int type, int code, db_regs_t *regs) 181 { 182 extern label_t *db_recover; 183 int s; 184 185 switch (type) { 186 case T_IBREAK: 187 case T_DBREAK: 188 case -1: 189 break; 190 default: 191 if (!db_panic) 192 return (0); 193 194 kdbprinttrap(type, code); 195 if (db_recover != 0) { 196 db_error("Caught exception in DDB; continuing...\n"); 197 /* NOT REACHED */ 198 } 199 } 200 201 /* XXX Should switch to kdb`s own stack here. */ 202 203 s = splhigh(); 204 ddb_regs = *regs; 205 db_active++; 206 cnpollc(1); 207 db_trap(type, code); 208 cnpollc(0); 209 db_active--; 210 splx(s); 211 212 *regs = ddb_regs; 213 214 return (1); 215 } 216 217 /* 218 * Validate an address for use as a breakpoint. 219 * Any address is allowed for now. 220 */ 221 int 222 db_valid_breakpoint(vaddr_t addr) 223 { 224 return (1); 225 } 226 227 void 228 db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count, 229 char *modif, int (*pr)(const char *, ...)) 230 { 231 register_t *fp, pc, rp, *argp; 232 Elf_Sym *sym; 233 db_expr_t off; 234 const char *name; 235 int nargs; 236 237 if (count < 0) 238 count = 65536; 239 240 if (!have_addr) { 241 fp = (register_t *)ddb_regs.tf_r3; 242 pc = ddb_regs.tf_iioq_head; 243 rp = ddb_regs.tf_rp; 244 } else { 245 fp = (register_t *)addr; 246 pc = 0; 247 rp = ((register_t *)fp)[-5]; 248 } 249 250 #ifdef DDB_DEBUG 251 (*pr) (">> %p, 0x%x, 0x%x\t", fp, pc, rp); 252 #endif 253 while (fp && count--) { 254 255 if (USERMODE(pc)) 256 return; 257 258 sym = db_search_symbol(pc, DB_STGY_ANY, &off); 259 db_symbol_values (sym, &name, NULL); 260 261 if (name == NULL) 262 (*pr)("%lx(", pc); 263 else 264 (*pr)("%s(", name); 265 266 /* args */ 267 nargs = 4; 268 /* 269 * XXX first four args are passed on registers, and may not 270 * be stored on stack, dunno how to recover their values yet 271 */ 272 for (argp = &fp[-9]; nargs--; argp--) { 273 (*pr)("%x%s", db_get_value((int)argp, 4, 0), 274 nargs? ",":""); 275 } 276 (*pr)(") at "); 277 db_printsym(pc, DB_STGY_PROC, pr); 278 (*pr)("\n"); 279 280 /* TODO: print locals */ 281 282 /* next frame */ 283 pc = rp; 284 rp = fp[-5]; 285 286 /* if a terminal frame and not a start of a page 287 * then skip the trapframe and the terminal frame */ 288 if (!fp[0]) { 289 struct trapframe *tf; 290 291 tf = (struct trapframe *)((char *)fp - sizeof(*tf)); 292 293 if (tf->tf_flags & TFF_SYS) 294 (*pr)("-- syscall #%d(%x, %x, %x, %x, ...)\n", 295 tf->tf_t1, tf->tf_arg0, tf->tf_arg1, 296 tf->tf_arg2, tf->tf_arg3); 297 else 298 (*pr)("-- trap #%d%s\n", tf->tf_flags & 0x3f, 299 (tf->tf_flags & T_USER)? " from user" : ""); 300 301 if (!(tf->tf_flags & TFF_LAST)) { 302 fp = (register_t *)tf->tf_r3; 303 pc = tf->tf_iioq_head; 304 rp = tf->tf_rp; 305 } else 306 fp = 0; 307 } else 308 fp = (register_t *)fp[0]; 309 #ifdef DDB_DEBUG 310 (*pr) (">> %x, %x, %x\t", fp, pc, rp); 311 #endif 312 } 313 314 if (count && pc) { 315 db_printsym(pc, DB_STGY_XTRN, pr); 316 (*pr)(":\n"); 317 } 318 } 319 320 void 321 stacktrace_save_at(struct stacktrace *st, unsigned int skip) 322 { 323 register_t *fp, pc, rp; 324 int i; 325 326 fp = (register_t *)__builtin_frame_address(0); 327 pc = 0; 328 rp = fp[-5]; 329 330 st->st_count = 0; 331 for (i = 0; i < STACKTRACE_MAX; i++) { 332 if (skip == 0) 333 st->st_pc[st->st_count++] = rp; 334 else 335 skip--; 336 337 /* next frame */ 338 pc = rp; 339 if (!fp[0] || USERMODE(pc)) 340 break; 341 342 rp = fp[-5]; 343 fp = (register_t *)fp[0]; 344 } 345 } 346 347 void 348 stacktrace_save_utrace(struct stacktrace *st) 349 { 350 st->st_count = 0; 351 } 352