xref: /netbsd-src/sys/arch/usermode/usermode/kgdb_machdep.c (revision 5b28f239895d55856221c590945769250e289f5f)
1*5b28f239Srillig /*	$NetBSD: kgdb_machdep.c,v 1.5 2024/09/08 09:36:49 rillig Exp $	*/
2203c061eSreinoud 
3203c061eSreinoud /*
4203c061eSreinoud  * Copyright (c) 1996 Matthias Pfaller.
5203c061eSreinoud  * All rights reserved.
6203c061eSreinoud  *
7203c061eSreinoud  * Redistribution and use in source and binary forms, with or without
8203c061eSreinoud  * modification, are permitted provided that the following conditions
9203c061eSreinoud  * are met:
10203c061eSreinoud  * 1. Redistributions of source code must retain the above copyright
11203c061eSreinoud  *    notice, this list of conditions and the following disclaimer.
12203c061eSreinoud  * 2. Redistributions in binary form must reproduce the above copyright
13203c061eSreinoud  *    notice, this list of conditions and the following disclaimer in the
14203c061eSreinoud  *    documentation and/or other materials provided with the distribution.
15203c061eSreinoud  *
16203c061eSreinoud  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17203c061eSreinoud  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18203c061eSreinoud  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19203c061eSreinoud  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20203c061eSreinoud  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21203c061eSreinoud  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22203c061eSreinoud  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23203c061eSreinoud  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24203c061eSreinoud  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25203c061eSreinoud  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26203c061eSreinoud  */
27203c061eSreinoud 
28203c061eSreinoud #include <sys/cdefs.h>
29*5b28f239Srillig __KERNEL_RCSID(0, "$NetBSD: kgdb_machdep.c,v 1.5 2024/09/08 09:36:49 rillig Exp $");
30203c061eSreinoud 
31203c061eSreinoud #include "opt_ddb.h"
32203c061eSreinoud #include "opt_kgdb.h"
33203c061eSreinoud 
34203c061eSreinoud #include <sys/param.h>
35203c061eSreinoud #include <sys/systm.h>
36203c061eSreinoud #include <sys/kgdb.h>
37203c061eSreinoud #include <sys/socket.h>
38203c061eSreinoud 
39203c061eSreinoud #include <uvm/uvm_extern.h>
40203c061eSreinoud 
41203c061eSreinoud //#include <machine/frame.h>
42203c061eSreinoud #include <machine/reg.h>
43203c061eSreinoud #include <machine/trap.h>
44203c061eSreinoud #include <machine/db_machdep.h>
45203c061eSreinoud #include <machine/thunk.h>
46203c061eSreinoud #include <netinet/in.h>
47203c061eSreinoud 
48203c061eSreinoud 
49203c061eSreinoud /*
50203c061eSreinoud  * Determine if the memory at va..(va+len) is valid.
51203c061eSreinoud  */
52203c061eSreinoud int
53203c061eSreinoud kgdb_acc(vaddr_t va, size_t len)
54203c061eSreinoud {
55203c061eSreinoud 	vaddr_t last_va;
56203c061eSreinoud 
57203c061eSreinoud 	last_va = va + len;
58203c061eSreinoud 	va  &= ~PGOFSET;
59203c061eSreinoud 	last_va &= ~PGOFSET;
60203c061eSreinoud 
61517b4f49Sreinoud 	thunk_printf_debug("%s: [%p .. %p]\n", __func__,
62517b4f49Sreinoud 		(void *) va, (void *) last_va);
63203c061eSreinoud 	do {
64203c061eSreinoud 		if (db_validate_address(va))
65203c061eSreinoud 			return (0);
66203c061eSreinoud 		va  += PAGE_SIZE;
67203c061eSreinoud 	} while (va < last_va);
68203c061eSreinoud 
69203c061eSreinoud 	return (1);
70203c061eSreinoud }
71203c061eSreinoud 
72203c061eSreinoud /*
73203c061eSreinoud  * Translate a trap number into a unix compatible signal value.
74203c061eSreinoud  * (gdb only understands unix signal numbers).
75203c061eSreinoud  */
76203c061eSreinoud int
77203c061eSreinoud kgdb_signal(int type)
78203c061eSreinoud {
79203c061eSreinoud 	return type;
80203c061eSreinoud 
81203c061eSreinoud //	panic("%s", __func__);
82203c061eSreinoud #if 0
83203c061eSreinoud 	switch (type) {
84203c061eSreinoud 	case T_BREAKPOINT:
85203c061eSreinoud 		return(SIGTRAP);
86203c061eSreinoud 	case -1:
87203c061eSreinoud 		return(SIGSEGV);
88203c061eSreinoud 	default:
89203c061eSreinoud 		return(SIGINT);
90203c061eSreinoud 	}
91203c061eSreinoud #endif
92203c061eSreinoud }
93203c061eSreinoud 
94203c061eSreinoud /*
95203c061eSreinoud  * Definitions exported from gdb.
96203c061eSreinoud  */
97203c061eSreinoud 
98203c061eSreinoud /*
99203c061eSreinoud  * Translate the values stored in the kernel regs struct to the format
100203c061eSreinoud  * understood by gdb.
101203c061eSreinoud  */
102203c061eSreinoud void
103203c061eSreinoud kgdb_getregs(db_regs_t *regs, kgdb_reg_t *gdb_regs)
104203c061eSreinoud {
105203c061eSreinoud #ifdef __x86_64__
106203c061eSreinoud 	kgdb_reg_t *gregs = regs->uc_mcontext.__gregs;
107203c061eSreinoud 
108203c061eSreinoud 	gdb_regs[ 0] = gregs[_REG_RAX];
109203c061eSreinoud 	gdb_regs[ 1] = gregs[_REG_RBX];
110203c061eSreinoud 	gdb_regs[ 2] = gregs[_REG_RCX];
111203c061eSreinoud 	gdb_regs[ 3] = gregs[_REG_RDX];
112203c061eSreinoud 	gdb_regs[ 4] = gregs[_REG_RSI];
113203c061eSreinoud 	gdb_regs[ 5] = gregs[_REG_RDI];
114203c061eSreinoud 	gdb_regs[ 6] = gregs[_REG_RBP];
115203c061eSreinoud 	gdb_regs[ 7] = gregs[_REG_RSP];
116203c061eSreinoud 	gdb_regs[ 8] = gregs[_REG_R8];
117203c061eSreinoud 	gdb_regs[ 9] = gregs[_REG_R9];
118203c061eSreinoud 	gdb_regs[10] = gregs[_REG_R10];
119203c061eSreinoud 	gdb_regs[11] = gregs[_REG_R11];
120203c061eSreinoud 	gdb_regs[12] = gregs[_REG_R12];
121203c061eSreinoud 	gdb_regs[13] = gregs[_REG_R13];
122203c061eSreinoud 	gdb_regs[14] = gregs[_REG_R14];
123203c061eSreinoud 	gdb_regs[15] = gregs[_REG_R15];
124203c061eSreinoud 	gdb_regs[16] = gregs[_REG_RIP];
125203c061eSreinoud 	gdb_regs[17] = gregs[_REG_RFLAGS];
126203c061eSreinoud 	gdb_regs[18] = gregs[_REG_CS];
127203c061eSreinoud 	gdb_regs[19] = gregs[_REG_SS];
128203c061eSreinoud 
129203c061eSreinoud #elif defined(__i386)
130e4b9cc03Sreinoud 	kgdb_reg_t *gregs = regs->uc_mcontext.__gregs;
131203c061eSreinoud 
132e4b9cc03Sreinoud 	gdb_regs[ 0] = gregs[_REG_EAX];
133e4b9cc03Sreinoud 	gdb_regs[ 1] = gregs[_REG_ECX];
134e4b9cc03Sreinoud 	gdb_regs[ 2] = gregs[_REG_EDX];
135e4b9cc03Sreinoud 	gdb_regs[ 3] = gregs[_REG_EBX];
136e4b9cc03Sreinoud 	gdb_regs[ 4] = gregs[_REG_ESP];
137e4b9cc03Sreinoud 	gdb_regs[ 5] = gregs[_REG_EBP];
138e4b9cc03Sreinoud 	gdb_regs[ 6] = gregs[_REG_ESI];
139e4b9cc03Sreinoud 	gdb_regs[ 7] = gregs[_REG_EDI];
140e4b9cc03Sreinoud 	gdb_regs[ 8] = gregs[_REG_EIP];
141e4b9cc03Sreinoud 	gdb_regs[ 9] = gregs[_REG_EFL];
142e4b9cc03Sreinoud 	gdb_regs[10] = gregs[_REG_CS];
143e4b9cc03Sreinoud 	gdb_regs[11] = gregs[_REG_SS];
144e4b9cc03Sreinoud 	gdb_regs[12] = gregs[_REG_DS];
145e4b9cc03Sreinoud 	gdb_regs[13] = gregs[_REG_ES];
146e4b9cc03Sreinoud 	gdb_regs[14] = gregs[_REG_FS];
147e4b9cc03Sreinoud 	gdb_regs[15] = gregs[_REG_GS];
148e4b9cc03Sreinoud 
149203c061eSreinoud #else
150203c061eSreinoud #error port kgdb_machdep.c kgdb_getregs
151203c061eSreinoud #endif
152203c061eSreinoud }
153203c061eSreinoud 
154203c061eSreinoud  /*
155203c061eSreinoud  * And the reverse.
156203c061eSreinoud  */
157203c061eSreinoud 
158203c061eSreinoud void
159203c061eSreinoud kgdb_setregs(db_regs_t *regs, kgdb_reg_t *gdb_regs)
160203c061eSreinoud {
161203c061eSreinoud #ifdef __x86_64__
162203c061eSreinoud 	kgdb_reg_t *gregs = regs->uc_mcontext.__gregs;
163203c061eSreinoud 
164203c061eSreinoud 	gregs[_REG_RAX] = gdb_regs[ 0];
165203c061eSreinoud 	gregs[_REG_RBX] = gdb_regs[ 1];
166203c061eSreinoud 	gregs[_REG_RCX] = gdb_regs[ 2];
167203c061eSreinoud 	gregs[_REG_RDX] = gdb_regs[ 3];
168203c061eSreinoud 	gregs[_REG_RSI] = gdb_regs[ 4];
169203c061eSreinoud 	gregs[_REG_RDI] = gdb_regs[ 5];
170203c061eSreinoud 	gregs[_REG_RBP] = gdb_regs[ 6];
171203c061eSreinoud 	gregs[_REG_RSP] = gdb_regs[ 7];
172203c061eSreinoud 	gregs[_REG_R8 ] = gdb_regs[ 8];
173203c061eSreinoud 	gregs[_REG_R9 ] = gdb_regs[ 9];
174203c061eSreinoud 	gregs[_REG_R10] = gdb_regs[10];
175203c061eSreinoud 	gregs[_REG_R11] = gdb_regs[11];
176203c061eSreinoud 	gregs[_REG_R12] = gdb_regs[12];
177203c061eSreinoud 	gregs[_REG_R13] = gdb_regs[13];
178203c061eSreinoud 	gregs[_REG_R14] = gdb_regs[14];
179203c061eSreinoud 	gregs[_REG_R15] = gdb_regs[15];
180203c061eSreinoud 	gregs[_REG_RIP] = gdb_regs[16];
181203c061eSreinoud 	gregs[_REG_RFLAGS] = gdb_regs[17];
182203c061eSreinoud 	gregs[_REG_CS ] = gdb_regs[18];
183203c061eSreinoud 	gregs[_REG_SS ] = gdb_regs[19];
184203c061eSreinoud #elif defined(__i386)
185203c061eSreinoud panic("%s", __func__);
186e4b9cc03Sreinoud 	kgdb_reg_t *gregs = regs->uc_mcontext.__gregs;
187203c061eSreinoud 
188e4b9cc03Sreinoud 	gregs[_REG_EAX] = gdb_regs[ 0];
189e4b9cc03Sreinoud 	gregs[_REG_ECX] = gdb_regs[ 1];
190e4b9cc03Sreinoud 	gregs[_REG_EDX] = gdb_regs[ 2];
191e4b9cc03Sreinoud 	gregs[_REG_EBX] = gdb_regs[ 3];
192e4b9cc03Sreinoud 	gregs[_REG_EBP] = gdb_regs[ 5];
193e4b9cc03Sreinoud 	gregs[_REG_ESI] = gdb_regs[ 6];
194e4b9cc03Sreinoud 	gregs[_REG_EDI] = gdb_regs[ 7];
195e4b9cc03Sreinoud 	gregs[_REG_EIP] = gdb_regs[ 8];
196e4b9cc03Sreinoud 	gregs[_REG_EFL] = gdb_regs[ 9];
197e4b9cc03Sreinoud 	gregs[_REG_CS]  = gdb_regs[10];
198e4b9cc03Sreinoud 	gregs[_REG_DS]  = gdb_regs[12];
199e4b9cc03Sreinoud 	gregs[_REG_ES]  = gdb_regs[13];
200e4b9cc03Sreinoud 
201203c061eSreinoud #else
202203c061eSreinoud panic("%s", __func__);
203203c061eSreinoud #endif
204203c061eSreinoud }
205203c061eSreinoud 
206203c061eSreinoud /*
207203c061eSreinoud  * Trap into kgdb to wait for debugger to connect,
208203c061eSreinoud  * noting on the console why nothing else is going on.
209203c061eSreinoud  */
210203c061eSreinoud void
211203c061eSreinoud kgdb_connect(int verbose)
212203c061eSreinoud {
213203c061eSreinoud 	if (kgdb_dev == NODEV)
214203c061eSreinoud 		return;
215203c061eSreinoud 
216203c061eSreinoud 	if (verbose)
217203c061eSreinoud 		printf("kgdb waiting...");
218203c061eSreinoud 
219203c061eSreinoud 	breakpoint();
220203c061eSreinoud 
221203c061eSreinoud 	if (verbose)
222203c061eSreinoud 		printf("connected.\n");
223203c061eSreinoud 
224203c061eSreinoud 	kgdb_debug_panic = 1;
225203c061eSreinoud }
226203c061eSreinoud 
227203c061eSreinoud /*
228203c061eSreinoud  * Decide what to do on panic.
229203c061eSreinoud  * (This is called by panic, like Debugger())
230203c061eSreinoud  */
231203c061eSreinoud void
232203c061eSreinoud kgdb_panic(void)
233203c061eSreinoud {
234203c061eSreinoud 	if (kgdb_dev != NODEV && kgdb_debug_panic) {
235203c061eSreinoud 		printf("entering kgdb\n");
236203c061eSreinoud 		kgdb_connect(kgdb_active == 0);
237203c061eSreinoud 	}
238203c061eSreinoud }
239203c061eSreinoud 
240203c061eSreinoud static int kgdb_socket, kgdb_fd;
241203c061eSreinoud static int kgdb_connected;
242203c061eSreinoud 
243203c061eSreinoud 
244203c061eSreinoud static void
245203c061eSreinoud kgdb_get_connection(void)
246203c061eSreinoud {
247203c061eSreinoud 	while (!kgdb_connected) {
248203c061eSreinoud 		thunk_printf("...[kgdb connecting]...");
249203c061eSreinoud 		kgdb_fd = thunk_gdb_accept(kgdb_socket);
250203c061eSreinoud 		if (kgdb_fd)
251203c061eSreinoud 			kgdb_connected = 1;
252203c061eSreinoud 	}
253203c061eSreinoud 	kgdb_active = 1;
254203c061eSreinoud }
255203c061eSreinoud 
256203c061eSreinoud static int
257203c061eSreinoud kgdb_getc(void *arg)
258203c061eSreinoud {
259203c061eSreinoud 	char ch;
260203c061eSreinoud 
261203c061eSreinoud 	while (thunk_kgdb_getc(kgdb_fd, &ch) < 0) {
262203c061eSreinoud 		kgdb_connected = 0;
263203c061eSreinoud 		kgdb_get_connection();
264203c061eSreinoud 	}
265203c061eSreinoud //thunk_printf("[<%c]", ch);
266203c061eSreinoud 	return (int) ch;
267203c061eSreinoud }
268203c061eSreinoud 
269203c061eSreinoud 
270203c061eSreinoud static void
271203c061eSreinoud kgdb_putc(void *arg, int ch_in)
272203c061eSreinoud {
273203c061eSreinoud 	char ch = (char) ch_in;
274203c061eSreinoud 	while (thunk_kgdb_putc(kgdb_fd, ch) < 0) {
275203c061eSreinoud 		kgdb_connected = 0;
276203c061eSreinoud 		kgdb_get_connection();
277203c061eSreinoud 	}
278203c061eSreinoud //thunk_printf("[>%c]", ch);
279203c061eSreinoud }
280203c061eSreinoud 
281203c061eSreinoud void
282203c061eSreinoud kgdb_port_init(void)
283203c061eSreinoud {
284203c061eSreinoud 	kgdb_connected = 0;
285203c061eSreinoud 
286203c061eSreinoud 	/* open our socket */
287203c061eSreinoud 	kgdb_socket = thunk_gdb_open();
288203c061eSreinoud 	if (kgdb_socket == 0) {
289203c061eSreinoud 		kgdb_dev = 0;
290203c061eSreinoud 		printf("aborting kgdb\n");
291203c061eSreinoud 		return;
292203c061eSreinoud 	}
293203c061eSreinoud 
294203c061eSreinoud 	/* signal we have a connection `dev' */
295203c061eSreinoud 	kgdb_dev = 0x123;
296203c061eSreinoud 	kgdb_attach(kgdb_getc, kgdb_putc, 0);
297203c061eSreinoud }
298203c061eSreinoud 
299203c061eSreinoud /*
300*5b28f239Srillig  * handle a trap instruction encountered from KGDB
301203c061eSreinoud  */
302203c061eSreinoud void
303203c061eSreinoud kgdb_kernel_trap(int signo, vaddr_t pc, vaddr_t va, ucontext_t *ucp)
304203c061eSreinoud {
305203c061eSreinoud 	kgdb_get_connection();
306203c061eSreinoud 
307203c061eSreinoud thunk_printf("entering trap\n");
308203c061eSreinoud thunk_printf("  signo %d, pc %p, va %p\n", signo, (void *) pc, (void *) va);
309203c061eSreinoud 	kgdb_trap(signo, ucp);
310203c061eSreinoud }
311203c061eSreinoud 
312