1129198Scognet/* $NetBSD: db_interface.c,v 1.33 2003/08/25 04:51:10 mrg Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright (c) 1996 Scott K. Stevens 5129198Scognet * 6129198Scognet * Mach Operating System 7129198Scognet * Copyright (c) 1991,1990 Carnegie Mellon University 8129198Scognet * All Rights Reserved. 9251866Sscottl * 10129198Scognet * Permission to use, copy, modify and distribute this software and its 11129198Scognet * documentation is hereby granted, provided that both the copyright 12129198Scognet * notice and this permission notice appear in all copies of the 13129198Scognet * software, derivative works or modified versions, and any portions 14129198Scognet * thereof, and that both notices appear in supporting documentation. 15251866Sscottl * 16129198Scognet * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 17129198Scognet * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 18129198Scognet * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 19251866Sscottl * 20129198Scognet * Carnegie Mellon requests users of this software to return to 21251866Sscottl * 22129198Scognet * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 23129198Scognet * School of Computer Science 24129198Scognet * Carnegie Mellon University 25129198Scognet * Pittsburgh PA 15213-3890 26251866Sscottl * 27129198Scognet * any improvements or extensions that they make and grant Carnegie the 28129198Scognet * rights to redistribute these changes. 29129198Scognet * 30129198Scognet * From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) 31129198Scognet */ 32129198Scognet 33129198Scognet/* 34129198Scognet * Interface to new debugger. 35129198Scognet */ 36129198Scognet 37129198Scognet#include <sys/cdefs.h> 38129198Scognet__FBSDID("$FreeBSD$"); 39129198Scognet#include "opt_ddb.h" 40129198Scognet 41129198Scognet#include <sys/param.h> 42129198Scognet#include <sys/proc.h> 43129198Scognet#include <sys/reboot.h> 44129198Scognet#include <sys/systm.h> /* just for boothowto */ 45129198Scognet#include <sys/exec.h> 46137975Scognet#ifdef KDB 47137975Scognet#include <sys/kdb.h> 48137975Scognet#endif 49129198Scognet 50129198Scognet#include <vm/vm.h> 51129198Scognet#include <vm/pmap.h> 52129198Scognet#include <vm/vm_map.h> 53129198Scognet#include <vm/vm_extern.h> 54129198Scognet 55129198Scognet#include <machine/db_machdep.h> 56129198Scognet#include <machine/vmparam.h> 57129198Scognet#include <machine/cpu.h> 58129198Scognet 59129198Scognet#include <ddb/ddb.h> 60129198Scognet#include <ddb/db_access.h> 61129198Scognet#include <ddb/db_command.h> 62129198Scognet#include <ddb/db_output.h> 63129198Scognet#include <ddb/db_variables.h> 64129198Scognet#include <ddb/db_sym.h> 65129198Scognet#include <sys/cons.h> 66129198Scognet 67132059Scognetstatic int nil = 0; 68129198Scognet 69129198Scognetint db_access_und_sp (struct db_variable *, db_expr_t *, int); 70129198Scognetint db_access_abt_sp (struct db_variable *, db_expr_t *, int); 71129198Scognetint db_access_irq_sp (struct db_variable *, db_expr_t *, int); 72129198Scognet 73147543Scognetstatic db_varfcn_t db_frame; 74147543Scognet 75132059Scognet#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) 76129198Scognetstruct db_variable db_regs[] = { 77147543Scognet { "spsr", DB_OFFSET(tf_spsr), db_frame }, 78147543Scognet { "r0", DB_OFFSET(tf_r0), db_frame }, 79147543Scognet { "r1", DB_OFFSET(tf_r1), db_frame }, 80147543Scognet { "r2", DB_OFFSET(tf_r2), db_frame }, 81147543Scognet { "r3", DB_OFFSET(tf_r3), db_frame }, 82147543Scognet { "r4", DB_OFFSET(tf_r4), db_frame }, 83147543Scognet { "r5", DB_OFFSET(tf_r5), db_frame }, 84147543Scognet { "r6", DB_OFFSET(tf_r6), db_frame }, 85147543Scognet { "r7", DB_OFFSET(tf_r7), db_frame }, 86147543Scognet { "r8", DB_OFFSET(tf_r8), db_frame }, 87147543Scognet { "r9", DB_OFFSET(tf_r9), db_frame }, 88147543Scognet { "r10", DB_OFFSET(tf_r10), db_frame }, 89147543Scognet { "r11", DB_OFFSET(tf_r11), db_frame }, 90147543Scognet { "r12", DB_OFFSET(tf_r12), db_frame }, 91147543Scognet { "usr_sp", DB_OFFSET(tf_usr_sp), db_frame }, 92147543Scognet { "usr_lr", DB_OFFSET(tf_usr_lr), db_frame }, 93147543Scognet { "svc_sp", DB_OFFSET(tf_svc_sp), db_frame }, 94147543Scognet { "svc_lr", DB_OFFSET(tf_svc_lr), db_frame }, 95147543Scognet { "pc", DB_OFFSET(tf_pc), db_frame }, 96129198Scognet { "und_sp", &nil, db_access_und_sp, }, 97129198Scognet { "abt_sp", &nil, db_access_abt_sp, }, 98129198Scognet { "irq_sp", &nil, db_access_irq_sp, }, 99129198Scognet}; 100129198Scognet 101129198Scognetstruct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); 102129198Scognet 103129198Scognetint 104129198Scognetdb_access_und_sp(struct db_variable *vp, db_expr_t *valp, int rw) 105129198Scognet{ 106129198Scognet 107147543Scognet if (rw == DB_VAR_GET) { 108129198Scognet *valp = get_stackptr(PSR_UND32_MODE); 109147543Scognet return (1); 110147543Scognet } 111166695Skevlo return (0); 112129198Scognet} 113129198Scognet 114129198Scognetint 115129198Scognetdb_access_abt_sp(struct db_variable *vp, db_expr_t *valp, int rw) 116129198Scognet{ 117129198Scognet 118147543Scognet if (rw == DB_VAR_GET) { 119129198Scognet *valp = get_stackptr(PSR_ABT32_MODE); 120147543Scognet return (1); 121147543Scognet } 122166695Skevlo return (0); 123129198Scognet} 124129198Scognet 125129198Scognetint 126129198Scognetdb_access_irq_sp(struct db_variable *vp, db_expr_t *valp, int rw) 127129198Scognet{ 128129198Scognet 129147543Scognet if (rw == DB_VAR_GET) { 130129198Scognet *valp = get_stackptr(PSR_IRQ32_MODE); 131147543Scognet return (1); 132147543Scognet } 133166695Skevlo return (0); 134129198Scognet} 135129198Scognet 136147543Scognetint db_frame(struct db_variable *vp, db_expr_t *valp, int rw) 137147543Scognet{ 138147543Scognet int *reg; 139147543Scognet 140147543Scognet if (kdb_frame == NULL) 141147543Scognet return (0); 142147543Scognet 143147543Scognet reg = (int *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep); 144147543Scognet if (rw == DB_VAR_GET) 145147543Scognet *valp = *reg; 146147543Scognet else 147147543Scognet *reg = *valp; 148166695Skevlo return (1); 149147543Scognet} 150147543Scognet 151129198Scognetvoid 152129198Scognetdb_show_mdpcpu(struct pcpu *pc) 153129198Scognet{ 154129198Scognet} 155129198Scognetint 156129198Scognetdb_validate_address(vm_offset_t addr) 157129198Scognet{ 158129198Scognet struct proc *p = curproc; 159129198Scognet struct pmap *pmap; 160129198Scognet 161129198Scognet if (!p || !p->p_vmspace || !p->p_vmspace->vm_map.pmap || 162129198Scognet#ifndef ARM32_NEW_VM_LAYOUT 163129198Scognet addr >= VM_MAXUSER_ADDRESS 164129198Scognet#else 165129198Scognet addr >= VM_MIN_KERNEL_ADDRESS 166129198Scognet#endif 167129198Scognet ) 168129198Scognet pmap = pmap_kernel(); 169129198Scognet else 170129198Scognet pmap = p->p_vmspace->vm_map.pmap; 171129198Scognet 172129198Scognet return (pmap_extract(pmap, addr) == FALSE); 173129198Scognet} 174129198Scognet 175129198Scognet/* 176129198Scognet * Read bytes from kernel address space for debugger. 177129198Scognet */ 178132059Scognetint 179129198Scognetdb_read_bytes(addr, size, data) 180129198Scognet vm_offset_t addr; 181129198Scognet size_t size; 182129198Scognet char *data; 183129198Scognet{ 184129198Scognet char *src = (char *)addr; 185129198Scognet 186129198Scognet if (db_validate_address((u_int)src)) { 187129198Scognet db_printf("address %p is invalid\n", src); 188132059Scognet return (-1); 189129198Scognet } 190129198Scognet 191129198Scognet if (size == 4 && (addr & 3) == 0 && ((uintptr_t)data & 3) == 0) { 192129198Scognet *((int*)data) = *((int*)src); 193132059Scognet return (0); 194129198Scognet } 195129198Scognet 196129198Scognet if (size == 2 && (addr & 1) == 0 && ((uintptr_t)data & 1) == 0) { 197129198Scognet *((short*)data) = *((short*)src); 198132059Scognet return (0); 199129198Scognet } 200129198Scognet 201129198Scognet while (size-- > 0) { 202129198Scognet if (db_validate_address((u_int)src)) { 203129198Scognet db_printf("address %p is invalid\n", src); 204132059Scognet return (-1); 205129198Scognet } 206129198Scognet *data++ = *src++; 207129198Scognet } 208132059Scognet return (0); 209129198Scognet} 210129198Scognet 211129198Scognet/* 212129198Scognet * Write bytes to kernel address space for debugger. 213129198Scognet */ 214132059Scognetint 215129198Scognetdb_write_bytes(vm_offset_t addr, size_t size, char *data) 216129198Scognet{ 217129198Scognet char *dst; 218129198Scognet size_t loop; 219129198Scognet 220129198Scognet dst = (char *)addr; 221129198Scognet if (db_validate_address((u_int)dst)) { 222129198Scognet db_printf("address %p is invalid\n", dst); 223132059Scognet return (0); 224129198Scognet } 225129198Scognet 226129198Scognet if (size == 4 && (addr & 3) == 0 && ((uintptr_t)data & 3) == 0) 227129198Scognet *((int*)dst) = *((int*)data); 228129198Scognet else 229129198Scognet if (size == 2 && (addr & 1) == 0 && ((uintptr_t)data & 1) == 0) 230129198Scognet *((short*)dst) = *((short*)data); 231129198Scognet else { 232129198Scognet loop = size; 233129198Scognet while (loop-- > 0) { 234129198Scognet if (db_validate_address((u_int)dst)) { 235129198Scognet db_printf("address %p is invalid\n", dst); 236132059Scognet return (-1); 237129198Scognet } 238129198Scognet *dst++ = *data++; 239129198Scognet } 240129198Scognet } 241129198Scognet 242129198Scognet /* make sure the caches and memory are in sync */ 243129198Scognet cpu_icache_sync_range(addr, size); 244129198Scognet 245129198Scognet /* In case the current page tables have been modified ... */ 246129198Scognet cpu_tlb_flushID(); 247129198Scognet cpu_cpwait(); 248129198Scognet return (0); 249129198Scognet} 250129198Scognet 251129198Scognet 252137975Scognetstatic u_int 253137975Scognetdb_fetch_reg(int reg) 254137975Scognet{ 255129198Scognet 256137975Scognet switch (reg) { 257137975Scognet case 0: 258137975Scognet return (kdb_frame->tf_r0); 259137975Scognet case 1: 260137975Scognet return (kdb_frame->tf_r1); 261137975Scognet case 2: 262137975Scognet return (kdb_frame->tf_r2); 263137975Scognet case 3: 264137975Scognet return (kdb_frame->tf_r3); 265137975Scognet case 4: 266137975Scognet return (kdb_frame->tf_r4); 267137975Scognet case 5: 268137975Scognet return (kdb_frame->tf_r5); 269137975Scognet case 6: 270137975Scognet return (kdb_frame->tf_r6); 271137975Scognet case 7: 272137975Scognet return (kdb_frame->tf_r7); 273137975Scognet case 8: 274137975Scognet return (kdb_frame->tf_r8); 275137975Scognet case 9: 276137975Scognet return (kdb_frame->tf_r9); 277137975Scognet case 10: 278137975Scognet return (kdb_frame->tf_r10); 279137975Scognet case 11: 280137975Scognet return (kdb_frame->tf_r11); 281137975Scognet case 12: 282137975Scognet return (kdb_frame->tf_r12); 283137975Scognet case 13: 284137975Scognet return (kdb_frame->tf_svc_sp); 285137975Scognet case 14: 286137975Scognet return (kdb_frame->tf_svc_lr); 287137975Scognet case 15: 288137975Scognet return (kdb_frame->tf_pc); 289137975Scognet default: 290137975Scognet panic("db_fetch_reg: botch"); 291137975Scognet } 292137975Scognet} 293137975Scognet 294137975Scognetu_int 295137975Scognetbranch_taken(u_int insn, db_addr_t pc) 296137975Scognet{ 297181223Scognet u_int addr, nregs, offset = 0; 298137975Scognet 299137975Scognet switch ((insn >> 24) & 0xf) { 300181253Scognet case 0x2: /* add pc, reg1, #value */ 301181253Scognet case 0x0: /* add pc, reg1, reg2, lsl #offset */ 302181253Scognet addr = db_fetch_reg((insn >> 16) & 0xf); 303181253Scognet if (((insn >> 16) & 0xf) == 15) 304181253Scognet addr += 8; 305181253Scognet if (insn & 0x0200000) { 306181253Scognet offset = (insn >> 7) & 0x1e; 307181253Scognet offset = (insn & 0xff) << (32 - offset) | 308181253Scognet (insn & 0xff) >> offset; 309181253Scognet } else { 310181253Scognet 311181253Scognet offset = db_fetch_reg(insn & 0x0f); 312181253Scognet if ((insn & 0x0000ff0) != 0x00000000) { 313181253Scognet if (insn & 0x10) 314181253Scognet nregs = db_fetch_reg((insn >> 8) & 0xf); 315181253Scognet else 316181253Scognet nregs = (insn >> 7) & 0x1f; 317181253Scognet switch ((insn >> 5) & 3) { 318181253Scognet case 0: 319181253Scognet /* lsl */ 320181253Scognet offset = offset << nregs; 321181253Scognet break; 322181253Scognet case 1: 323181253Scognet /* lsr */ 324181253Scognet offset = offset >> nregs; 325181253Scognet break; 326181253Scognet default: 327181253Scognet break; /* XXX */ 328251866Sscottl } 329181253Scognet 330181253Scognet } 331181253Scognet return (addr + offset); 332181253Scognet 333181253Scognet } 334181253Scognet 335137975Scognet case 0xa: /* b ... */ 336137975Scognet case 0xb: /* bl ... */ 337137975Scognet addr = ((insn << 2) & 0x03ffffff); 338137975Scognet if (addr & 0x02000000) 339137975Scognet addr |= 0xfc000000; 340137975Scognet return (pc + 8 + addr); 341137975Scognet case 0x7: /* ldr pc, [pc, reg, lsl #2] */ 342137975Scognet addr = db_fetch_reg(insn & 0xf); 343137975Scognet addr = pc + 8 + (addr << 2); 344137975Scognet db_read_bytes(addr, 4, (char *)&addr); 345137975Scognet return (addr); 346137975Scognet case 0x1: /* mov pc, reg */ 347137975Scognet addr = db_fetch_reg(insn & 0xf); 348137975Scognet return (addr); 349181253Scognet case 0x4: 350181223Scognet case 0x5: /* ldr pc, [reg] */ 351181223Scognet addr = db_fetch_reg((insn >> 16) & 0xf); 352181223Scognet /* ldr pc, [reg, #offset] */ 353181223Scognet if (insn & (1 << 24)) 354181223Scognet offset = insn & 0xfff; 355181223Scognet if (insn & 0x00800000) 356181223Scognet addr += offset; 357181223Scognet else 358181223Scognet addr -= offset; 359181223Scognet db_read_bytes(addr, 4, (char *)&addr); 360181223Scognet return (addr); 361137975Scognet case 0x8: /* ldmxx reg, {..., pc} */ 362137975Scognet case 0x9: 363137975Scognet addr = db_fetch_reg((insn >> 16) & 0xf); 364137975Scognet nregs = (insn & 0x5555) + ((insn >> 1) & 0x5555); 365137975Scognet nregs = (nregs & 0x3333) + ((nregs >> 2) & 0x3333); 366137975Scognet nregs = (nregs + (nregs >> 4)) & 0x0f0f; 367137975Scognet nregs = (nregs + (nregs >> 8)) & 0x001f; 368137975Scognet switch ((insn >> 23) & 0x3) { 369137975Scognet case 0x0: /* ldmda */ 370137975Scognet addr = addr - 0; 371137975Scognet break; 372137975Scognet case 0x1: /* ldmia */ 373137975Scognet addr = addr + 0 + ((nregs - 1) << 2); 374137975Scognet break; 375137975Scognet case 0x2: /* ldmdb */ 376137975Scognet addr = addr - 4; 377137975Scognet break; 378137975Scognet case 0x3: /* ldmib */ 379137975Scognet addr = addr + 4 + ((nregs - 1) << 2); 380137975Scognet break; 381137975Scognet } 382137975Scognet db_read_bytes(addr, 4, (char *)&addr); 383137975Scognet return (addr); 384137975Scognet default: 385137975Scognet panic("branch_taken: botch"); 386137975Scognet } 387137975Scognet} 388