1 /* $NetBSD: kgdb_machdep.c,v 1.7 2009/10/18 18:14:00 snj Exp $ */ 2 3 /* 4 * Copyright (c) 1996 Matthias Pfaller. 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 BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: kgdb_machdep.c,v 1.7 2009/10/18 18:14:00 snj Exp $"); 30 31 #include "opt_ddb.h" 32 #include "opt_kgdb.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kgdb.h> 37 38 #include <uvm/uvm_extern.h> 39 40 #include <machine/frame.h> 41 #include <machine/reg.h> 42 #include <machine/trap.h> 43 44 /* 45 * Determine if the memory at va..(va+len) is valid. 46 */ 47 int 48 kgdb_acc(vaddr_t va, size_t len) 49 { 50 vaddr_t last_va; 51 52 last_va = va + len; 53 va &= ~PGOFSET; 54 last_va &= ~PGOFSET; 55 56 do { 57 if (db_validate_address(va)) 58 return (0); 59 va += PAGE_SIZE; 60 } while (va < last_va); 61 62 return (1); 63 } 64 65 /* 66 * Translate a trap number into a unix compatible signal value. 67 * (gdb only understands unix signal numbers). 68 */ 69 int 70 kgdb_signal(int type) 71 { 72 73 switch (type) { 74 case T_BREAKPOINT: 75 return(SIGTRAP); 76 case -1: 77 return(SIGSEGV); 78 default: 79 return(SIGINT); 80 } 81 } 82 83 /* 84 * Definitions exported from gdb. 85 */ 86 87 /* 88 * Translate the values stored in the kernel regs struct to the format 89 * understood by gdb. 90 */ 91 void 92 kgdb_getregs(db_regs_t *regs, kgdb_reg_t *gdb_regs) 93 { 94 95 gdb_regs[KGDB_REGNUM_R0 + 0] = regs->tf_r0; 96 gdb_regs[KGDB_REGNUM_R0 + 1] = regs->tf_r1; 97 gdb_regs[KGDB_REGNUM_R0 + 2] = regs->tf_r2; 98 gdb_regs[KGDB_REGNUM_R0 + 3] = regs->tf_r3; 99 gdb_regs[KGDB_REGNUM_R0 + 4] = regs->tf_r4; 100 gdb_regs[KGDB_REGNUM_R0 + 5] = regs->tf_r5; 101 gdb_regs[KGDB_REGNUM_R0 + 6] = regs->tf_r6; 102 gdb_regs[KGDB_REGNUM_R0 + 7] = regs->tf_r7; 103 gdb_regs[KGDB_REGNUM_R0 + 8] = regs->tf_r8; 104 gdb_regs[KGDB_REGNUM_R0 + 9] = regs->tf_r9; 105 gdb_regs[KGDB_REGNUM_R0 + 10] = regs->tf_r10; 106 gdb_regs[KGDB_REGNUM_R0 + 11] = regs->tf_r11; 107 gdb_regs[KGDB_REGNUM_R0 + 12] = regs->tf_r12; 108 gdb_regs[KGDB_REGNUM_R0 + 13] = regs->tf_svc_sp; 109 gdb_regs[KGDB_REGNUM_R0 + 14] = regs->tf_svc_lr; 110 gdb_regs[KGDB_REGNUM_R0 + 15] = regs->tf_pc; 111 112 gdb_regs[KGDB_REGNUM_SPSR] = regs->tf_spsr; 113 } 114 115 /* 116 * Reverse the above. 117 */ 118 void 119 kgdb_setregs(db_regs_t *regs, kgdb_reg_t *gdb_regs) 120 { 121 regs->tf_r0 = gdb_regs[KGDB_REGNUM_R0 + 0]; 122 regs->tf_r1 = gdb_regs[KGDB_REGNUM_R0 + 1]; 123 regs->tf_r2 = gdb_regs[KGDB_REGNUM_R0 + 2]; 124 regs->tf_r3 = gdb_regs[KGDB_REGNUM_R0 + 3]; 125 regs->tf_r4 = gdb_regs[KGDB_REGNUM_R0 + 4]; 126 regs->tf_r5 = gdb_regs[KGDB_REGNUM_R0 + 5]; 127 regs->tf_r6 = gdb_regs[KGDB_REGNUM_R0 + 6]; 128 regs->tf_r7 = gdb_regs[KGDB_REGNUM_R0 + 7]; 129 regs->tf_r8 = gdb_regs[KGDB_REGNUM_R0 + 8]; 130 regs->tf_r9 = gdb_regs[KGDB_REGNUM_R0 + 9]; 131 regs->tf_r10 = gdb_regs[KGDB_REGNUM_R0 + 10]; 132 regs->tf_r11 = gdb_regs[KGDB_REGNUM_R0 + 11]; 133 regs->tf_r12 = gdb_regs[KGDB_REGNUM_R0 + 12]; 134 regs->tf_svc_sp = gdb_regs[KGDB_REGNUM_R0 + 13]; 135 regs->tf_svc_lr = gdb_regs[KGDB_REGNUM_R0 + 14]; 136 regs->tf_pc = gdb_regs[KGDB_REGNUM_R0 + 15]; 137 138 regs->tf_spsr = gdb_regs[KGDB_REGNUM_SPSR]; 139 } 140 141 /* 142 * Trap into kgdb to wait for debugger to connect, 143 * noting on the console why nothing else is going on. 144 */ 145 void 146 kgdb_connect(int verbose) 147 { 148 149 if (kgdb_dev == NODEV) 150 return; 151 152 if (verbose) 153 printf("kgdb waiting..."); 154 155 __asm volatile(KBPT_ASM); 156 157 if (verbose) 158 printf("connected.\n"); 159 160 kgdb_debug_panic = 1; 161 } 162 163 /* 164 * Decide what to do on panic. 165 * (This is called by panic, like Debugger()) 166 */ 167 void 168 kgdb_panic(void) 169 { 170 171 if (kgdb_dev != NODEV && kgdb_debug_panic) { 172 printf("entering kgdb\n"); 173 kgdb_connect(kgdb_active == 0); 174 } 175 } 176