xref: /freebsd-src/sys/arm/arm/db_interface.c (revision 9d2c93c249962364d599852f00c161870b28f33d)
16fc729afSOlivier Houchard /*	$NetBSD: db_interface.c,v 1.33 2003/08/25 04:51:10 mrg Exp $	*/
26fc729afSOlivier Houchard 
3d8315c79SWarner Losh /*-
46fc729afSOlivier Houchard  * Copyright (c) 1996 Scott K. Stevens
56fc729afSOlivier Houchard  *
66fc729afSOlivier Houchard  * Mach Operating System
76fc729afSOlivier Houchard  * Copyright (c) 1991,1990 Carnegie Mellon University
86fc729afSOlivier Houchard  * All Rights Reserved.
96fc729afSOlivier Houchard  *
106fc729afSOlivier Houchard  * Permission to use, copy, modify and distribute this software and its
116fc729afSOlivier Houchard  * documentation is hereby granted, provided that both the copyright
126fc729afSOlivier Houchard  * notice and this permission notice appear in all copies of the
136fc729afSOlivier Houchard  * software, derivative works or modified versions, and any portions
146fc729afSOlivier Houchard  * thereof, and that both notices appear in supporting documentation.
156fc729afSOlivier Houchard  *
166fc729afSOlivier Houchard  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
176fc729afSOlivier Houchard  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
186fc729afSOlivier Houchard  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
196fc729afSOlivier Houchard  *
206fc729afSOlivier Houchard  * Carnegie Mellon requests users of this software to return to
216fc729afSOlivier Houchard  *
226fc729afSOlivier Houchard  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
236fc729afSOlivier Houchard  *  School of Computer Science
246fc729afSOlivier Houchard  *  Carnegie Mellon University
256fc729afSOlivier Houchard  *  Pittsburgh PA 15213-3890
266fc729afSOlivier Houchard  *
276fc729afSOlivier Houchard  * any improvements or extensions that they make and grant Carnegie the
286fc729afSOlivier Houchard  * rights to redistribute these changes.
296fc729afSOlivier Houchard  *
306fc729afSOlivier Houchard  *	From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
316fc729afSOlivier Houchard  */
326fc729afSOlivier Houchard 
336fc729afSOlivier Houchard /*
346fc729afSOlivier Houchard  * Interface to new debugger.
356fc729afSOlivier Houchard  */
366fc729afSOlivier Houchard 
376fc729afSOlivier Houchard #include "opt_ddb.h"
386fc729afSOlivier Houchard 
396fc729afSOlivier Houchard #include <sys/param.h>
40a89156f5SMichal Meloun #include <sys/cons.h>
416fc729afSOlivier Houchard #include <sys/proc.h>
426fc729afSOlivier Houchard #include <sys/reboot.h>
436fc729afSOlivier Houchard #include <sys/exec.h>
449ebe15a1SOlivier Houchard #ifdef KDB
459ebe15a1SOlivier Houchard #include <sys/kdb.h>
469ebe15a1SOlivier Houchard #endif
476fc729afSOlivier Houchard 
486fc729afSOlivier Houchard #include <vm/vm.h>
496fc729afSOlivier Houchard #include <vm/pmap.h>
506fc729afSOlivier Houchard #include <vm/vm_map.h>
516fc729afSOlivier Houchard #include <vm/vm_extern.h>
526fc729afSOlivier Houchard 
536fc729afSOlivier Houchard #include <machine/db_machdep.h>
54a89156f5SMichal Meloun #include <machine/cpu.h>
55232e189aSZbigniew Bodek #include <machine/machdep.h>
566fc729afSOlivier Houchard #include <machine/vmparam.h>
576fc729afSOlivier Houchard 
586fc729afSOlivier Houchard #include <ddb/ddb.h>
596fc729afSOlivier Houchard #include <ddb/db_access.h>
606fc729afSOlivier Houchard #include <ddb/db_command.h>
616fc729afSOlivier Houchard #include <ddb/db_output.h>
626fc729afSOlivier Houchard #include <ddb/db_variables.h>
636fc729afSOlivier Houchard #include <ddb/db_sym.h>
64a89156f5SMichal Meloun 
652f6d0d8fSOlivier Houchard static int nil = 0;
666fc729afSOlivier Houchard 
676fc729afSOlivier Houchard int db_access_und_sp (struct db_variable *, db_expr_t *, int);
686fc729afSOlivier Houchard int db_access_abt_sp (struct db_variable *, db_expr_t *, int);
696fc729afSOlivier Houchard int db_access_irq_sp (struct db_variable *, db_expr_t *, int);
706fc729afSOlivier Houchard 
7131897fe8SOlivier Houchard static db_varfcn_t db_frame;
7231897fe8SOlivier Houchard 
732f6d0d8fSOlivier Houchard #define DB_OFFSET(x)	(db_expr_t *)offsetof(struct trapframe, x)
746fc729afSOlivier Houchard struct db_variable db_regs[] = {
7531897fe8SOlivier Houchard 	{ "spsr", DB_OFFSET(tf_spsr),	db_frame },
7631897fe8SOlivier Houchard 	{ "r0", DB_OFFSET(tf_r0),	db_frame },
7731897fe8SOlivier Houchard 	{ "r1", DB_OFFSET(tf_r1),	db_frame },
7831897fe8SOlivier Houchard 	{ "r2", DB_OFFSET(tf_r2),	db_frame },
7931897fe8SOlivier Houchard 	{ "r3", DB_OFFSET(tf_r3),	db_frame },
8031897fe8SOlivier Houchard 	{ "r4", DB_OFFSET(tf_r4),	db_frame },
8131897fe8SOlivier Houchard 	{ "r5", DB_OFFSET(tf_r5),	db_frame },
8231897fe8SOlivier Houchard 	{ "r6", DB_OFFSET(tf_r6),	db_frame },
8331897fe8SOlivier Houchard 	{ "r7", DB_OFFSET(tf_r7),	db_frame },
8431897fe8SOlivier Houchard 	{ "r8", DB_OFFSET(tf_r8),	db_frame },
8531897fe8SOlivier Houchard 	{ "r9", DB_OFFSET(tf_r9),	db_frame },
8631897fe8SOlivier Houchard 	{ "r10", DB_OFFSET(tf_r10),	db_frame },
8731897fe8SOlivier Houchard 	{ "r11", DB_OFFSET(tf_r11),	db_frame },
8831897fe8SOlivier Houchard 	{ "r12", DB_OFFSET(tf_r12),	db_frame },
8931897fe8SOlivier Houchard 	{ "usr_sp", DB_OFFSET(tf_usr_sp), db_frame },
9031897fe8SOlivier Houchard 	{ "usr_lr", DB_OFFSET(tf_usr_lr), db_frame },
9131897fe8SOlivier Houchard 	{ "svc_sp", DB_OFFSET(tf_svc_sp), db_frame },
9231897fe8SOlivier Houchard 	{ "svc_lr", DB_OFFSET(tf_svc_lr), db_frame },
9331897fe8SOlivier Houchard 	{ "pc", DB_OFFSET(tf_pc), 	db_frame },
946fc729afSOlivier Houchard 	{ "und_sp", &nil, db_access_und_sp, },
956fc729afSOlivier Houchard 	{ "abt_sp", &nil, db_access_abt_sp, },
966fc729afSOlivier Houchard 	{ "irq_sp", &nil, db_access_irq_sp, },
976fc729afSOlivier Houchard };
986fc729afSOlivier Houchard 
9933495e5dSPedro F. Giffuni struct db_variable *db_eregs = db_regs + nitems(db_regs);
1006fc729afSOlivier Houchard 
1016fc729afSOlivier Houchard int
db_access_und_sp(struct db_variable * vp,db_expr_t * valp,int rw)1026fc729afSOlivier Houchard db_access_und_sp(struct db_variable *vp, db_expr_t *valp, int rw)
1036fc729afSOlivier Houchard {
1046fc729afSOlivier Houchard 
10531897fe8SOlivier Houchard 	if (rw == DB_VAR_GET) {
1066fc729afSOlivier Houchard 		*valp = get_stackptr(PSR_UND32_MODE);
10731897fe8SOlivier Houchard 		return (1);
10831897fe8SOlivier Houchard 	}
1096fc729afSOlivier Houchard 	return (0);
1106fc729afSOlivier Houchard }
1116fc729afSOlivier Houchard 
1126fc729afSOlivier Houchard int
db_access_abt_sp(struct db_variable * vp,db_expr_t * valp,int rw)1136fc729afSOlivier Houchard db_access_abt_sp(struct db_variable *vp, db_expr_t *valp, int rw)
1146fc729afSOlivier Houchard {
1156fc729afSOlivier Houchard 
11631897fe8SOlivier Houchard 	if (rw == DB_VAR_GET) {
1176fc729afSOlivier Houchard 		*valp = get_stackptr(PSR_ABT32_MODE);
11831897fe8SOlivier Houchard 		return (1);
11931897fe8SOlivier Houchard 	}
1206fc729afSOlivier Houchard 	return (0);
1216fc729afSOlivier Houchard }
1226fc729afSOlivier Houchard 
1236fc729afSOlivier Houchard int
db_access_irq_sp(struct db_variable * vp,db_expr_t * valp,int rw)1246fc729afSOlivier Houchard db_access_irq_sp(struct db_variable *vp, db_expr_t *valp, int rw)
1256fc729afSOlivier Houchard {
1266fc729afSOlivier Houchard 
12731897fe8SOlivier Houchard 	if (rw == DB_VAR_GET) {
1286fc729afSOlivier Houchard 		*valp = get_stackptr(PSR_IRQ32_MODE);
12931897fe8SOlivier Houchard 		return (1);
13031897fe8SOlivier Houchard 	}
1316fc729afSOlivier Houchard 	return (0);
1326fc729afSOlivier Houchard }
1336fc729afSOlivier Houchard 
db_frame(struct db_variable * vp,db_expr_t * valp,int rw)13431897fe8SOlivier Houchard int db_frame(struct db_variable *vp, db_expr_t *valp, int rw)
13531897fe8SOlivier Houchard {
13631897fe8SOlivier Houchard 	int *reg;
13731897fe8SOlivier Houchard 
13831897fe8SOlivier Houchard 	if (kdb_frame == NULL)
13931897fe8SOlivier Houchard 		return (0);
14031897fe8SOlivier Houchard 
14131897fe8SOlivier Houchard 	reg = (int *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep);
14231897fe8SOlivier Houchard 	if (rw == DB_VAR_GET)
14331897fe8SOlivier Houchard 		*valp = *reg;
14431897fe8SOlivier Houchard 	else
14531897fe8SOlivier Houchard 		*reg = *valp;
14631897fe8SOlivier Houchard 	return (1);
14731897fe8SOlivier Houchard }
14831897fe8SOlivier Houchard 
1496fc729afSOlivier Houchard void
db_show_mdpcpu(struct pcpu * pc)1506fc729afSOlivier Houchard db_show_mdpcpu(struct pcpu *pc)
1516fc729afSOlivier Houchard {
152514ba655SSvatopluk Kraus 
153514ba655SSvatopluk Kraus 	db_printf("curpmap      = %p\n", pc->pc_curpmap);
1546fc729afSOlivier Houchard }
1555c2967f6SMichal Meloun 
1566fc729afSOlivier Houchard int
db_validate_address(vm_offset_t addr)1576fc729afSOlivier Houchard db_validate_address(vm_offset_t addr)
1586fc729afSOlivier Houchard {
1596fc729afSOlivier Houchard 	struct proc *p = curproc;
1606fc729afSOlivier Houchard 	struct pmap *pmap;
1616fc729afSOlivier Houchard 
1626fc729afSOlivier Houchard 	if (!p || !p->p_vmspace || !p->p_vmspace->vm_map.pmap ||
1636fc729afSOlivier Houchard #ifndef ARM32_NEW_VM_LAYOUT
1646fc729afSOlivier Houchard 	    addr >= VM_MAXUSER_ADDRESS
1656fc729afSOlivier Houchard #else
1666fc729afSOlivier Houchard 	    addr >= VM_MIN_KERNEL_ADDRESS
1676fc729afSOlivier Houchard #endif
1686fc729afSOlivier Houchard 	   )
169480f7464SSvatopluk Kraus 		pmap = kernel_pmap;
1706fc729afSOlivier Houchard 	else
1716fc729afSOlivier Houchard 		pmap = p->p_vmspace->vm_map.pmap;
1726fc729afSOlivier Houchard 
173*afb1a3e3SJohn Baldwin 	return (pmap_extract(pmap, addr) == 0);
1746fc729afSOlivier Houchard }
1756fc729afSOlivier Houchard 
1766fc729afSOlivier Houchard /*
1776fc729afSOlivier Houchard  * Read bytes from kernel address space for debugger.
1786fc729afSOlivier Houchard  */
1792f6d0d8fSOlivier Houchard int
db_read_bytes(vm_offset_t addr,size_t size,char * data)180bf043855SJohn Baldwin db_read_bytes(vm_offset_t addr, size_t size, char *data)
1816fc729afSOlivier Houchard {
1826fc729afSOlivier Houchard 	char	*src = (char *)addr;
1836fc729afSOlivier Houchard 
1846fc729afSOlivier Houchard 	if (db_validate_address((u_int)src)) {
1856fc729afSOlivier Houchard 		db_printf("address %p is invalid\n", src);
1862f6d0d8fSOlivier Houchard 		return (-1);
1876fc729afSOlivier Houchard 	}
1886fc729afSOlivier Houchard 
1896fc729afSOlivier Houchard 	if (size == 4 && (addr & 3) == 0 && ((uintptr_t)data & 3) == 0) {
1906fc729afSOlivier Houchard 		*((int*)data) = *((int*)src);
1912f6d0d8fSOlivier Houchard 		return (0);
1926fc729afSOlivier Houchard 	}
1936fc729afSOlivier Houchard 
1946fc729afSOlivier Houchard 	if (size == 2 && (addr & 1) == 0 && ((uintptr_t)data & 1) == 0) {
1956fc729afSOlivier Houchard 		*((short*)data) = *((short*)src);
1962f6d0d8fSOlivier Houchard 		return (0);
1976fc729afSOlivier Houchard 	}
1986fc729afSOlivier Houchard 
1996fc729afSOlivier Houchard 	while (size-- > 0) {
2006fc729afSOlivier Houchard 		if (db_validate_address((u_int)src)) {
2016fc729afSOlivier Houchard 			db_printf("address %p is invalid\n", src);
2022f6d0d8fSOlivier Houchard 			return (-1);
2036fc729afSOlivier Houchard 		}
2046fc729afSOlivier Houchard 		*data++ = *src++;
2056fc729afSOlivier Houchard 	}
2062f6d0d8fSOlivier Houchard 	return (0);
2076fc729afSOlivier Houchard }
2086fc729afSOlivier Houchard 
2096fc729afSOlivier Houchard /*
2106fc729afSOlivier Houchard  * Write bytes to kernel address space for debugger.
2116fc729afSOlivier Houchard  */
2122f6d0d8fSOlivier Houchard int
db_write_bytes(vm_offset_t addr,size_t size,char * data)2136fc729afSOlivier Houchard db_write_bytes(vm_offset_t addr, size_t size, char *data)
2146fc729afSOlivier Houchard {
2156fc729afSOlivier Houchard 	char *dst;
2166fc729afSOlivier Houchard 	size_t loop;
2176fc729afSOlivier Houchard 
2186fc729afSOlivier Houchard 	dst = (char *)addr;
2196fc729afSOlivier Houchard 	if (db_validate_address((u_int)dst)) {
2206fc729afSOlivier Houchard 		db_printf("address %p is invalid\n", dst);
2212f6d0d8fSOlivier Houchard 		return (0);
2226fc729afSOlivier Houchard 	}
2236fc729afSOlivier Houchard 
2246fc729afSOlivier Houchard 	if (size == 4 && (addr & 3) == 0 && ((uintptr_t)data & 3) == 0)
2256fc729afSOlivier Houchard 		*((int*)dst) = *((int*)data);
2266fc729afSOlivier Houchard 	else
2276fc729afSOlivier Houchard 	if (size == 2 && (addr & 1) == 0 && ((uintptr_t)data & 1) == 0)
2286fc729afSOlivier Houchard 		*((short*)dst) = *((short*)data);
2296fc729afSOlivier Houchard 	else {
2306fc729afSOlivier Houchard 		loop = size;
2316fc729afSOlivier Houchard 		while (loop-- > 0) {
2326fc729afSOlivier Houchard 			if (db_validate_address((u_int)dst)) {
2336fc729afSOlivier Houchard 				db_printf("address %p is invalid\n", dst);
2342f6d0d8fSOlivier Houchard 				return (-1);
2356fc729afSOlivier Houchard 			}
2366fc729afSOlivier Houchard 			*dst++ = *data++;
2376fc729afSOlivier Houchard 		}
2386fc729afSOlivier Houchard 	}
2396fc729afSOlivier Houchard 
2406fc729afSOlivier Houchard 	/* make sure the caches and memory are in sync */
241a89156f5SMichal Meloun 	icache_sync(addr, size);
2426fc729afSOlivier Houchard 
2436fc729afSOlivier Houchard 	/* In case the current page tables have been modified ... */
244a89156f5SMichal Meloun 	tlb_flush_all();
2456fc729afSOlivier Houchard 	return (0);
2466fc729afSOlivier Houchard }
2476fc729afSOlivier Houchard 
2489ebe15a1SOlivier Houchard static u_int
db_fetch_reg(int reg)2499ebe15a1SOlivier Houchard db_fetch_reg(int reg)
2509ebe15a1SOlivier Houchard {
2519ebe15a1SOlivier Houchard 
2529ebe15a1SOlivier Houchard 	switch (reg) {
2539ebe15a1SOlivier Houchard 	case 0:
2549ebe15a1SOlivier Houchard 		return (kdb_frame->tf_r0);
2559ebe15a1SOlivier Houchard 	case 1:
2569ebe15a1SOlivier Houchard 		return (kdb_frame->tf_r1);
2579ebe15a1SOlivier Houchard 	case 2:
2589ebe15a1SOlivier Houchard 		return (kdb_frame->tf_r2);
2599ebe15a1SOlivier Houchard 	case 3:
2609ebe15a1SOlivier Houchard 		return (kdb_frame->tf_r3);
2619ebe15a1SOlivier Houchard 	case 4:
2629ebe15a1SOlivier Houchard 		return (kdb_frame->tf_r4);
2639ebe15a1SOlivier Houchard 	case 5:
2649ebe15a1SOlivier Houchard 		return (kdb_frame->tf_r5);
2659ebe15a1SOlivier Houchard 	case 6:
2669ebe15a1SOlivier Houchard 		return (kdb_frame->tf_r6);
2679ebe15a1SOlivier Houchard 	case 7:
2689ebe15a1SOlivier Houchard 		return (kdb_frame->tf_r7);
2699ebe15a1SOlivier Houchard 	case 8:
2709ebe15a1SOlivier Houchard 		return (kdb_frame->tf_r8);
2719ebe15a1SOlivier Houchard 	case 9:
2729ebe15a1SOlivier Houchard 		return (kdb_frame->tf_r9);
2739ebe15a1SOlivier Houchard 	case 10:
2749ebe15a1SOlivier Houchard 		return (kdb_frame->tf_r10);
2759ebe15a1SOlivier Houchard 	case 11:
2769ebe15a1SOlivier Houchard 		return (kdb_frame->tf_r11);
2779ebe15a1SOlivier Houchard 	case 12:
2789ebe15a1SOlivier Houchard 		return (kdb_frame->tf_r12);
2799ebe15a1SOlivier Houchard 	case 13:
2809ebe15a1SOlivier Houchard 		return (kdb_frame->tf_svc_sp);
2819ebe15a1SOlivier Houchard 	case 14:
2829ebe15a1SOlivier Houchard 		return (kdb_frame->tf_svc_lr);
2839ebe15a1SOlivier Houchard 	case 15:
2849ebe15a1SOlivier Houchard 		return (kdb_frame->tf_pc);
2859ebe15a1SOlivier Houchard 	default:
2869ebe15a1SOlivier Houchard 		panic("db_fetch_reg: botch");
2879ebe15a1SOlivier Houchard 	}
2889ebe15a1SOlivier Houchard }
2899ebe15a1SOlivier Houchard 
290232e189aSZbigniew Bodek static u_int
db_branch_taken_read_int(void * cookie __unused,vm_offset_t offset,u_int * val)291232e189aSZbigniew Bodek db_branch_taken_read_int(void *cookie __unused, vm_offset_t offset, u_int *val)
292232e189aSZbigniew Bodek {
293232e189aSZbigniew Bodek 	u_int ret;
294232e189aSZbigniew Bodek 
295232e189aSZbigniew Bodek 	db_read_bytes(offset, 4, (char *)&ret);
296232e189aSZbigniew Bodek 	*val = ret;
297232e189aSZbigniew Bodek 
298232e189aSZbigniew Bodek 	return (0);
299232e189aSZbigniew Bodek }
300232e189aSZbigniew Bodek 
301232e189aSZbigniew Bodek static u_int
db_branch_taken_fetch_reg(void * cookie __unused,int reg)302232e189aSZbigniew Bodek db_branch_taken_fetch_reg(void *cookie __unused, int reg)
303232e189aSZbigniew Bodek {
304232e189aSZbigniew Bodek 
305232e189aSZbigniew Bodek 	return (db_fetch_reg(reg));
306232e189aSZbigniew Bodek }
307232e189aSZbigniew Bodek 
3089ebe15a1SOlivier Houchard u_int
branch_taken(u_int insn,db_addr_t pc)3099ebe15a1SOlivier Houchard branch_taken(u_int insn, db_addr_t pc)
3109ebe15a1SOlivier Houchard {
311232e189aSZbigniew Bodek 	register_t new_pc;
312232e189aSZbigniew Bodek 	int ret;
3139ebe15a1SOlivier Houchard 
314232e189aSZbigniew Bodek 	ret = arm_predict_branch(NULL, insn, (register_t)pc, &new_pc,
315232e189aSZbigniew Bodek 	    db_branch_taken_fetch_reg, db_branch_taken_read_int);
316f0fe5e91SOlivier Houchard 
317232e189aSZbigniew Bodek 	if (ret != 0)
318232e189aSZbigniew Bodek 		kdb_reenter();
319232e189aSZbigniew Bodek 
320232e189aSZbigniew Bodek 	return (new_pc);
3219ebe15a1SOlivier Houchard }
322