xref: /freebsd/sys/gdb/netgdb.c (revision dda17b3672f2c7f661699a69ea4462710a52480d)
1*dda17b36SConrad Meyer /*-
2*dda17b36SConrad Meyer  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*dda17b36SConrad Meyer  *
4*dda17b36SConrad Meyer  * Copyright (c) 2019 Isilon Systems, LLC.
5*dda17b36SConrad Meyer  *
6*dda17b36SConrad Meyer  * Redistribution and use in source and binary forms, with or without
7*dda17b36SConrad Meyer  * modification, are permitted provided that the following conditions
8*dda17b36SConrad Meyer  * are met:
9*dda17b36SConrad Meyer  * 1. Redistributions of source code must retain the above copyright
10*dda17b36SConrad Meyer  *    notice, this list of conditions and the following disclaimer.
11*dda17b36SConrad Meyer  * 2. Redistributions in binary form must reproduce the above copyright
12*dda17b36SConrad Meyer  *    notice, this list of conditions and the following disclaimer in the
13*dda17b36SConrad Meyer  *    documentation and/or other materials provided with the distribution.
14*dda17b36SConrad Meyer  *
15*dda17b36SConrad Meyer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*dda17b36SConrad Meyer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*dda17b36SConrad Meyer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*dda17b36SConrad Meyer  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*dda17b36SConrad Meyer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*dda17b36SConrad Meyer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*dda17b36SConrad Meyer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*dda17b36SConrad Meyer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*dda17b36SConrad Meyer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*dda17b36SConrad Meyer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*dda17b36SConrad Meyer  * SUCH DAMAGE.
26*dda17b36SConrad Meyer  */
27*dda17b36SConrad Meyer 
28*dda17b36SConrad Meyer /*
29*dda17b36SConrad Meyer  * netgdb.c
30*dda17b36SConrad Meyer  * FreeBSD subsystem supporting debugging the FreeBSD kernel over the network.
31*dda17b36SConrad Meyer  *
32*dda17b36SConrad Meyer  * There are three pieces necessary to use NetGDB.
33*dda17b36SConrad Meyer  *
34*dda17b36SConrad Meyer  * First, a dedicated proxy server must be running to accept connections from
35*dda17b36SConrad Meyer  * both NetGDB and gdb(1), and pass bidirectional traffic between the two
36*dda17b36SConrad Meyer  * protocols.
37*dda17b36SConrad Meyer  *
38*dda17b36SConrad Meyer  * Second, The NetGDB client is activated much like ordinary 'gdb' and
39*dda17b36SConrad Meyer  * similarly to 'netdump' in ddb(4).  Like other debugnet(4) clients
40*dda17b36SConrad Meyer  * (netdump(4)), the network interface on the route to the proxy server must be
41*dda17b36SConrad Meyer  * online and support debugnet(4).
42*dda17b36SConrad Meyer  *
43*dda17b36SConrad Meyer  * Finally, the remote (k)gdb(1) uses 'target remote <proxy>:<port>' to connect
44*dda17b36SConrad Meyer  * to the proxy server.
45*dda17b36SConrad Meyer  *
46*dda17b36SConrad Meyer  * NetGDBv1 speaks the literal GDB remote serial protocol, and uses a 1:1
47*dda17b36SConrad Meyer  * relationship between GDB packets and plain debugnet packets.  There is no
48*dda17b36SConrad Meyer  * encryption utilized to keep debugging sessions private, so this is only
49*dda17b36SConrad Meyer  * appropriate for local segments or trusted networks.
50*dda17b36SConrad Meyer  */
51*dda17b36SConrad Meyer 
52*dda17b36SConrad Meyer #include <sys/cdefs.h>
53*dda17b36SConrad Meyer __FBSDID("$FreeBSD$");
54*dda17b36SConrad Meyer 
55*dda17b36SConrad Meyer #include "opt_ddb.h"
56*dda17b36SConrad Meyer #ifndef DDB
57*dda17b36SConrad Meyer #error "NetGDB cannot be used without DDB at this time"
58*dda17b36SConrad Meyer #endif
59*dda17b36SConrad Meyer 
60*dda17b36SConrad Meyer #include <sys/param.h>
61*dda17b36SConrad Meyer #include <sys/kdb.h>
62*dda17b36SConrad Meyer #include <sys/sbuf.h>
63*dda17b36SConrad Meyer #include <sys/socket.h>
64*dda17b36SConrad Meyer #include <sys/sysctl.h>
65*dda17b36SConrad Meyer #include <sys/ttydefaults.h>
66*dda17b36SConrad Meyer 
67*dda17b36SConrad Meyer #include <machine/gdb_machdep.h>
68*dda17b36SConrad Meyer 
69*dda17b36SConrad Meyer #ifdef DDB
70*dda17b36SConrad Meyer #include <ddb/ddb.h>
71*dda17b36SConrad Meyer #include <ddb/db_command.h>
72*dda17b36SConrad Meyer #include <ddb/db_lex.h>
73*dda17b36SConrad Meyer #endif
74*dda17b36SConrad Meyer 
75*dda17b36SConrad Meyer #include <net/debugnet.h>
76*dda17b36SConrad Meyer #include <net/if.h>
77*dda17b36SConrad Meyer #include <net/if_var.h>
78*dda17b36SConrad Meyer #include <net/route.h>
79*dda17b36SConrad Meyer 
80*dda17b36SConrad Meyer #include <gdb/gdb.h>
81*dda17b36SConrad Meyer #include <gdb/gdb_int.h>
82*dda17b36SConrad Meyer #include <gdb/netgdb.h>
83*dda17b36SConrad Meyer 
84*dda17b36SConrad Meyer FEATURE(netgdb, "NetGDB support");
85*dda17b36SConrad Meyer SYSCTL_NODE(_debug_gdb, OID_AUTO, netgdb, CTLFLAG_RD, NULL,
86*dda17b36SConrad Meyer     "NetGDB parameters");
87*dda17b36SConrad Meyer 
88*dda17b36SConrad Meyer static unsigned netgdb_debug;
89*dda17b36SConrad Meyer SYSCTL_UINT(_debug_gdb_netgdb, OID_AUTO, debug, CTLFLAG_RWTUN,
90*dda17b36SConrad Meyer     &netgdb_debug, 0,
91*dda17b36SConrad Meyer     "Debug message verbosity (0: off; 1: on)");
92*dda17b36SConrad Meyer 
93*dda17b36SConrad Meyer #define	NETGDB_DEBUG(f, ...) do {						\
94*dda17b36SConrad Meyer 	if (netgdb_debug > 0)							\
95*dda17b36SConrad Meyer 		printf(("%s [%s:%d]: " f), __func__, __FILE__, __LINE__, ##	\
96*dda17b36SConrad Meyer 		    __VA_ARGS__);						\
97*dda17b36SConrad Meyer } while (false)
98*dda17b36SConrad Meyer 
99*dda17b36SConrad Meyer static void netgdb_fini(void);
100*dda17b36SConrad Meyer 
101*dda17b36SConrad Meyer /* Runtime state. */
102*dda17b36SConrad Meyer static char netgdb_rxbuf[GDB_BUFSZ + 16];	/* Some overhead for framing. */
103*dda17b36SConrad Meyer static struct sbuf netgdb_rxsb;
104*dda17b36SConrad Meyer static ssize_t netgdb_rx_off;
105*dda17b36SConrad Meyer 
106*dda17b36SConrad Meyer static struct debugnet_pcb *netgdb_conn;
107*dda17b36SConrad Meyer static struct gdb_dbgport *netgdb_prev_dbgport;
108*dda17b36SConrad Meyer static int *netgdb_prev_kdb_inactive;
109*dda17b36SConrad Meyer 
110*dda17b36SConrad Meyer /* TODO(CEM) disable ack mode */
111*dda17b36SConrad Meyer 
112*dda17b36SConrad Meyer /*
113*dda17b36SConrad Meyer  * Receive non-TX ACK packets on the client port.
114*dda17b36SConrad Meyer  *
115*dda17b36SConrad Meyer  * The mbuf chain will have all non-debugnet framing headers removed
116*dda17b36SConrad Meyer  * (ethernet, inet, udp).  It will start with a debugnet_msg_hdr, of
117*dda17b36SConrad Meyer  * which the header is guaranteed to be contiguous.  If m_pullup is
118*dda17b36SConrad Meyer  * used, the supplied in-out mbuf pointer should be updated
119*dda17b36SConrad Meyer  * appropriately.
120*dda17b36SConrad Meyer  *
121*dda17b36SConrad Meyer  * If the handler frees the mbuf chain, it should set the mbuf pointer
122*dda17b36SConrad Meyer  * to NULL.  Otherwise, the debugnet input framework will free the
123*dda17b36SConrad Meyer  * chain.
124*dda17b36SConrad Meyer  */
125*dda17b36SConrad Meyer static void
126*dda17b36SConrad Meyer netgdb_rx(struct debugnet_pcb *pcb, struct mbuf **mb)
127*dda17b36SConrad Meyer {
128*dda17b36SConrad Meyer 	const struct debugnet_msg_hdr *dnh;
129*dda17b36SConrad Meyer 	struct mbuf *m;
130*dda17b36SConrad Meyer 	uint32_t rlen, count;
131*dda17b36SConrad Meyer 	int error;
132*dda17b36SConrad Meyer 
133*dda17b36SConrad Meyer 	m = *mb;
134*dda17b36SConrad Meyer 	dnh = mtod(m, const void *);
135*dda17b36SConrad Meyer 
136*dda17b36SConrad Meyer 	if (ntohl(dnh->mh_type) == DEBUGNET_FINISHED) {
137*dda17b36SConrad Meyer 		sbuf_putc(&netgdb_rxsb, CTRL('C'));
138*dda17b36SConrad Meyer 		return;
139*dda17b36SConrad Meyer 	}
140*dda17b36SConrad Meyer 
141*dda17b36SConrad Meyer 	if (ntohl(dnh->mh_type) != DEBUGNET_DATA) {
142*dda17b36SConrad Meyer 		printf("%s: Got unexpected debugnet message %u\n",
143*dda17b36SConrad Meyer 		    __func__, ntohl(dnh->mh_type));
144*dda17b36SConrad Meyer 		return;
145*dda17b36SConrad Meyer 	}
146*dda17b36SConrad Meyer 
147*dda17b36SConrad Meyer 	rlen = ntohl(dnh->mh_len);
148*dda17b36SConrad Meyer #define	_SBUF_FREESPACE(s)	((s)->s_size - ((s)->s_len + 1))
149*dda17b36SConrad Meyer 	if (_SBUF_FREESPACE(&netgdb_rxsb) < rlen) {
150*dda17b36SConrad Meyer 		NETGDB_DEBUG("Backpressure: Not ACKing RX of packet that "
151*dda17b36SConrad Meyer 		    "would overflow our buffer (%zd/%zd used).\n",
152*dda17b36SConrad Meyer 		    netgdb_rxsb.s_len, netgdb_rxsb.s_size);
153*dda17b36SConrad Meyer 		return;
154*dda17b36SConrad Meyer 	}
155*dda17b36SConrad Meyer #undef _SBUF_FREESPACE
156*dda17b36SConrad Meyer 
157*dda17b36SConrad Meyer 	error = debugnet_ack_output(pcb, dnh->mh_seqno);
158*dda17b36SConrad Meyer 	if (error != 0) {
159*dda17b36SConrad Meyer 		printf("%s: Couldn't ACK rx packet %u; %d\n", __func__,
160*dda17b36SConrad Meyer 		    ntohl(dnh->mh_seqno), error);
161*dda17b36SConrad Meyer 		/*
162*dda17b36SConrad Meyer 		 * Sender will re-xmit, and assuming the condition is
163*dda17b36SConrad Meyer 		 * transient, we'll process the packet's contentss later.
164*dda17b36SConrad Meyer 		 */
165*dda17b36SConrad Meyer 		return;
166*dda17b36SConrad Meyer 	}
167*dda17b36SConrad Meyer 
168*dda17b36SConrad Meyer 	m_adj(m, sizeof(*dnh));
169*dda17b36SConrad Meyer 	dnh = NULL;
170*dda17b36SConrad Meyer 
171*dda17b36SConrad Meyer 	/*
172*dda17b36SConrad Meyer 	 * Inlined m_apply -- why isn't there a macro or inline function
173*dda17b36SConrad Meyer 	 * version?
174*dda17b36SConrad Meyer 	 */
175*dda17b36SConrad Meyer 	while (m != NULL && m->m_len == 0)
176*dda17b36SConrad Meyer 		m = m->m_next;
177*dda17b36SConrad Meyer 	while (rlen > 0) {
178*dda17b36SConrad Meyer 		MPASS(m != NULL && m->m_len >= 0);
179*dda17b36SConrad Meyer 		count = min((uint32_t)m->m_len, rlen);
180*dda17b36SConrad Meyer 		(void)sbuf_bcat(&netgdb_rxsb, mtod(m, const void *), count);
181*dda17b36SConrad Meyer 		rlen -= count;
182*dda17b36SConrad Meyer 		m = m->m_next;
183*dda17b36SConrad Meyer 	}
184*dda17b36SConrad Meyer }
185*dda17b36SConrad Meyer 
186*dda17b36SConrad Meyer /*
187*dda17b36SConrad Meyer  * The following routines implement a pseudo GDB debugport (an emulated serial
188*dda17b36SConrad Meyer  * driver that the MI gdb(4) code does I/O with).
189*dda17b36SConrad Meyer  */
190*dda17b36SConrad Meyer 
191*dda17b36SConrad Meyer static int
192*dda17b36SConrad Meyer netgdb_dbg_getc(void)
193*dda17b36SConrad Meyer {
194*dda17b36SConrad Meyer 	int c;
195*dda17b36SConrad Meyer 
196*dda17b36SConrad Meyer 	while (true) {
197*dda17b36SConrad Meyer 		/* Pull bytes off any currently cached packet first. */
198*dda17b36SConrad Meyer 		if (netgdb_rx_off < sbuf_len(&netgdb_rxsb)) {
199*dda17b36SConrad Meyer 			c = netgdb_rxsb.s_buf[netgdb_rx_off];
200*dda17b36SConrad Meyer 			netgdb_rx_off++;
201*dda17b36SConrad Meyer 			break;
202*dda17b36SConrad Meyer 		}
203*dda17b36SConrad Meyer 
204*dda17b36SConrad Meyer 		/* Reached EOF?  Reuse buffer. */
205*dda17b36SConrad Meyer 		sbuf_clear(&netgdb_rxsb);
206*dda17b36SConrad Meyer 		netgdb_rx_off = 0;
207*dda17b36SConrad Meyer 
208*dda17b36SConrad Meyer 		/* Check for CTRL-C on console/serial, if any. */
209*dda17b36SConrad Meyer 		if (netgdb_prev_dbgport != NULL) {
210*dda17b36SConrad Meyer 			c = netgdb_prev_dbgport->gdb_getc();
211*dda17b36SConrad Meyer 			if (c == CTRL('C'))
212*dda17b36SConrad Meyer 				break;
213*dda17b36SConrad Meyer 		}
214*dda17b36SConrad Meyer 
215*dda17b36SConrad Meyer 		debugnet_network_poll(netgdb_conn);
216*dda17b36SConrad Meyer 	}
217*dda17b36SConrad Meyer 
218*dda17b36SConrad Meyer 	if (c == CTRL('C')) {
219*dda17b36SConrad Meyer 		netgdb_fini();
220*dda17b36SConrad Meyer 		/* Caller gdb_getc() will print that we got ^C. */
221*dda17b36SConrad Meyer 	}
222*dda17b36SConrad Meyer 	return (c);
223*dda17b36SConrad Meyer }
224*dda17b36SConrad Meyer 
225*dda17b36SConrad Meyer static void
226*dda17b36SConrad Meyer netgdb_dbg_sendpacket(const void *buf, size_t len)
227*dda17b36SConrad Meyer {
228*dda17b36SConrad Meyer 	struct debugnet_proto_aux aux;
229*dda17b36SConrad Meyer 	int error;
230*dda17b36SConrad Meyer 
231*dda17b36SConrad Meyer 	MPASS(len <= UINT32_MAX);
232*dda17b36SConrad Meyer 
233*dda17b36SConrad Meyer 	/*
234*dda17b36SConrad Meyer 	 * GDB packet boundaries matter.  debugnet_send() fragments a single
235*dda17b36SConrad Meyer 	 * request into many sequential debugnet messages.  Mark full packet
236*dda17b36SConrad Meyer 	 * length and offset for potential reassembly by the proxy.
237*dda17b36SConrad Meyer 	 */
238*dda17b36SConrad Meyer 	aux = (struct debugnet_proto_aux) {
239*dda17b36SConrad Meyer 		.dp_aux2 = len,
240*dda17b36SConrad Meyer 	};
241*dda17b36SConrad Meyer 
242*dda17b36SConrad Meyer 	error = debugnet_send(netgdb_conn, DEBUGNET_DATA, buf, len, &aux);
243*dda17b36SConrad Meyer 	if (error != 0) {
244*dda17b36SConrad Meyer 		printf("%s: Network error: %d; trying to switch back to ddb.\n",
245*dda17b36SConrad Meyer 		    __func__, error);
246*dda17b36SConrad Meyer 		netgdb_fini();
247*dda17b36SConrad Meyer 
248*dda17b36SConrad Meyer 		if (kdb_dbbe_select("ddb") != 0)
249*dda17b36SConrad Meyer 			printf("The ddb backend could not be selected.\n");
250*dda17b36SConrad Meyer 		else {
251*dda17b36SConrad Meyer 			printf("using longjmp, hope it works!\n");
252*dda17b36SConrad Meyer 			kdb_reenter();
253*dda17b36SConrad Meyer 		}
254*dda17b36SConrad Meyer 	}
255*dda17b36SConrad Meyer 
256*dda17b36SConrad Meyer }
257*dda17b36SConrad Meyer 
258*dda17b36SConrad Meyer /* Just used for + / - GDB-level ACKs. */
259*dda17b36SConrad Meyer static void
260*dda17b36SConrad Meyer netgdb_dbg_putc(int i)
261*dda17b36SConrad Meyer {
262*dda17b36SConrad Meyer 	char c;
263*dda17b36SConrad Meyer 
264*dda17b36SConrad Meyer 	c = i;
265*dda17b36SConrad Meyer 	netgdb_dbg_sendpacket(&c, 1);
266*dda17b36SConrad Meyer 
267*dda17b36SConrad Meyer }
268*dda17b36SConrad Meyer 
269*dda17b36SConrad Meyer static struct gdb_dbgport netgdb_gdb_dbgport = {
270*dda17b36SConrad Meyer 	.gdb_name = "netgdb",
271*dda17b36SConrad Meyer 	.gdb_getc = netgdb_dbg_getc,
272*dda17b36SConrad Meyer 	.gdb_putc = netgdb_dbg_putc,
273*dda17b36SConrad Meyer 	.gdb_term = netgdb_fini,
274*dda17b36SConrad Meyer 	.gdb_sendpacket = netgdb_dbg_sendpacket,
275*dda17b36SConrad Meyer 	.gdb_dbfeatures = GDB_DBGP_FEAT_WANTTERM,
276*dda17b36SConrad Meyer };
277*dda17b36SConrad Meyer 
278*dda17b36SConrad Meyer static void
279*dda17b36SConrad Meyer netgdb_init(void)
280*dda17b36SConrad Meyer {
281*dda17b36SConrad Meyer 	struct kdb_dbbe *be, **iter;
282*dda17b36SConrad Meyer 
283*dda17b36SConrad Meyer 	/*
284*dda17b36SConrad Meyer 	 * Force enable GDB.  (If no other debugports were registered at boot,
285*dda17b36SConrad Meyer 	 * KDB thinks it doesn't exist.)
286*dda17b36SConrad Meyer 	 */
287*dda17b36SConrad Meyer 	SET_FOREACH(iter, kdb_dbbe_set) {
288*dda17b36SConrad Meyer 		be = *iter;
289*dda17b36SConrad Meyer 		if (strcmp(be->dbbe_name, "gdb") != 0)
290*dda17b36SConrad Meyer 			continue;
291*dda17b36SConrad Meyer 		if (be->dbbe_active == -1) {
292*dda17b36SConrad Meyer 			netgdb_prev_kdb_inactive = &be->dbbe_active;
293*dda17b36SConrad Meyer 			be->dbbe_active = 0;
294*dda17b36SConrad Meyer 		}
295*dda17b36SConrad Meyer 		break;
296*dda17b36SConrad Meyer 	}
297*dda17b36SConrad Meyer 
298*dda17b36SConrad Meyer 	/* Force netgdb debugport. */
299*dda17b36SConrad Meyer 	netgdb_prev_dbgport = gdb_cur;
300*dda17b36SConrad Meyer 	gdb_cur = &netgdb_gdb_dbgport;
301*dda17b36SConrad Meyer 
302*dda17b36SConrad Meyer 	sbuf_new(&netgdb_rxsb, netgdb_rxbuf, sizeof(netgdb_rxbuf),
303*dda17b36SConrad Meyer 	    SBUF_FIXEDLEN);
304*dda17b36SConrad Meyer 	netgdb_rx_off = 0;
305*dda17b36SConrad Meyer }
306*dda17b36SConrad Meyer 
307*dda17b36SConrad Meyer static void
308*dda17b36SConrad Meyer netgdb_fini(void)
309*dda17b36SConrad Meyer {
310*dda17b36SConrad Meyer 
311*dda17b36SConrad Meyer 	/* TODO: tear down conn gracefully? */
312*dda17b36SConrad Meyer 	if (netgdb_conn != NULL) {
313*dda17b36SConrad Meyer 		debugnet_free(netgdb_conn);
314*dda17b36SConrad Meyer 		netgdb_conn = NULL;
315*dda17b36SConrad Meyer 	}
316*dda17b36SConrad Meyer 
317*dda17b36SConrad Meyer 	sbuf_delete(&netgdb_rxsb);
318*dda17b36SConrad Meyer 
319*dda17b36SConrad Meyer 	gdb_cur = netgdb_prev_dbgport;
320*dda17b36SConrad Meyer 
321*dda17b36SConrad Meyer 	if (netgdb_prev_kdb_inactive != NULL) {
322*dda17b36SConrad Meyer 		*netgdb_prev_kdb_inactive = -1;
323*dda17b36SConrad Meyer 		netgdb_prev_kdb_inactive = NULL;
324*dda17b36SConrad Meyer 	}
325*dda17b36SConrad Meyer }
326*dda17b36SConrad Meyer 
327*dda17b36SConrad Meyer #ifdef DDB
328*dda17b36SConrad Meyer /*
329*dda17b36SConrad Meyer  * Usage: netgdb -s <server> [-g <gateway -c <localip> -i <interface>]
330*dda17b36SConrad Meyer  *
331*dda17b36SConrad Meyer  * Order is not significant.
332*dda17b36SConrad Meyer  *
333*dda17b36SConrad Meyer  * Currently, this command does not support configuring encryption or
334*dda17b36SConrad Meyer  * compression.
335*dda17b36SConrad Meyer  */
336*dda17b36SConrad Meyer DB_FUNC(netgdb, db_netgdb_cmd, db_cmd_table, CS_OWN, NULL)
337*dda17b36SConrad Meyer {
338*dda17b36SConrad Meyer 	struct debugnet_ddb_config params;
339*dda17b36SConrad Meyer 	struct debugnet_conn_params dcp;
340*dda17b36SConrad Meyer 	struct debugnet_pcb *pcb;
341*dda17b36SConrad Meyer 	int error;
342*dda17b36SConrad Meyer 
343*dda17b36SConrad Meyer 	if (panicstr == NULL) {
344*dda17b36SConrad Meyer 		/* TODO: This limitation should be removed in future work. */
345*dda17b36SConrad Meyer 		printf("%s: netgdb is currently limited to use only after a "
346*dda17b36SConrad Meyer 		    "panic.  Sorry.\n", __func__);
347*dda17b36SConrad Meyer 		return;
348*dda17b36SConrad Meyer 	}
349*dda17b36SConrad Meyer 
350*dda17b36SConrad Meyer 	error = debugnet_parse_ddb_cmd("netgdb", &params);
351*dda17b36SConrad Meyer 	if (error != 0) {
352*dda17b36SConrad Meyer 		db_printf("Error configuring netgdb: %d\n", error);
353*dda17b36SConrad Meyer 		return;
354*dda17b36SConrad Meyer 	}
355*dda17b36SConrad Meyer 
356*dda17b36SConrad Meyer 	/*
357*dda17b36SConrad Meyer 	 * Must initialize netgdb_rxsb before debugnet_connect(), because we
358*dda17b36SConrad Meyer 	 * might be getting rx handler callbacks from the send->poll path
359*dda17b36SConrad Meyer 	 * during debugnet_connect().
360*dda17b36SConrad Meyer 	 */
361*dda17b36SConrad Meyer 	netgdb_init();
362*dda17b36SConrad Meyer 
363*dda17b36SConrad Meyer 	if (!params.dd_has_client)
364*dda17b36SConrad Meyer 		params.dd_client = INADDR_ANY;
365*dda17b36SConrad Meyer 	if (!params.dd_has_gateway)
366*dda17b36SConrad Meyer 		params.dd_gateway = INADDR_ANY;
367*dda17b36SConrad Meyer 
368*dda17b36SConrad Meyer 	dcp = (struct debugnet_conn_params) {
369*dda17b36SConrad Meyer 		.dc_ifp = params.dd_ifp,
370*dda17b36SConrad Meyer 		.dc_client = params.dd_client,
371*dda17b36SConrad Meyer 		.dc_server = params.dd_server,
372*dda17b36SConrad Meyer 		.dc_gateway = params.dd_gateway,
373*dda17b36SConrad Meyer 		.dc_herald_port = NETGDB_HERALDPORT,
374*dda17b36SConrad Meyer 		.dc_client_port = NETGDB_CLIENTPORT,
375*dda17b36SConrad Meyer 		.dc_herald_aux2 = NETGDB_PROTO_V1,
376*dda17b36SConrad Meyer 		.dc_rx_handler = netgdb_rx,
377*dda17b36SConrad Meyer 	};
378*dda17b36SConrad Meyer 
379*dda17b36SConrad Meyer 	error = debugnet_connect(&dcp, &pcb);
380*dda17b36SConrad Meyer 	if (error != 0) {
381*dda17b36SConrad Meyer 		printf("failed to contact netgdb server: %d\n", error);
382*dda17b36SConrad Meyer 		netgdb_fini();
383*dda17b36SConrad Meyer 		return;
384*dda17b36SConrad Meyer 	}
385*dda17b36SConrad Meyer 
386*dda17b36SConrad Meyer 	netgdb_conn = pcb;
387*dda17b36SConrad Meyer 
388*dda17b36SConrad Meyer 	if (kdb_dbbe_select("gdb") != 0) {
389*dda17b36SConrad Meyer 		db_printf("The remote GDB backend could not be selected.\n");
390*dda17b36SConrad Meyer 		netgdb_fini();
391*dda17b36SConrad Meyer 		return;
392*dda17b36SConrad Meyer 	}
393*dda17b36SConrad Meyer 
394*dda17b36SConrad Meyer 	/*
395*dda17b36SConrad Meyer 	 * Mark that we are done in ddb(4).  Return -> kdb_trap() should
396*dda17b36SConrad Meyer 	 * re-enter with the new backend.
397*dda17b36SConrad Meyer 	 */
398*dda17b36SConrad Meyer 	db_cmd_loop_done = 1;
399*dda17b36SConrad Meyer 	gdb_return_to_ddb = true;
400*dda17b36SConrad Meyer 	db_printf("(detaching GDB will return control to DDB)\n");
401*dda17b36SConrad Meyer #if 0
402*dda17b36SConrad Meyer 	/* Aspirational, but does not work reliably. */
403*dda17b36SConrad Meyer 	db_printf("(ctrl-c will return control to ddb)\n");
404*dda17b36SConrad Meyer #endif
405*dda17b36SConrad Meyer }
406*dda17b36SConrad Meyer #endif /* DDB */
407