1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2004 Marcel Moolenaar
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 *
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/kdb.h>
35#include <sys/kernel.h>
36#include <sys/pcpu.h>
37#include <sys/proc.h>
38#include <sys/reboot.h>
39
40#include <machine/gdb_machdep.h>
41#include <machine/kdb.h>
42
43#include <gdb/gdb.h>
44#include <gdb/gdb_int.h>
45
46static dbbe_init_f gdb_init;
47static dbbe_trap_f gdb_trap;
48
49KDB_BACKEND(gdb, gdb_init, NULL, NULL, gdb_trap);
50
51static struct gdb_dbgport null_gdb_dbgport;
52DATA_SET(gdb_dbgport_set, null_gdb_dbgport);
53SET_DECLARE(gdb_dbgport_set, struct gdb_dbgport);
54
55struct gdb_dbgport *gdb_cur = NULL;
56int gdb_listening = 0;
57
58static unsigned char gdb_bindata[64];
59
60static int
61gdb_init(void)
62{
63	struct gdb_dbgport *dp, **iter;
64	int cur_pri, pri;
65
66	gdb_cur = NULL;
67	cur_pri = -1;
68	SET_FOREACH(iter, gdb_dbgport_set) {
69		dp = *iter;
70		pri = (dp->gdb_probe != NULL) ? dp->gdb_probe() : -1;
71		dp->gdb_active = (pri >= 0) ? 0 : -1;
72		if (pri > cur_pri) {
73			cur_pri = pri;
74			gdb_cur = dp;
75		}
76	}
77	if (gdb_cur != NULL) {
78		printf("GDB: debug ports:");
79		SET_FOREACH(iter, gdb_dbgport_set) {
80			dp = *iter;
81			if (dp->gdb_active == 0)
82				printf(" %s", dp->gdb_name);
83		}
84		printf("\n");
85	} else
86		printf("GDB: no debug ports present\n");
87	if (gdb_cur != NULL) {
88		gdb_cur->gdb_init();
89		printf("GDB: current port: %s\n", gdb_cur->gdb_name);
90	}
91	if (gdb_cur != NULL) {
92		cur_pri = (boothowto & RB_GDB) ? 2 : 0;
93		gdb_consinit();
94	} else
95		cur_pri = -1;
96	return (cur_pri);
97}
98
99static void
100gdb_do_mem_search(void)
101{
102	size_t patlen;
103	intmax_t addr, size;
104	const unsigned char *found;
105
106	if (gdb_rx_varhex(&addr) || gdb_rx_char() != ';' ||
107	    gdb_rx_varhex(&size) || gdb_rx_char() != ';' ||
108	    gdb_rx_bindata(gdb_bindata, sizeof(gdb_bindata), &patlen)) {
109		gdb_tx_err(EINVAL);
110		return;
111	}
112	if (gdb_search_mem((char *)(uintptr_t)addr, size, gdb_bindata,
113	    patlen, &found)) {
114		if (found == 0ULL)
115			gdb_tx_begin('0');
116		else {
117			gdb_tx_begin('1');
118			gdb_tx_char(',');
119			gdb_tx_hex((intmax_t)(uintptr_t)found, 8);
120		}
121		gdb_tx_end();
122	} else
123		gdb_tx_err(EIO);
124}
125
126static int
127gdb_trap(int type, int code)
128{
129	jmp_buf jb;
130	struct thread *thr_iter;
131	void *prev_jb;
132
133	prev_jb = kdb_jmpbuf(jb);
134	if (setjmp(jb) != 0) {
135		printf("%s bailing, hopefully back to ddb!\n", __func__);
136		gdb_listening = 0;
137		(void)kdb_jmpbuf(prev_jb);
138		return (1);
139	}
140
141	gdb_listening = 0;
142	/*
143	 * Send a T packet. We currently do not support watchpoints (the
144	 * awatch, rwatch or watch elements).
145	 */
146	gdb_tx_begin('T');
147	gdb_tx_hex(gdb_cpu_signal(type, code), 2);
148	gdb_tx_varhex(GDB_REG_PC);
149	gdb_tx_char(':');
150	gdb_tx_reg(GDB_REG_PC);
151	gdb_tx_char(';');
152	gdb_tx_str("thread:");
153	gdb_tx_varhex((long)kdb_thread->td_tid);
154	gdb_tx_char(';');
155	gdb_tx_end();			/* XXX check error condition. */
156
157	thr_iter = NULL;
158	while (gdb_rx_begin() == 0) {
159		/* printf("GDB: got '%s'\n", gdb_rxp); */
160		switch (gdb_rx_char()) {
161		case '?':	/* Last signal. */
162			gdb_tx_begin('S');
163			gdb_tx_hex(gdb_cpu_signal(type, code), 2);
164			gdb_tx_end();
165			break;
166		case 'c': {	/* Continue. */
167			uintmax_t addr;
168			register_t pc;
169			if (!gdb_rx_varhex(&addr)) {
170				pc = addr;
171				gdb_cpu_setreg(GDB_REG_PC, &pc);
172			}
173			kdb_cpu_clear_singlestep();
174			gdb_listening = 1;
175			return (1);
176		}
177		case 'C': {	/* Continue with signal. */
178			uintmax_t addr, sig;
179			register_t pc;
180			if (!gdb_rx_varhex(&sig) && gdb_rx_char() == ';' &&
181			    !gdb_rx_varhex(&addr)) {
182				pc = addr;
183				gdb_cpu_setreg(GDB_REG_PC, &pc);
184			}
185			kdb_cpu_clear_singlestep();
186			gdb_listening = 1;
187			return (1);
188		}
189		case 'D': {     /* Detach */
190			gdb_tx_ok();
191			kdb_cpu_clear_singlestep();
192			return (1);
193		}
194		case 'g': {	/* Read registers. */
195			size_t r;
196			gdb_tx_begin(0);
197			for (r = 0; r < GDB_NREGS; r++)
198				gdb_tx_reg(r);
199			gdb_tx_end();
200			break;
201		}
202		case 'G': {	/* Write registers. */
203			char *val;
204			bool success;
205			size_t r;
206			for (success = true, r = 0; r < GDB_NREGS; r++) {
207				val = gdb_rxp;
208				if (!gdb_rx_mem(val, gdb_cpu_regsz(r))) {
209					gdb_tx_err(EINVAL);
210					success = false;
211					break;
212				}
213				gdb_cpu_setreg(r, val);
214			}
215			if (success)
216				gdb_tx_ok();
217			break;
218		}
219		case 'H': {	/* Set thread. */
220			intmax_t tid;
221			struct thread *thr;
222			gdb_rx_char();
223			if (gdb_rx_varhex(&tid)) {
224				gdb_tx_err(EINVAL);
225				break;
226			}
227			if (tid > 0) {
228				thr = kdb_thr_lookup(tid);
229				if (thr == NULL) {
230					gdb_tx_err(ENOENT);
231					break;
232				}
233				kdb_thr_select(thr);
234			}
235			gdb_tx_ok();
236			break;
237		}
238		case 'k':	/* Kill request. */
239			kdb_cpu_clear_singlestep();
240			gdb_listening = 1;
241			return (1);
242		case 'm': {	/* Read memory. */
243			uintmax_t addr, size;
244			if (gdb_rx_varhex(&addr) || gdb_rx_char() != ',' ||
245			    gdb_rx_varhex(&size)) {
246				gdb_tx_err(EINVAL);
247				break;
248			}
249			gdb_tx_begin(0);
250			if (gdb_tx_mem((char *)(uintptr_t)addr, size))
251				gdb_tx_end();
252			else
253				gdb_tx_err(EIO);
254			break;
255		}
256		case 'M': {	/* Write memory. */
257			uintmax_t addr, size;
258			if (gdb_rx_varhex(&addr) || gdb_rx_char() != ',' ||
259			    gdb_rx_varhex(&size) || gdb_rx_char() != ':') {
260				gdb_tx_err(EINVAL);
261				break;
262			}
263			if (gdb_rx_mem((char *)(uintptr_t)addr, size) == 0)
264				gdb_tx_err(EIO);
265			else
266				gdb_tx_ok();
267			break;
268		}
269		case 'p': {     /* Read register. */
270			uintmax_t reg;
271			if (gdb_rx_varhex(&reg)) {
272				gdb_tx_err(EINVAL);
273				break;
274			}
275			gdb_tx_begin(0);
276			gdb_tx_reg(reg);
277			gdb_tx_end();
278			break;
279		}
280		case 'P': {	/* Write register. */
281			char *val;
282			uintmax_t reg;
283			val = gdb_rxp;
284			if (gdb_rx_varhex(&reg) || gdb_rx_char() != '=' ||
285			    !gdb_rx_mem(val, gdb_cpu_regsz(reg))) {
286				gdb_tx_err(EINVAL);
287				break;
288			}
289			gdb_cpu_setreg(reg, val);
290			gdb_tx_ok();
291			break;
292		}
293		case 'q':	/* General query. */
294			if (gdb_rx_equal("fThreadInfo")) {
295				thr_iter = kdb_thr_first();
296				gdb_tx_begin('m');
297				gdb_tx_hex((long)thr_iter->td_tid, 8);
298				gdb_tx_end();
299			} else if (gdb_rx_equal("sThreadInfo")) {
300				if (thr_iter == NULL) {
301					gdb_tx_err(ENXIO);
302					break;
303				}
304				thr_iter = kdb_thr_next(thr_iter);
305				if (thr_iter != NULL) {
306					gdb_tx_begin('m');
307					gdb_tx_hex((long)thr_iter->td_tid, 8);
308					gdb_tx_end();
309				} else {
310					gdb_tx_begin('l');
311					gdb_tx_end();
312				}
313			} else if (gdb_rx_equal("Search:memory:")) {
314				gdb_do_mem_search();
315			} else if (!gdb_cpu_query())
316				gdb_tx_empty();
317			break;
318		case 's': {	/* Step. */
319			uintmax_t addr;
320			register_t pc;
321			if (!gdb_rx_varhex(&addr)) {
322				pc = addr;
323				gdb_cpu_setreg(GDB_REG_PC, &pc);
324			}
325			kdb_cpu_set_singlestep();
326			gdb_listening = 1;
327			return (1);
328		}
329		case 'S': {	/* Step with signal. */
330			uintmax_t addr, sig;
331			register_t pc;
332			if (!gdb_rx_varhex(&sig) && gdb_rx_char() == ';' &&
333			    !gdb_rx_varhex(&addr)) {
334				pc = addr;
335				gdb_cpu_setreg(GDB_REG_PC, &pc);
336			}
337			kdb_cpu_set_singlestep();
338			gdb_listening = 1;
339			return (1);
340		}
341		case 'T': {	/* Thread alive. */
342			intmax_t tid;
343			if (gdb_rx_varhex(&tid)) {
344				gdb_tx_err(EINVAL);
345				break;
346			}
347			if (kdb_thr_lookup(tid) != NULL)
348				gdb_tx_ok();
349			else
350				gdb_tx_err(ENOENT);
351			break;
352		}
353		case -1:
354			/* Empty command. Treat as unknown command. */
355			/* FALLTHROUGH */
356		default:
357			/* Unknown command. Send empty response. */
358			gdb_tx_empty();
359			break;
360		}
361	}
362	(void)kdb_jmpbuf(prev_jb);
363	return (0);
364}
365