gdb_main.c revision 158949
1208099Sdelphij/*-
2208099Sdelphij * Copyright (c) 2004 Marcel Moolenaar
3208099Sdelphij * All rights reserved.
4208099Sdelphij *
5208099Sdelphij * Redistribution and use in source and binary forms, with or without
6208099Sdelphij * modification, are permitted provided that the following conditions
7208099Sdelphij * are met:
8208099Sdelphij *
9208099Sdelphij * 1. Redistributions of source code must retain the above copyright
10208099Sdelphij *    notice, this list of conditions and the following disclaimer.
11208099Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
12208099Sdelphij *    notice, this list of conditions and the following disclaimer in the
13208099Sdelphij *    documentation and/or other materials provided with the distribution.
14208099Sdelphij *
15208099Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16208099Sdelphij * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17208099Sdelphij * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18208099Sdelphij * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19208099Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20208099Sdelphij * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21208099Sdelphij * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22208099Sdelphij * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23208099Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24208099Sdelphij * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25208099Sdelphij */
26208099Sdelphij
27208099Sdelphij#include <sys/cdefs.h>
28208099Sdelphij__FBSDID("$FreeBSD: head/sys/gdb/gdb_main.c 158949 2006-05-26 11:52:59Z phk $");
29208099Sdelphij
30208099Sdelphij#include <sys/param.h>
31208099Sdelphij#include <sys/systm.h>
32208099Sdelphij#include <sys/kdb.h>
33208099Sdelphij#include <sys/kernel.h>
34208099Sdelphij#include <sys/pcpu.h>
35208099Sdelphij#include <sys/proc.h>
36208099Sdelphij#include <sys/reboot.h>
37208099Sdelphij
38208099Sdelphij#include <machine/gdb_machdep.h>
39208099Sdelphij#include <machine/kdb.h>
40208099Sdelphij
41208099Sdelphij#include <gdb/gdb.h>
42208099Sdelphij#include <gdb/gdb_int.h>
43208099Sdelphij
44208099Sdelphijstatic dbbe_init_f gdb_init;
45208099Sdelphijstatic dbbe_trap_f gdb_trap;
46208099Sdelphij
47208099SdelphijKDB_BACKEND(gdb, gdb_init, NULL, gdb_trap);
48208099Sdelphij
49208099Sdelphijstatic struct gdb_dbgport null_gdb_dbgport;
50208099SdelphijDATA_SET(gdb_dbgport_set, null_gdb_dbgport);
51208099SdelphijSET_DECLARE(gdb_dbgport_set, struct gdb_dbgport);
52208099Sdelphij
53208099Sdelphijstruct gdb_dbgport *gdb_cur = NULL;
54208099Sdelphijint gdb_listening = 0;
55208099Sdelphij
56208099Sdelphijstatic int
57208099Sdelphijgdb_init(void)
58208099Sdelphij{
59208099Sdelphij	struct gdb_dbgport *dp, **iter;
60208099Sdelphij	int cur_pri, pri;
61208099Sdelphij
62208099Sdelphij	gdb_cur = NULL;
63208099Sdelphij	cur_pri = -1;
64208099Sdelphij	SET_FOREACH(iter, gdb_dbgport_set) {
65208099Sdelphij		dp = *iter;
66208099Sdelphij		pri = (dp->gdb_probe != NULL) ? dp->gdb_probe() : -1;
67208099Sdelphij		dp->gdb_active = (pri >= 0) ? 0 : -1;
68208099Sdelphij		if (pri > cur_pri) {
69208099Sdelphij			cur_pri = pri;
70208099Sdelphij			gdb_cur = dp;
71208099Sdelphij		}
72208099Sdelphij	}
73208099Sdelphij	if (gdb_cur != NULL) {
74208099Sdelphij		printf("GDB: debug ports:");
75208099Sdelphij		SET_FOREACH(iter, gdb_dbgport_set) {
76208099Sdelphij			dp = *iter;
77208099Sdelphij			if (dp->gdb_active == 0)
78208099Sdelphij				printf(" %s", dp->gdb_name);
79208099Sdelphij		}
80208099Sdelphij		printf("\n");
81208099Sdelphij	} else
82208099Sdelphij		printf("GDB: no debug ports present\n");
83208099Sdelphij	if (gdb_cur != NULL) {
84208099Sdelphij		gdb_cur->gdb_init();
85208099Sdelphij		printf("GDB: current port: %s\n", gdb_cur->gdb_name);
86208099Sdelphij	}
87208099Sdelphij	if (gdb_cur != NULL) {
88208099Sdelphij		cur_pri = (boothowto & RB_GDB) ? 2 : 0;
89208099Sdelphij		gdb_consinit();
90208099Sdelphij	} else
91208099Sdelphij		cur_pri = -1;
92208099Sdelphij	return (cur_pri);
93208099Sdelphij}
94208099Sdelphij
95208099Sdelphijstatic int
96208099Sdelphijgdb_trap(int type, int code)
97208099Sdelphij{
98208099Sdelphij	struct thread *thr_iter;
99208099Sdelphij
100208099Sdelphij	gdb_listening = 0;
101292588Sdelphij	/*
102292588Sdelphij	 * Send a T packet. We currently do not support watchpoints (the
103292588Sdelphij	 * awatch, rwatch or watch elements).
104292588Sdelphij	 */
105292588Sdelphij	gdb_tx_begin('T');
106292588Sdelphij	gdb_tx_hex(gdb_cpu_signal(type, code), 2);
107292588Sdelphij	gdb_tx_varhex(GDB_REG_PC);
108292588Sdelphij	gdb_tx_char(':');
109208099Sdelphij	gdb_tx_reg(GDB_REG_PC);
110208099Sdelphij	gdb_tx_char(';');
111292588Sdelphij	gdb_tx_str("thread:");
112208099Sdelphij	gdb_tx_varhex((long)kdb_thread->td_tid);
113292588Sdelphij	gdb_tx_char(';');
114208099Sdelphij	gdb_tx_end();			/* XXX check error condition. */
115208099Sdelphij
116208099Sdelphij	thr_iter = NULL;
117208099Sdelphij	while (gdb_rx_begin() == 0) {
118208099Sdelphij		/* printf("GDB: got '%s'\n", gdb_rxp); */
119208099Sdelphij		switch (gdb_rx_char()) {
120208099Sdelphij		case '?':	/* Last signal. */
121208099Sdelphij			gdb_tx_begin('S');
122208099Sdelphij			gdb_tx_hex(gdb_cpu_signal(type, code), 2);
123208099Sdelphij			gdb_tx_end();
124208099Sdelphij			break;
125208099Sdelphij		case 'c': {	/* Continue. */
126208099Sdelphij			uintmax_t addr;
127208099Sdelphij			register_t pc;
128208099Sdelphij			if (!gdb_rx_varhex(&addr)) {
129208099Sdelphij				pc = addr;
130208099Sdelphij				gdb_cpu_setreg(GDB_REG_PC, &pc);
131208099Sdelphij			}
132208099Sdelphij			kdb_cpu_clear_singlestep();
133208099Sdelphij			gdb_listening = 1;
134208099Sdelphij			return (1);
135208099Sdelphij		}
136292588Sdelphij		case 'C': {	/* Continue with signal. */
137208099Sdelphij			uintmax_t addr, sig;
138208099Sdelphij			register_t pc;
139208099Sdelphij			if (!gdb_rx_varhex(&sig) && gdb_rx_char() == ';' &&
140208099Sdelphij			    !gdb_rx_varhex(&addr)) {
141208099Sdelphij				pc = addr;
142208099Sdelphij				gdb_cpu_setreg(GDB_REG_PC, &pc);
143208099Sdelphij			}
144208099Sdelphij			kdb_cpu_clear_singlestep();
145208099Sdelphij			gdb_listening = 1;
146208099Sdelphij			return (1);
147208099Sdelphij		}
148208099Sdelphij		case 'g': {	/* Read registers. */
149208099Sdelphij			size_t r;
150208099Sdelphij			gdb_tx_begin(0);
151208099Sdelphij			for (r = 0; r < GDB_NREGS; r++)
152208099Sdelphij				gdb_tx_reg(r);
153208099Sdelphij			gdb_tx_end();
154208099Sdelphij			break;
155208099Sdelphij		}
156208099Sdelphij		case 'G':	/* Write registers. */
157208099Sdelphij			gdb_tx_err(0);
158208099Sdelphij			break;
159208099Sdelphij		case 'H': {	/* Set thread. */
160208099Sdelphij			intmax_t tid;
161208099Sdelphij			struct thread *thr;
162208099Sdelphij			gdb_rx_char();
163208099Sdelphij			if (gdb_rx_varhex(&tid)) {
164208099Sdelphij				gdb_tx_err(EINVAL);
165208099Sdelphij				break;
166208099Sdelphij			}
167208099Sdelphij			if (tid > 0) {
168208099Sdelphij				thr = kdb_thr_lookup(tid);
169292588Sdelphij				if (thr == NULL) {
170208099Sdelphij					gdb_tx_err(ENOENT);
171208099Sdelphij					break;
172208099Sdelphij				}
173292588Sdelphij				kdb_thr_select(thr);
174292588Sdelphij			}
175292588Sdelphij			gdb_tx_ok();
176292588Sdelphij			break;
177292588Sdelphij		}
178292588Sdelphij		case 'k':	/* Kill request. */
179208099Sdelphij			kdb_cpu_clear_singlestep();
180208099Sdelphij			gdb_listening = 1;
181208099Sdelphij			return (1);
182208099Sdelphij		case 'm': {	/* Read memory. */
183208099Sdelphij			uintmax_t addr, size;
184208099Sdelphij			if (gdb_rx_varhex(&addr) || gdb_rx_char() != ',' ||
185208099Sdelphij			    gdb_rx_varhex(&size)) {
186208099Sdelphij				gdb_tx_err(EINVAL);
187208099Sdelphij				break;
188208099Sdelphij			}
189208099Sdelphij			gdb_tx_begin(0);
190208099Sdelphij			if (gdb_tx_mem((char *)(uintptr_t)addr, size))
191208099Sdelphij				gdb_tx_end();
192208099Sdelphij			else
193208099Sdelphij				gdb_tx_err(EIO);
194208099Sdelphij			break;
195208099Sdelphij		}
196208099Sdelphij		case 'M': {	/* Write memory. */
197208099Sdelphij			uintmax_t addr, size;
198208099Sdelphij			if (gdb_rx_varhex(&addr) || gdb_rx_char() != ',' ||
199208099Sdelphij			    gdb_rx_varhex(&size) || gdb_rx_char() != ':') {
200208099Sdelphij				gdb_tx_err(EINVAL);
201208099Sdelphij				break;
202208099Sdelphij			}
203208099Sdelphij			if (gdb_rx_mem((char *)(uintptr_t)addr, size) == 0)
204292588Sdelphij				gdb_tx_err(EIO);
205208099Sdelphij			else
206208099Sdelphij				gdb_tx_ok();
207			break;
208		}
209		case 'P': {	/* Write register. */
210			char *val;
211			uintmax_t reg;
212			val = gdb_rxp;
213			if (gdb_rx_varhex(&reg) || gdb_rx_char() != '=' ||
214			    !gdb_rx_mem(val, gdb_cpu_regsz(reg))) {
215				gdb_tx_err(EINVAL);
216				break;
217			}
218			gdb_cpu_setreg(reg, val);
219			gdb_tx_ok();
220			break;
221		}
222		case 'q':	/* General query. */
223			if (gdb_rx_equal("fThreadInfo")) {
224				thr_iter = kdb_thr_first();
225				gdb_tx_begin('m');
226				gdb_tx_hex((long)thr_iter->td_tid, 8);
227				gdb_tx_end();
228			} else if (gdb_rx_equal("sThreadInfo")) {
229				if (thr_iter == NULL) {
230					gdb_tx_err(ENXIO);
231					break;
232				}
233				thr_iter = kdb_thr_next(thr_iter);
234				if (thr_iter != NULL) {
235					gdb_tx_begin('m');
236					gdb_tx_hex((long)thr_iter->td_tid, 8);
237					gdb_tx_end();
238				} else {
239					gdb_tx_begin('l');
240					gdb_tx_end();
241				}
242			} else if (!gdb_cpu_query())
243				gdb_tx_empty();
244			break;
245		case 's': {	/* Step. */
246			uintmax_t addr;
247			register_t pc;
248			if (!gdb_rx_varhex(&addr)) {
249				pc = addr;
250				gdb_cpu_setreg(GDB_REG_PC, &pc);
251			}
252			kdb_cpu_set_singlestep();
253			gdb_listening = 1;
254			return (1);
255		}
256		case 'S': {	/* Step with signal. */
257			uintmax_t addr, sig;
258			register_t pc;
259			if (!gdb_rx_varhex(&sig) && gdb_rx_char() == ';' &&
260			    !gdb_rx_varhex(&addr)) {
261				pc = addr;
262				gdb_cpu_setreg(GDB_REG_PC, &pc);
263			}
264			kdb_cpu_set_singlestep();
265			gdb_listening = 1;
266			return (1);
267		}
268		case 'T': {	/* Thread alive. */
269			intmax_t tid;
270			if (gdb_rx_varhex(&tid)) {
271				gdb_tx_err(EINVAL);
272				break;
273			}
274			if (kdb_thr_lookup(tid) != NULL)
275				gdb_tx_ok();
276			else
277				gdb_tx_err(ENOENT);
278			break;
279		}
280		case -1:
281			/* Empty command. Treat as unknown command. */
282			/* FALLTHROUGH */
283		default:
284			/* Unknown command. Send empty response. */
285			gdb_tx_empty();
286			break;
287		}
288	}
289	return (0);
290}
291