1/* $NetBSD: db_interface.c,v 1.33 2003/08/25 04:51:10 mrg Exp $ */ 2 3/*- 4 * Copyright (c) 1996 Scott K. Stevens 5 * 6 * Mach Operating System 7 * Copyright (c) 1991,1990 Carnegie Mellon University 8 * All Rights Reserved. 9 * 10 * Permission to use, copy, modify and distribute this software and its 11 * documentation is hereby granted, provided that both the copyright 12 * notice and this permission notice appear in all copies of the 13 * software, derivative works or modified versions, and any portions 14 * thereof, and that both notices appear in supporting documentation. 15 * 16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 17 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 18 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 19 * 20 * Carnegie Mellon requests users of this software to return to 21 * 22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 23 * School of Computer Science 24 * Carnegie Mellon University 25 * Pittsburgh PA 15213-3890 26 * 27 * any improvements or extensions that they make and grant Carnegie the 28 * rights to redistribute these changes. 29 * 30 * From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) 31 */ 32 33/* 34 * Interface to new debugger. 35 */ 36 37#include <sys/cdefs.h> 38__FBSDID("$FreeBSD$"); 39#include "opt_ddb.h" 40 41#include <sys/param.h> 42#include <sys/cons.h> 43#include <sys/proc.h> 44#include <sys/reboot.h> 45#include <sys/systm.h> /* just for boothowto */ 46#include <sys/exec.h> 47#ifdef KDB 48#include <sys/kdb.h> 49#endif 50 51#include <vm/vm.h> 52#include <vm/pmap.h> 53#include <vm/vm_map.h> 54#include <vm/vm_extern.h> 55 56#include <machine/db_machdep.h> 57#include <machine/cpu.h> 58#include <machine/machdep.h> 59#include <machine/vmparam.h> 60 61#include <ddb/ddb.h> 62#include <ddb/db_access.h> 63#include <ddb/db_command.h> 64#include <ddb/db_output.h> 65#include <ddb/db_variables.h> 66#include <ddb/db_sym.h> 67 68 69static int nil = 0; 70 71int db_access_und_sp (struct db_variable *, db_expr_t *, int); 72int db_access_abt_sp (struct db_variable *, db_expr_t *, int); 73int db_access_irq_sp (struct db_variable *, db_expr_t *, int); 74 75static db_varfcn_t db_frame; 76 77#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) 78struct db_variable db_regs[] = { 79 { "spsr", DB_OFFSET(tf_spsr), db_frame }, 80 { "r0", DB_OFFSET(tf_r0), db_frame }, 81 { "r1", DB_OFFSET(tf_r1), db_frame }, 82 { "r2", DB_OFFSET(tf_r2), db_frame }, 83 { "r3", DB_OFFSET(tf_r3), db_frame }, 84 { "r4", DB_OFFSET(tf_r4), db_frame }, 85 { "r5", DB_OFFSET(tf_r5), db_frame }, 86 { "r6", DB_OFFSET(tf_r6), db_frame }, 87 { "r7", DB_OFFSET(tf_r7), db_frame }, 88 { "r8", DB_OFFSET(tf_r8), db_frame }, 89 { "r9", DB_OFFSET(tf_r9), db_frame }, 90 { "r10", DB_OFFSET(tf_r10), db_frame }, 91 { "r11", DB_OFFSET(tf_r11), db_frame }, 92 { "r12", DB_OFFSET(tf_r12), db_frame }, 93 { "usr_sp", DB_OFFSET(tf_usr_sp), db_frame }, 94 { "usr_lr", DB_OFFSET(tf_usr_lr), db_frame }, 95 { "svc_sp", DB_OFFSET(tf_svc_sp), db_frame }, 96 { "svc_lr", DB_OFFSET(tf_svc_lr), db_frame }, 97 { "pc", DB_OFFSET(tf_pc), db_frame }, 98 { "und_sp", &nil, db_access_und_sp, }, 99 { "abt_sp", &nil, db_access_abt_sp, }, 100 { "irq_sp", &nil, db_access_irq_sp, }, 101}; 102 103struct db_variable *db_eregs = db_regs + nitems(db_regs); 104 105int 106db_access_und_sp(struct db_variable *vp, db_expr_t *valp, int rw) 107{ 108 109 if (rw == DB_VAR_GET) { 110 *valp = get_stackptr(PSR_UND32_MODE); 111 return (1); 112 } 113 return (0); 114} 115 116int 117db_access_abt_sp(struct db_variable *vp, db_expr_t *valp, int rw) 118{ 119 120 if (rw == DB_VAR_GET) { 121 *valp = get_stackptr(PSR_ABT32_MODE); 122 return (1); 123 } 124 return (0); 125} 126 127int 128db_access_irq_sp(struct db_variable *vp, db_expr_t *valp, int rw) 129{ 130 131 if (rw == DB_VAR_GET) { 132 *valp = get_stackptr(PSR_IRQ32_MODE); 133 return (1); 134 } 135 return (0); 136} 137 138int db_frame(struct db_variable *vp, db_expr_t *valp, int rw) 139{ 140 int *reg; 141 142 if (kdb_frame == NULL) 143 return (0); 144 145 reg = (int *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep); 146 if (rw == DB_VAR_GET) 147 *valp = *reg; 148 else 149 *reg = *valp; 150 return (1); 151} 152 153void 154db_show_mdpcpu(struct pcpu *pc) 155{ 156 157#if __ARM_ARCH >= 6 158 db_printf("curpmap = %p\n", pc->pc_curpmap); 159#endif 160} 161int 162db_validate_address(vm_offset_t addr) 163{ 164 struct proc *p = curproc; 165 struct pmap *pmap; 166 167 if (!p || !p->p_vmspace || !p->p_vmspace->vm_map.pmap || 168#ifndef ARM32_NEW_VM_LAYOUT 169 addr >= VM_MAXUSER_ADDRESS 170#else 171 addr >= VM_MIN_KERNEL_ADDRESS 172#endif 173 ) 174 pmap = kernel_pmap; 175 else 176 pmap = p->p_vmspace->vm_map.pmap; 177 178 return (pmap_extract(pmap, addr) == FALSE); 179} 180 181/* 182 * Read bytes from kernel address space for debugger. 183 */ 184int 185db_read_bytes(addr, size, data) 186 vm_offset_t addr; 187 size_t size; 188 char *data; 189{ 190 char *src = (char *)addr; 191 192 if (db_validate_address((u_int)src)) { 193 db_printf("address %p is invalid\n", src); 194 return (-1); 195 } 196 197 if (size == 4 && (addr & 3) == 0 && ((uintptr_t)data & 3) == 0) { 198 *((int*)data) = *((int*)src); 199 return (0); 200 } 201 202 if (size == 2 && (addr & 1) == 0 && ((uintptr_t)data & 1) == 0) { 203 *((short*)data) = *((short*)src); 204 return (0); 205 } 206 207 while (size-- > 0) { 208 if (db_validate_address((u_int)src)) { 209 db_printf("address %p is invalid\n", src); 210 return (-1); 211 } 212 *data++ = *src++; 213 } 214 return (0); 215} 216 217/* 218 * Write bytes to kernel address space for debugger. 219 */ 220int 221db_write_bytes(vm_offset_t addr, size_t size, char *data) 222{ 223 char *dst; 224 size_t loop; 225 226 dst = (char *)addr; 227 if (db_validate_address((u_int)dst)) { 228 db_printf("address %p is invalid\n", dst); 229 return (0); 230 } 231 232 if (size == 4 && (addr & 3) == 0 && ((uintptr_t)data & 3) == 0) 233 *((int*)dst) = *((int*)data); 234 else 235 if (size == 2 && (addr & 1) == 0 && ((uintptr_t)data & 1) == 0) 236 *((short*)dst) = *((short*)data); 237 else { 238 loop = size; 239 while (loop-- > 0) { 240 if (db_validate_address((u_int)dst)) { 241 db_printf("address %p is invalid\n", dst); 242 return (-1); 243 } 244 *dst++ = *data++; 245 } 246 } 247 248 /* make sure the caches and memory are in sync */ 249 icache_sync(addr, size); 250 251 /* In case the current page tables have been modified ... */ 252 tlb_flush_all(); 253 return (0); 254} 255 256 257static u_int 258db_fetch_reg(int reg) 259{ 260 261 switch (reg) { 262 case 0: 263 return (kdb_frame->tf_r0); 264 case 1: 265 return (kdb_frame->tf_r1); 266 case 2: 267 return (kdb_frame->tf_r2); 268 case 3: 269 return (kdb_frame->tf_r3); 270 case 4: 271 return (kdb_frame->tf_r4); 272 case 5: 273 return (kdb_frame->tf_r5); 274 case 6: 275 return (kdb_frame->tf_r6); 276 case 7: 277 return (kdb_frame->tf_r7); 278 case 8: 279 return (kdb_frame->tf_r8); 280 case 9: 281 return (kdb_frame->tf_r9); 282 case 10: 283 return (kdb_frame->tf_r10); 284 case 11: 285 return (kdb_frame->tf_r11); 286 case 12: 287 return (kdb_frame->tf_r12); 288 case 13: 289 return (kdb_frame->tf_svc_sp); 290 case 14: 291 return (kdb_frame->tf_svc_lr); 292 case 15: 293 return (kdb_frame->tf_pc); 294 default: 295 panic("db_fetch_reg: botch"); 296 } 297} 298 299static u_int 300db_branch_taken_read_int(void *cookie __unused, vm_offset_t offset, u_int *val) 301{ 302 u_int ret; 303 304 db_read_bytes(offset, 4, (char *)&ret); 305 *val = ret; 306 307 return (0); 308} 309 310static u_int 311db_branch_taken_fetch_reg(void *cookie __unused, int reg) 312{ 313 314 return (db_fetch_reg(reg)); 315} 316 317u_int 318branch_taken(u_int insn, db_addr_t pc) 319{ 320 register_t new_pc; 321 int ret; 322 323 ret = arm_predict_branch(NULL, insn, (register_t)pc, &new_pc, 324 db_branch_taken_fetch_reg, db_branch_taken_read_int); 325 326 if (ret != 0) 327 kdb_reenter(); 328 329 return (new_pc); 330} 331