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