xref: /freebsd/sys/gdb/netgdb.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 #include "opt_ddb.h"
54 #ifndef DDB
55 #error "NetGDB cannot be used without DDB at this time"
56 #endif
57 
58 #include <sys/errno.h>
59 #include <sys/param.h>
60 #include <sys/kdb.h>
61 #include <sys/sbuf.h>
62 #include <sys/socket.h>
63 #include <sys/sysctl.h>
64 #include <sys/ttydefaults.h>
65 
66 #include <machine/gdb_machdep.h>
67 
68 #ifdef DDB
69 #include <ddb/ddb.h>
70 #include <ddb/db_command.h>
71 #include <ddb/db_lex.h>
72 #endif
73 
74 #include <net/debugnet.h>
75 #include <net/if.h>
76 #include <net/if_var.h>
77 #include <net/route.h>
78 
79 #include <gdb/gdb.h>
80 #include <gdb/gdb_int.h>
81 #include <gdb/netgdb.h>
82 
83 FEATURE(netgdb, "NetGDB support");
84 SYSCTL_NODE(_debug_gdb, OID_AUTO, netgdb, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
85     "NetGDB parameters");
86 
87 static unsigned netgdb_debug;
88 SYSCTL_UINT(_debug_gdb_netgdb, OID_AUTO, debug, CTLFLAG_RWTUN,
89     &netgdb_debug, 0,
90     "Debug message verbosity (0: off; 1: on)");
91 
92 #define	NETGDB_DEBUG(f, ...) do {						\
93 	if (netgdb_debug > 0)							\
94 		printf(("%s [%s:%d]: " f), __func__, __FILE__, __LINE__, ##	\
95 		    __VA_ARGS__);						\
96 } while (false)
97 
98 static void netgdb_fini(void);
99 
100 /* Runtime state. */
101 static char netgdb_rxbuf[GDB_BUFSZ + 16];	/* Some overhead for framing. */
102 static struct sbuf netgdb_rxsb;
103 static ssize_t netgdb_rx_off;
104 
105 static struct debugnet_pcb *netgdb_conn;
106 static struct gdb_dbgport *netgdb_prev_dbgport;
107 static int *netgdb_prev_kdb_inactive;
108 
109 /* TODO(CEM) disable ack mode */
110 
111 /*
112  * Attempt to accept the incoming packet. If we run into ENOBUFS or another
113  * error, return it.
114  *
115  * The mbuf chain will have all framing headers removed (ethernet, inet, udp,
116  * debugnet).
117  */
118 static int
netgdb_rx(struct mbuf * m)119 netgdb_rx(struct mbuf *m)
120 {
121 	uint32_t rlen, count;
122 
123 	rlen = m->m_pkthdr.len;
124 #define	_SBUF_FREESPACE(s)	((s)->s_size - ((s)->s_len + 1))
125 	if (_SBUF_FREESPACE(&netgdb_rxsb) < rlen) {
126 		NETGDB_DEBUG("Backpressure: Not ACKing RX of packet that "
127 		    "would overflow our buffer (%zd/%zd used).\n",
128 		    netgdb_rxsb.s_len, netgdb_rxsb.s_size);
129 		return (ENOBUFS);
130 	}
131 #undef _SBUF_FREESPACE
132 
133 	/*
134 	 * Inlined m_apply -- why isn't there a macro or inline function
135 	 * version?
136 	 */
137 	while (m != NULL && m->m_len == 0)
138 		m = m->m_next;
139 	while (rlen > 0) {
140 		MPASS(m != NULL && m->m_len >= 0);
141 		count = min((uint32_t)m->m_len, rlen);
142 		(void)sbuf_bcat(&netgdb_rxsb, mtod(m, const void *), count);
143 		rlen -= count;
144 		m = m->m_next;
145 	}
146 	return (0);
147 }
148 
149 static void
netgdb_finish(void)150 netgdb_finish(void)
151 {
152 	sbuf_putc(&netgdb_rxsb, CTRL('C'));
153 }
154 
155 /*
156  * The following routines implement a pseudo GDB debugport (an emulated serial
157  * driver that the MI gdb(4) code does I/O with).
158  */
159 
160 static int
netgdb_dbg_getc(void)161 netgdb_dbg_getc(void)
162 {
163 	int c;
164 
165 	while (true) {
166 		/* Pull bytes off any currently cached packet first. */
167 		if (netgdb_rx_off < sbuf_len(&netgdb_rxsb)) {
168 			c = netgdb_rxsb.s_buf[netgdb_rx_off];
169 			netgdb_rx_off++;
170 			break;
171 		}
172 
173 		/* Reached EOF?  Reuse buffer. */
174 		sbuf_clear(&netgdb_rxsb);
175 		netgdb_rx_off = 0;
176 
177 		/* Check for CTRL-C on console/serial, if any. */
178 		if (netgdb_prev_dbgport != NULL) {
179 			c = netgdb_prev_dbgport->gdb_getc();
180 			if (c == CTRL('C'))
181 				break;
182 		}
183 
184 		debugnet_network_poll(netgdb_conn);
185 	}
186 
187 	if (c == CTRL('C')) {
188 		netgdb_fini();
189 		/* Caller gdb_getc() will print that we got ^C. */
190 	}
191 	return (c);
192 }
193 
194 static void
netgdb_dbg_sendpacket(const void * buf,size_t len)195 netgdb_dbg_sendpacket(const void *buf, size_t len)
196 {
197 	struct debugnet_proto_aux aux;
198 	int error;
199 
200 	MPASS(len <= UINT32_MAX);
201 
202 	/*
203 	 * GDB packet boundaries matter.  debugnet_send() fragments a single
204 	 * request into many sequential debugnet messages.  Mark full packet
205 	 * length and offset for potential reassembly by the proxy.
206 	 */
207 	aux = (struct debugnet_proto_aux) {
208 		.dp_aux2 = len,
209 	};
210 
211 	error = debugnet_send(netgdb_conn, DEBUGNET_DATA, buf, len, &aux);
212 	if (error != 0) {
213 		printf("%s: Network error: %d; trying to switch back to ddb.\n",
214 		    __func__, error);
215 		netgdb_fini();
216 
217 		if (kdb_dbbe_select("ddb") != 0)
218 			printf("The ddb backend could not be selected.\n");
219 		else {
220 			printf("using longjmp, hope it works!\n");
221 			kdb_reenter();
222 		}
223 	}
224 
225 }
226 
227 /* Just used for + / - GDB-level ACKs. */
228 static void
netgdb_dbg_putc(int i)229 netgdb_dbg_putc(int i)
230 {
231 	char c;
232 
233 	c = i;
234 	netgdb_dbg_sendpacket(&c, 1);
235 
236 }
237 
238 static struct gdb_dbgport netgdb_gdb_dbgport = {
239 	.gdb_name = "netgdb",
240 	.gdb_getc = netgdb_dbg_getc,
241 	.gdb_putc = netgdb_dbg_putc,
242 	.gdb_term = netgdb_fini,
243 	.gdb_sendpacket = netgdb_dbg_sendpacket,
244 	.gdb_dbfeatures = GDB_DBGP_FEAT_WANTTERM | GDB_DBGP_FEAT_RELIABLE,
245 };
246 
247 static void
netgdb_init(void)248 netgdb_init(void)
249 {
250 	struct kdb_dbbe *be, **iter;
251 
252 	/*
253 	 * Force enable GDB.  (If no other debugports were registered at boot,
254 	 * KDB thinks it doesn't exist.)
255 	 */
256 	SET_FOREACH(iter, kdb_dbbe_set) {
257 		be = *iter;
258 		if (strcmp(be->dbbe_name, "gdb") != 0)
259 			continue;
260 		if (be->dbbe_active == -1) {
261 			netgdb_prev_kdb_inactive = &be->dbbe_active;
262 			be->dbbe_active = 0;
263 		}
264 		break;
265 	}
266 
267 	/* Force netgdb debugport. */
268 	netgdb_prev_dbgport = gdb_cur;
269 	gdb_cur = &netgdb_gdb_dbgport;
270 
271 	sbuf_new(&netgdb_rxsb, netgdb_rxbuf, sizeof(netgdb_rxbuf),
272 	    SBUF_FIXEDLEN);
273 	netgdb_rx_off = 0;
274 }
275 
276 static void
netgdb_fini(void)277 netgdb_fini(void)
278 {
279 
280 	/* TODO: tear down conn gracefully? */
281 	if (netgdb_conn != NULL) {
282 		debugnet_free(netgdb_conn);
283 		netgdb_conn = NULL;
284 	}
285 
286 	sbuf_delete(&netgdb_rxsb);
287 
288 	gdb_cur = netgdb_prev_dbgport;
289 
290 	if (netgdb_prev_kdb_inactive != NULL) {
291 		*netgdb_prev_kdb_inactive = -1;
292 		netgdb_prev_kdb_inactive = NULL;
293 	}
294 }
295 
296 #ifdef DDB
297 /*
298  * Usage: netgdb -s <server> [-g <gateway -c <localip> -i <interface>]
299  *
300  * Order is not significant.
301  *
302  * Currently, this command does not support configuring encryption or
303  * compression.
304  */
DB_COMMAND_FLAGS(netgdb,db_netgdb_cmd,CS_OWN)305 DB_COMMAND_FLAGS(netgdb, db_netgdb_cmd, CS_OWN)
306 {
307 	struct debugnet_ddb_config params;
308 	struct debugnet_conn_params dcp;
309 	struct debugnet_pcb *pcb;
310 	char proxy_buf[INET_ADDRSTRLEN];
311 	int error;
312 
313 	if (!KERNEL_PANICKED()) {
314 		/* TODO: This limitation should be removed in future work. */
315 		printf("%s: netgdb is currently limited to use only after a "
316 		    "panic.  Sorry.\n", __func__);
317 		return;
318 	}
319 
320 	error = debugnet_parse_ddb_cmd("netgdb", &params);
321 	if (error != 0) {
322 		db_printf("Error configuring netgdb: %d\n", error);
323 		return;
324 	}
325 
326 	/*
327 	 * Must initialize netgdb_rxsb before debugnet_connect(), because we
328 	 * might be getting rx handler callbacks from the send->poll path
329 	 * during debugnet_connect().
330 	 */
331 	netgdb_init();
332 
333 	if (!params.dd_has_client)
334 		params.dd_client = INADDR_ANY;
335 	if (!params.dd_has_gateway)
336 		params.dd_gateway = INADDR_ANY;
337 
338 	dcp = (struct debugnet_conn_params) {
339 		.dc_ifp = params.dd_ifp,
340 		.dc_client = params.dd_client,
341 		.dc_server = params.dd_server,
342 		.dc_gateway = params.dd_gateway,
343 		.dc_herald_port = NETGDB_HERALDPORT,
344 		.dc_client_port = NETGDB_CLIENTPORT,
345 		.dc_herald_aux2 = NETGDB_PROTO_V1,
346 		.dc_rx_handler = netgdb_rx,
347 		.dc_finish_handler = netgdb_finish,
348 	};
349 
350 	error = debugnet_connect(&dcp, &pcb);
351 	if (error != 0) {
352 		printf("failed to contact netgdb server: %d\n", error);
353 		netgdb_fini();
354 		return;
355 	}
356 
357 	netgdb_conn = pcb;
358 
359 	if (kdb_dbbe_select("gdb") != 0) {
360 		db_printf("The remote GDB backend could not be selected.\n");
361 		netgdb_fini();
362 		return;
363 	}
364 
365 	/*
366 	 * Mark that we are done in ddb(4).  Return -> kdb_trap() should
367 	 * re-enter with the new backend.
368 	 */
369 	db_cmd_loop_done = 1;
370 	gdb_return_to_ddb = true;
371 	db_printf("(detaching GDB will return control to DDB)\n");
372 
373 	const in_addr_t *proxy_addr = debugnet_get_server_addr(netgdb_conn);
374 	const uint16_t proxy_port = debugnet_get_server_port(netgdb_conn) + 1;
375 	inet_ntop(AF_INET, proxy_addr, proxy_buf, sizeof(proxy_buf));
376 	if (inet_ntop(AF_INET, proxy_addr, proxy_buf, sizeof(proxy_buf)) == NULL) {
377 		db_printf("Connected to proxy. "
378 		    "Use target remote <proxy address>:%hu to begin debugging.\n",
379 		    proxy_port);
380 	} else {
381 		db_printf("Connected to proxy. "
382 		    "Use target remote %s:%hu to begin debugging.\n",
383 		    proxy_buf, proxy_port);
384 	}
385 #if 0
386 	/* Aspirational, but does not work reliably. */
387 	db_printf("(ctrl-c will return control to ddb)\n");
388 #endif
389 }
390 #endif /* DDB */
391