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", ¶ms); 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