xref: /netbsd-src/sys/arch/usermode/usermode/kgdb_machdep.c (revision 5b28f239895d55856221c590945769250e289f5f)
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