db_interface.c revision 147543
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. 9129198Scognet * 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. 15129198Scognet * 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. 19129198Scognet * 20129198Scognet * Carnegie Mellon requests users of this software to return to 21129198Scognet * 22129198Scognet * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 23129198Scognet * School of Computer Science 24129198Scognet * Carnegie Mellon University 25129198Scognet * Pittsburgh PA 15213-3890 26129198Scognet * 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: head/sys/arm/arm/db_interface.c 147543 2005-06-23 11:38:47Z cognet $"); 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/katelib.h> 57129198Scognet#include <machine/vmparam.h> 58129198Scognet#include <machine/cpu.h> 59129198Scognet 60129198Scognet#include <ddb/ddb.h> 61129198Scognet#include <ddb/db_access.h> 62129198Scognet#include <ddb/db_command.h> 63129198Scognet#include <ddb/db_output.h> 64129198Scognet#include <ddb/db_variables.h> 65129198Scognet#include <ddb/db_sym.h> 66129198Scognet#include <sys/cons.h> 67129198Scognet 68132059Scognetstatic int nil = 0; 69129198Scognet 70129198Scognetint db_access_und_sp (struct db_variable *, db_expr_t *, int); 71129198Scognetint db_access_abt_sp (struct db_variable *, db_expr_t *, int); 72129198Scognetint db_access_irq_sp (struct db_variable *, db_expr_t *, int); 73129198Scognet 74147543Scognetstatic db_varfcn_t db_frame; 75147543Scognet 76132059Scognet#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) 77129198Scognetstruct db_variable db_regs[] = { 78147543Scognet { "spsr", DB_OFFSET(tf_spsr), db_frame }, 79147543Scognet { "r0", DB_OFFSET(tf_r0), db_frame }, 80147543Scognet { "r1", DB_OFFSET(tf_r1), db_frame }, 81147543Scognet { "r2", DB_OFFSET(tf_r2), db_frame }, 82147543Scognet { "r3", DB_OFFSET(tf_r3), db_frame }, 83147543Scognet { "r4", DB_OFFSET(tf_r4), db_frame }, 84147543Scognet { "r5", DB_OFFSET(tf_r5), db_frame }, 85147543Scognet { "r6", DB_OFFSET(tf_r6), db_frame }, 86147543Scognet { "r7", DB_OFFSET(tf_r7), db_frame }, 87147543Scognet { "r8", DB_OFFSET(tf_r8), db_frame }, 88147543Scognet { "r9", DB_OFFSET(tf_r9), db_frame }, 89147543Scognet { "r10", DB_OFFSET(tf_r10), db_frame }, 90147543Scognet { "r11", DB_OFFSET(tf_r11), db_frame }, 91147543Scognet { "r12", DB_OFFSET(tf_r12), db_frame }, 92147543Scognet { "usr_sp", DB_OFFSET(tf_usr_sp), db_frame }, 93147543Scognet { "usr_lr", DB_OFFSET(tf_usr_lr), db_frame }, 94147543Scognet { "svc_sp", DB_OFFSET(tf_svc_sp), db_frame }, 95147543Scognet { "svc_lr", DB_OFFSET(tf_svc_lr), db_frame }, 96147543Scognet { "pc", DB_OFFSET(tf_pc), db_frame }, 97129198Scognet { "und_sp", &nil, db_access_und_sp, }, 98129198Scognet { "abt_sp", &nil, db_access_abt_sp, }, 99129198Scognet { "irq_sp", &nil, db_access_irq_sp, }, 100129198Scognet}; 101129198Scognet 102129198Scognetstruct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); 103129198Scognet 104129198Scognetint 105129198Scognetdb_access_und_sp(struct db_variable *vp, db_expr_t *valp, int rw) 106129198Scognet{ 107129198Scognet 108147543Scognet if (rw == DB_VAR_GET) { 109129198Scognet *valp = get_stackptr(PSR_UND32_MODE); 110147543Scognet return (1); 111147543Scognet } 112129198Scognet return(0); 113129198Scognet} 114129198Scognet 115129198Scognetint 116129198Scognetdb_access_abt_sp(struct db_variable *vp, db_expr_t *valp, int rw) 117129198Scognet{ 118129198Scognet 119147543Scognet if (rw == DB_VAR_GET) { 120129198Scognet *valp = get_stackptr(PSR_ABT32_MODE); 121147543Scognet return (1); 122147543Scognet } 123129198Scognet return(0); 124129198Scognet} 125129198Scognet 126129198Scognetint 127129198Scognetdb_access_irq_sp(struct db_variable *vp, db_expr_t *valp, int rw) 128129198Scognet{ 129129198Scognet 130147543Scognet if (rw == DB_VAR_GET) { 131129198Scognet *valp = get_stackptr(PSR_IRQ32_MODE); 132147543Scognet return (1); 133147543Scognet } 134129198Scognet return(0); 135129198Scognet} 136129198Scognet 137147543Scognetint db_frame(struct db_variable *vp, db_expr_t *valp, int rw) 138147543Scognet{ 139147543Scognet int *reg; 140147543Scognet 141147543Scognet if (kdb_frame == NULL) 142147543Scognet return (0); 143147543Scognet 144147543Scognet reg = (int *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep); 145147543Scognet if (rw == DB_VAR_GET) 146147543Scognet *valp = *reg; 147147543Scognet else 148147543Scognet *reg = *valp; 149147543Scognet return(1); 150147543Scognet} 151147543Scognet 152129198Scognetvoid 153129198Scognetdb_show_mdpcpu(struct pcpu *pc) 154129198Scognet{ 155129198Scognet} 156129198Scognetint 157129198Scognetdb_validate_address(vm_offset_t addr) 158129198Scognet{ 159129198Scognet struct proc *p = curproc; 160129198Scognet struct pmap *pmap; 161129198Scognet 162129198Scognet if (!p || !p->p_vmspace || !p->p_vmspace->vm_map.pmap || 163129198Scognet#ifndef ARM32_NEW_VM_LAYOUT 164129198Scognet addr >= VM_MAXUSER_ADDRESS 165129198Scognet#else 166129198Scognet addr >= VM_MIN_KERNEL_ADDRESS 167129198Scognet#endif 168129198Scognet ) 169129198Scognet pmap = pmap_kernel(); 170129198Scognet else 171129198Scognet pmap = p->p_vmspace->vm_map.pmap; 172129198Scognet 173129198Scognet return (pmap_extract(pmap, addr) == FALSE); 174129198Scognet} 175129198Scognet 176129198Scognet/* 177129198Scognet * Read bytes from kernel address space for debugger. 178129198Scognet */ 179132059Scognetint 180129198Scognetdb_read_bytes(addr, size, data) 181129198Scognet vm_offset_t addr; 182129198Scognet size_t size; 183129198Scognet char *data; 184129198Scognet{ 185129198Scognet char *src = (char *)addr; 186129198Scognet 187129198Scognet if (db_validate_address((u_int)src)) { 188129198Scognet db_printf("address %p is invalid\n", src); 189132059Scognet return (-1); 190129198Scognet } 191129198Scognet 192129198Scognet if (size == 4 && (addr & 3) == 0 && ((uintptr_t)data & 3) == 0) { 193129198Scognet *((int*)data) = *((int*)src); 194132059Scognet return (0); 195129198Scognet } 196129198Scognet 197129198Scognet if (size == 2 && (addr & 1) == 0 && ((uintptr_t)data & 1) == 0) { 198129198Scognet *((short*)data) = *((short*)src); 199132059Scognet return (0); 200129198Scognet } 201129198Scognet 202129198Scognet while (size-- > 0) { 203129198Scognet if (db_validate_address((u_int)src)) { 204129198Scognet db_printf("address %p is invalid\n", src); 205132059Scognet return (-1); 206129198Scognet } 207129198Scognet *data++ = *src++; 208129198Scognet } 209132059Scognet return (0); 210129198Scognet} 211129198Scognet 212129198Scognet/* 213129198Scognet * Write bytes to kernel address space for debugger. 214129198Scognet */ 215132059Scognetint 216129198Scognetdb_write_bytes(vm_offset_t addr, size_t size, char *data) 217129198Scognet{ 218129198Scognet char *dst; 219129198Scognet size_t loop; 220129198Scognet 221129198Scognet dst = (char *)addr; 222129198Scognet if (db_validate_address((u_int)dst)) { 223129198Scognet db_printf("address %p is invalid\n", dst); 224132059Scognet return (0); 225129198Scognet } 226129198Scognet 227129198Scognet if (size == 4 && (addr & 3) == 0 && ((uintptr_t)data & 3) == 0) 228129198Scognet *((int*)dst) = *((int*)data); 229129198Scognet else 230129198Scognet if (size == 2 && (addr & 1) == 0 && ((uintptr_t)data & 1) == 0) 231129198Scognet *((short*)dst) = *((short*)data); 232129198Scognet else { 233129198Scognet loop = size; 234129198Scognet while (loop-- > 0) { 235129198Scognet if (db_validate_address((u_int)dst)) { 236129198Scognet db_printf("address %p is invalid\n", dst); 237132059Scognet return (-1); 238129198Scognet } 239129198Scognet *dst++ = *data++; 240129198Scognet } 241129198Scognet } 242129198Scognet 243129198Scognet /* make sure the caches and memory are in sync */ 244129198Scognet cpu_icache_sync_range(addr, size); 245129198Scognet 246129198Scognet /* In case the current page tables have been modified ... */ 247129198Scognet cpu_tlb_flushID(); 248129198Scognet cpu_cpwait(); 249129198Scognet return (0); 250129198Scognet} 251129198Scognet 252129198Scognet 253137975Scognetstatic u_int 254137975Scognetdb_fetch_reg(int reg) 255137975Scognet{ 256129198Scognet 257137975Scognet switch (reg) { 258137975Scognet case 0: 259137975Scognet return (kdb_frame->tf_r0); 260137975Scognet case 1: 261137975Scognet return (kdb_frame->tf_r1); 262137975Scognet case 2: 263137975Scognet return (kdb_frame->tf_r2); 264137975Scognet case 3: 265137975Scognet return (kdb_frame->tf_r3); 266137975Scognet case 4: 267137975Scognet return (kdb_frame->tf_r4); 268137975Scognet case 5: 269137975Scognet return (kdb_frame->tf_r5); 270137975Scognet case 6: 271137975Scognet return (kdb_frame->tf_r6); 272137975Scognet case 7: 273137975Scognet return (kdb_frame->tf_r7); 274137975Scognet case 8: 275137975Scognet return (kdb_frame->tf_r8); 276137975Scognet case 9: 277137975Scognet return (kdb_frame->tf_r9); 278137975Scognet case 10: 279137975Scognet return (kdb_frame->tf_r10); 280137975Scognet case 11: 281137975Scognet return (kdb_frame->tf_r11); 282137975Scognet case 12: 283137975Scognet return (kdb_frame->tf_r12); 284137975Scognet case 13: 285137975Scognet return (kdb_frame->tf_svc_sp); 286137975Scognet case 14: 287137975Scognet return (kdb_frame->tf_svc_lr); 288137975Scognet case 15: 289137975Scognet return (kdb_frame->tf_pc); 290137975Scognet default: 291137975Scognet panic("db_fetch_reg: botch"); 292137975Scognet } 293137975Scognet} 294137975Scognet 295137975Scognetu_int 296137975Scognetbranch_taken(u_int insn, db_addr_t pc) 297137975Scognet{ 298137975Scognet u_int addr, nregs; 299137975Scognet 300137975Scognet switch ((insn >> 24) & 0xf) { 301137975Scognet case 0xa: /* b ... */ 302137975Scognet case 0xb: /* bl ... */ 303137975Scognet addr = ((insn << 2) & 0x03ffffff); 304137975Scognet if (addr & 0x02000000) 305137975Scognet addr |= 0xfc000000; 306137975Scognet return (pc + 8 + addr); 307137975Scognet case 0x7: /* ldr pc, [pc, reg, lsl #2] */ 308137975Scognet addr = db_fetch_reg(insn & 0xf); 309137975Scognet addr = pc + 8 + (addr << 2); 310137975Scognet db_read_bytes(addr, 4, (char *)&addr); 311137975Scognet return (addr); 312137975Scognet case 0x1: /* mov pc, reg */ 313137975Scognet addr = db_fetch_reg(insn & 0xf); 314137975Scognet return (addr); 315137975Scognet case 0x8: /* ldmxx reg, {..., pc} */ 316137975Scognet case 0x9: 317137975Scognet addr = db_fetch_reg((insn >> 16) & 0xf); 318137975Scognet nregs = (insn & 0x5555) + ((insn >> 1) & 0x5555); 319137975Scognet nregs = (nregs & 0x3333) + ((nregs >> 2) & 0x3333); 320137975Scognet nregs = (nregs + (nregs >> 4)) & 0x0f0f; 321137975Scognet nregs = (nregs + (nregs >> 8)) & 0x001f; 322137975Scognet switch ((insn >> 23) & 0x3) { 323137975Scognet case 0x0: /* ldmda */ 324137975Scognet addr = addr - 0; 325137975Scognet break; 326137975Scognet case 0x1: /* ldmia */ 327137975Scognet addr = addr + 0 + ((nregs - 1) << 2); 328137975Scognet break; 329137975Scognet case 0x2: /* ldmdb */ 330137975Scognet addr = addr - 4; 331137975Scognet break; 332137975Scognet case 0x3: /* ldmib */ 333137975Scognet addr = addr + 4 + ((nregs - 1) << 2); 334137975Scognet break; 335137975Scognet } 336137975Scognet db_read_bytes(addr, 4, (char *)&addr); 337137975Scognet return (addr); 338137975Scognet default: 339137975Scognet panic("branch_taken: botch"); 340137975Scognet } 341137975Scognet} 342137975Scognet 343