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