Home | History | Annotate | Line # | Download | only in usermode
      1 /*	$NetBSD: kgdb_machdep.c,v 1.5 2024/09/08 09:36:49 rillig 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.5 2024/09/08 09:36:49 rillig 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 #include <sys/socket.h>
     38 
     39 #include <uvm/uvm_extern.h>
     40 
     41 //#include <machine/frame.h>
     42 #include <machine/reg.h>
     43 #include <machine/trap.h>
     44 #include <machine/db_machdep.h>
     45 #include <machine/thunk.h>
     46 #include <netinet/in.h>
     47 
     48 
     49 /*
     50  * Determine if the memory at va..(va+len) is valid.
     51  */
     52 int
     53 kgdb_acc(vaddr_t va, size_t len)
     54 {
     55 	vaddr_t last_va;
     56 
     57 	last_va = va + len;
     58 	va  &= ~PGOFSET;
     59 	last_va &= ~PGOFSET;
     60 
     61 	thunk_printf_debug("%s: [%p .. %p]\n", __func__,
     62 		(void *) va, (void *) last_va);
     63 	do {
     64 		if (db_validate_address(va))
     65 			return (0);
     66 		va  += PAGE_SIZE;
     67 	} while (va < last_va);
     68 
     69 	return (1);
     70 }
     71 
     72 /*
     73  * Translate a trap number into a unix compatible signal value.
     74  * (gdb only understands unix signal numbers).
     75  */
     76 int
     77 kgdb_signal(int type)
     78 {
     79 	return type;
     80 
     81 //	panic("%s", __func__);
     82 #if 0
     83 	switch (type) {
     84 	case T_BREAKPOINT:
     85 		return(SIGTRAP);
     86 	case -1:
     87 		return(SIGSEGV);
     88 	default:
     89 		return(SIGINT);
     90 	}
     91 #endif
     92 }
     93 
     94 /*
     95  * Definitions exported from gdb.
     96  */
     97 
     98 /*
     99  * Translate the values stored in the kernel regs struct to the format
    100  * understood by gdb.
    101  */
    102 void
    103 kgdb_getregs(db_regs_t *regs, kgdb_reg_t *gdb_regs)
    104 {
    105 #ifdef __x86_64__
    106 	kgdb_reg_t *gregs = regs->uc_mcontext.__gregs;
    107 
    108 	gdb_regs[ 0] = gregs[_REG_RAX];
    109 	gdb_regs[ 1] = gregs[_REG_RBX];
    110 	gdb_regs[ 2] = gregs[_REG_RCX];
    111 	gdb_regs[ 3] = gregs[_REG_RDX];
    112 	gdb_regs[ 4] = gregs[_REG_RSI];
    113 	gdb_regs[ 5] = gregs[_REG_RDI];
    114 	gdb_regs[ 6] = gregs[_REG_RBP];
    115 	gdb_regs[ 7] = gregs[_REG_RSP];
    116 	gdb_regs[ 8] = gregs[_REG_R8];
    117 	gdb_regs[ 9] = gregs[_REG_R9];
    118 	gdb_regs[10] = gregs[_REG_R10];
    119 	gdb_regs[11] = gregs[_REG_R11];
    120 	gdb_regs[12] = gregs[_REG_R12];
    121 	gdb_regs[13] = gregs[_REG_R13];
    122 	gdb_regs[14] = gregs[_REG_R14];
    123 	gdb_regs[15] = gregs[_REG_R15];
    124 	gdb_regs[16] = gregs[_REG_RIP];
    125 	gdb_regs[17] = gregs[_REG_RFLAGS];
    126 	gdb_regs[18] = gregs[_REG_CS];
    127 	gdb_regs[19] = gregs[_REG_SS];
    128 
    129 #elif defined(__i386)
    130 	kgdb_reg_t *gregs = regs->uc_mcontext.__gregs;
    131 
    132 	gdb_regs[ 0] = gregs[_REG_EAX];
    133 	gdb_regs[ 1] = gregs[_REG_ECX];
    134 	gdb_regs[ 2] = gregs[_REG_EDX];
    135 	gdb_regs[ 3] = gregs[_REG_EBX];
    136 	gdb_regs[ 4] = gregs[_REG_ESP];
    137 	gdb_regs[ 5] = gregs[_REG_EBP];
    138 	gdb_regs[ 6] = gregs[_REG_ESI];
    139 	gdb_regs[ 7] = gregs[_REG_EDI];
    140 	gdb_regs[ 8] = gregs[_REG_EIP];
    141 	gdb_regs[ 9] = gregs[_REG_EFL];
    142 	gdb_regs[10] = gregs[_REG_CS];
    143 	gdb_regs[11] = gregs[_REG_SS];
    144 	gdb_regs[12] = gregs[_REG_DS];
    145 	gdb_regs[13] = gregs[_REG_ES];
    146 	gdb_regs[14] = gregs[_REG_FS];
    147 	gdb_regs[15] = gregs[_REG_GS];
    148 
    149 #else
    150 #error port kgdb_machdep.c kgdb_getregs
    151 #endif
    152 }
    153 
    154  /*
    155  * And the reverse.
    156  */
    157 
    158 void
    159 kgdb_setregs(db_regs_t *regs, kgdb_reg_t *gdb_regs)
    160 {
    161 #ifdef __x86_64__
    162 	kgdb_reg_t *gregs = regs->uc_mcontext.__gregs;
    163 
    164 	gregs[_REG_RAX] = gdb_regs[ 0];
    165 	gregs[_REG_RBX] = gdb_regs[ 1];
    166 	gregs[_REG_RCX] = gdb_regs[ 2];
    167 	gregs[_REG_RDX] = gdb_regs[ 3];
    168 	gregs[_REG_RSI] = gdb_regs[ 4];
    169 	gregs[_REG_RDI] = gdb_regs[ 5];
    170 	gregs[_REG_RBP] = gdb_regs[ 6];
    171 	gregs[_REG_RSP] = gdb_regs[ 7];
    172 	gregs[_REG_R8 ] = gdb_regs[ 8];
    173 	gregs[_REG_R9 ] = gdb_regs[ 9];
    174 	gregs[_REG_R10] = gdb_regs[10];
    175 	gregs[_REG_R11] = gdb_regs[11];
    176 	gregs[_REG_R12] = gdb_regs[12];
    177 	gregs[_REG_R13] = gdb_regs[13];
    178 	gregs[_REG_R14] = gdb_regs[14];
    179 	gregs[_REG_R15] = gdb_regs[15];
    180 	gregs[_REG_RIP] = gdb_regs[16];
    181 	gregs[_REG_RFLAGS] = gdb_regs[17];
    182 	gregs[_REG_CS ] = gdb_regs[18];
    183 	gregs[_REG_SS ] = gdb_regs[19];
    184 #elif defined(__i386)
    185 panic("%s", __func__);
    186 	kgdb_reg_t *gregs = regs->uc_mcontext.__gregs;
    187 
    188 	gregs[_REG_EAX] = gdb_regs[ 0];
    189 	gregs[_REG_ECX] = gdb_regs[ 1];
    190 	gregs[_REG_EDX] = gdb_regs[ 2];
    191 	gregs[_REG_EBX] = gdb_regs[ 3];
    192 	gregs[_REG_EBP] = gdb_regs[ 5];
    193 	gregs[_REG_ESI] = gdb_regs[ 6];
    194 	gregs[_REG_EDI] = gdb_regs[ 7];
    195 	gregs[_REG_EIP] = gdb_regs[ 8];
    196 	gregs[_REG_EFL] = gdb_regs[ 9];
    197 	gregs[_REG_CS]  = gdb_regs[10];
    198 	gregs[_REG_DS]  = gdb_regs[12];
    199 	gregs[_REG_ES]  = gdb_regs[13];
    200 
    201 #else
    202 panic("%s", __func__);
    203 #endif
    204 }
    205 
    206 /*
    207  * Trap into kgdb to wait for debugger to connect,
    208  * noting on the console why nothing else is going on.
    209  */
    210 void
    211 kgdb_connect(int verbose)
    212 {
    213 	if (kgdb_dev == NODEV)
    214 		return;
    215 
    216 	if (verbose)
    217 		printf("kgdb waiting...");
    218 
    219 	breakpoint();
    220 
    221 	if (verbose)
    222 		printf("connected.\n");
    223 
    224 	kgdb_debug_panic = 1;
    225 }
    226 
    227 /*
    228  * Decide what to do on panic.
    229  * (This is called by panic, like Debugger())
    230  */
    231 void
    232 kgdb_panic(void)
    233 {
    234 	if (kgdb_dev != NODEV && kgdb_debug_panic) {
    235 		printf("entering kgdb\n");
    236 		kgdb_connect(kgdb_active == 0);
    237 	}
    238 }
    239 
    240 static int kgdb_socket, kgdb_fd;
    241 static int kgdb_connected;
    242 
    243 
    244 static void
    245 kgdb_get_connection(void)
    246 {
    247 	while (!kgdb_connected) {
    248 		thunk_printf("...[kgdb connecting]...");
    249 		kgdb_fd = thunk_gdb_accept(kgdb_socket);
    250 		if (kgdb_fd)
    251 			kgdb_connected = 1;
    252 	}
    253 	kgdb_active = 1;
    254 }
    255 
    256 static int
    257 kgdb_getc(void *arg)
    258 {
    259 	char ch;
    260 
    261 	while (thunk_kgdb_getc(kgdb_fd, &ch) < 0) {
    262 		kgdb_connected = 0;
    263 		kgdb_get_connection();
    264 	}
    265 //thunk_printf("[<%c]", ch);
    266 	return (int) ch;
    267 }
    268 
    269 
    270 static void
    271 kgdb_putc(void *arg, int ch_in)
    272 {
    273 	char ch = (char) ch_in;
    274 	while (thunk_kgdb_putc(kgdb_fd, ch) < 0) {
    275 		kgdb_connected = 0;
    276 		kgdb_get_connection();
    277 	}
    278 //thunk_printf("[>%c]", ch);
    279 }
    280 
    281 void
    282 kgdb_port_init(void)
    283 {
    284 	kgdb_connected = 0;
    285 
    286 	/* open our socket */
    287 	kgdb_socket = thunk_gdb_open();
    288 	if (kgdb_socket == 0) {
    289 		kgdb_dev = 0;
    290 		printf("aborting kgdb\n");
    291 		return;
    292 	}
    293 
    294 	/* signal we have a connection `dev' */
    295 	kgdb_dev = 0x123;
    296 	kgdb_attach(kgdb_getc, kgdb_putc, 0);
    297 }
    298 
    299 /*
    300  * handle a trap instruction encountered from KGDB
    301  */
    302 void
    303 kgdb_kernel_trap(int signo, vaddr_t pc, vaddr_t va, ucontext_t *ucp)
    304 {
    305 	kgdb_get_connection();
    306 
    307 thunk_printf("entering trap\n");
    308 thunk_printf("  signo %d, pc %p, va %p\n", signo, (void *) pc, (void *) va);
    309 	kgdb_trap(signo, ucp);
    310 }
    311 
    312