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