Index: share/man/man4/ddb.4 =================================================================== --- share/man/man4/ddb.4 +++ share/man/man4/ddb.4 @@ -24,43 +24,9 @@ .\" any improvements or extensions that they make and grant Carnegie Mellon .\" the rights to redistribute these changes. .\" -.\" changed a \# to #, since groff choked on it. -.\" -.\" HISTORY -.\" ddb.4,v -.\" Revision 1.1 1993/07/15 18:41:02 brezak -.\" Man page for DDB -.\" -.\" Revision 2.6 92/04/08 08:52:57 rpd -.\" Changes from OSF. -.\" [92/01/17 14:19:22 jsb] -.\" Changes for OSF debugger modifications. -.\" [91/12/12 tak] -.\" -.\" Revision 2.5 91/06/25 13:50:22 rpd -.\" Added some watchpoint explanation. -.\" [91/06/25 rpd] -.\" -.\" Revision 2.4 91/06/17 15:47:31 jsb -.\" Added documentation for continue/c, match, search, and watchpoints. -.\" I've not actually explained what a watchpoint is; maybe Rich can -.\" do that (hint, hint). -.\" [91/06/17 10:58:08 jsb] -.\" -.\" Revision 2.3 91/05/14 17:04:23 mrt -.\" Correcting copyright -.\" -.\" Revision 2.2 91/02/14 14:10:06 mrt -.\" Changed to new Mach copyright -.\" [91/02/12 18:10:12 mrt] -.\" -.\" Revision 2.2 90/08/30 14:23:15 dbg -.\" Created. -.\" [90/08/30 dbg] -.\" .\" $FreeBSD$ .\" -.Dd November 30, 2018 +.Dd August 30, 2019 .Dt DDB 4 .Os .Sh NAME @@ -212,7 +178,12 @@ browse through the history buffer, and move the cursor within the current line. .Sh COMMANDS +.Ss COMMON DEBUGGER COMMANDS .Bl -tag -width indent -compact +.It Ic help +Print a short summary of the available commands and command +abbreviations. +.Pp .It Xo .Ic examine Ns Op Li / Ns Cm AISabcdghilmorsuxz ... .Oo Ar addr Oc Ns Op , Ns Ar count @@ -396,6 +367,9 @@ to get the default address of .Va dot . .Pp +.It Ic halt +Halt the system. +.Pp .It Ic watch Oo Ar addr Oc Ns Op , Ns Ar size Set a watchpoint for a region. Execution stops when an attempt to modify the region occurs. @@ -429,6 +403,20 @@ .It Ic dhwatch Oo Ar addr Oc Ns Op , Ns Ar size Delete specified hardware watchpoint. .Pp +.It Ic kill Ar sig pid +Send signal +.Ar sig +to process +.Ar pid . +The signal is acted on upon returning from the debugger. +This command can be used to kill a process causing resource contention +in the case of a hung system. +See +.Xr signal 3 +for a list of signals. +Note that the arguments are reversed relative to +.Xr kill 2 . +.Pp .It Ic step Ns Oo Li / Ns Cm p Oc Ns Op , Ns Ar count .It Ic s Ns Oo Li / Ns Cm p Oc Ns Op , Ns Ar count Single step @@ -529,6 +517,25 @@ argument limits the search. .\" .Pp +.It Ic reboot Op Ar seconds +.It Ic reset Op Ar seconds +Hard reset the system. +If the optional argument +.Ar seconds +is given, the debugger will wait for this long, at most a week, +before rebooting. +.Pp +.It Ic thread Ar addr | tid +Switch the debugger to the thread with ID +.Ar tid , +if the argument is a decimal number, or address +.Ar addr , +otherwise. +.El +.Pp +.Ss SPECIALIZED HELPER COMMANDS +.Pp +.Bl -tag -width indent -compact .It Xo .Ic findstack .Ar addr @@ -1143,46 +1150,35 @@ Shows information about lock acquisition coming from the .Xr witness 4 subsystem. -.\" +.El .Pp +.Ss OFFLINE DEBUGGING COMMANDS +.Bl -tag -width indent -compact .It Ic gdb -Toggles between remote GDB and DDB mode. +Switches to remote GDB mode. In remote GDB mode, another machine is required that runs .Xr gdb 1 using the remote debug feature, with a connection to the serial console port on the target machine. -Currently only available on the -i386 -architecture. -.Pp -.It Ic halt -Halt the system. -.Pp -.It Ic kill Ar sig pid -Send signal -.Ar sig -to process -.Ar pid . -The signal is acted on upon returning from the debugger. -This command can be used to kill a process causing resource contention -in the case of a hung system. -See -.Xr signal 3 -for a list of signals. -Note that the arguments are reversed relative to -.Xr kill 2 . -.Pp -.It Ic reboot Op Ar seconds -.It Ic reset Op Ar seconds -Hard reset the system. -If the optional argument -.Ar seconds -is given, the debugger will wait for this long, at most a week, -before rebooting. .Pp -.It Ic help -Print a short summary of the available commands and command -abbreviations. +.It Ic netdump Fl s Ar server Oo Fl g Ar gateway Oc Fl c Ar client Fl i Ar iface +Configure +.Xr netdump 4 +with the provided parameters, and immediately perform a netdump. +.Pp +There are some known limitations. +Principally, +.Xr netdump 4 +only supports IPv4 at this time. +The address arguments to the +.Ic netdump +command must be dotted decimal IPv4 addresses. +(Hostnames are not supported.) +At present, the command only works if the machine is in a panic state. +Finally, the +.Nm +.Ic netdump +command does not provide any way to configure compressed or encrypted dump. .Pp .It Ic capture on .It Ic capture off @@ -1255,13 +1251,6 @@ reports whether a textdump has been scheduled. .Ic textdump unset cancels a request to perform a textdump as the next kernel core dump. -.Pp -.It Ic thread Ar addr | tid -Switch the debugger to the thread with ID -.Ar tid , -if the argument is a decimal number, or address -.Ar addr , -otherwise. .El .Sh VARIABLES The debugger accesses registers and variables as Index: share/man/man4/netdump.4 =================================================================== --- share/man/man4/netdump.4 +++ share/man/man4/netdump.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 5, 2018 +.Dd August 30, 2019 .Dt NETDUMP 4 .Os .Sh NAME @@ -46,7 +46,10 @@ .Nm clients are configured using the .Xr dumpon 8 -utility. +utility or the +.Ic netdump +command in +.Xr ddb 4 . .Pp .Nm client messages consist of a fixed-size header followed by a variable-sized Index: sys/net/debugnet.h =================================================================== --- sys/net/debugnet.h +++ sys/net/debugnet.h @@ -177,6 +177,29 @@ */ void debugnet_any_ifnet_update(struct ifnet *); +/* + * DDB parsing helper for common debugnet options. + * + * -s [-g -i + * + * Order is not significant. Interface is an online interface that supports + * debugnet and can route to the debugnet server. The other parameters are all + * IP addresses. For now, all parameters are mandatory, except gateway. + * + * Provides basic '-h' using provided 'cmd' string. + * + * Returns zero on success, or errno. + */ +struct debugnet_ddb_config { + struct ifnet *dd_ifp; /* not ref'd */ + in_addr_t dd_client; + in_addr_t dd_server; + in_addr_t dd_gateway; + bool dd_has_gateway : 1; +}; +int debugnet_parse_ddb_cmd(const char *cmd, + struct debugnet_ddb_config *result); + /* Expose sysctl variables for netdump(4) to alias. */ extern int debugnet_npolls; extern int debugnet_nretries; Index: sys/net/debugnet.c =================================================================== --- sys/net/debugnet.c +++ sys/net/debugnet.c @@ -31,6 +31,7 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_ddb.h" #include "opt_inet.h" #include @@ -40,6 +41,11 @@ #include #include +#ifdef DDB +#include +#include +#endif + #include #include #include @@ -656,3 +662,226 @@ dn_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); } SYSINIT(dn_evh_init, SI_SUB_EVENTHANDLER + 1, SI_ORDER_ANY, dn_evh_init, NULL); + +/* + * DDB parsing helpers for debugnet(4) consumers. + */ +#ifdef DDB +struct my_inet_opt { + bool has_opt; + const char *printname; + in_addr_t *result; +}; + +static int +dn_parse_optarg_ipv4(struct my_inet_opt *opt) +{ + in_addr_t tmp; + unsigned octet; + int t; + + tmp = 0; + for (octet = 0; octet < 4; octet++) { + t = db_read_token(); + if (t != tNUMBER) { + db_printf("%s:%s: octet %u expected number; found %d\n", + __func__, opt->printname, octet, t); + return (EINVAL); + } + /* + * db_lex lexes '-' distinctly from the number itself, but + * let's document that invariant. + */ + MPASS(db_tok_number >= 0); + + if (db_tok_number > UINT8_MAX) { + db_printf("%s:%s: octet %u out of range: %ld\n", __func__, + opt->printname, octet, db_tok_number); + return (EDOM); + } + + /* Constructed host-endian and converted to network later. */ + tmp = (tmp << 8) | db_tok_number; + + if (octet < 3) { + t = db_read_token(); + if (t != tDOT) { + db_printf("%s:%s: octet %u expected '.'; found" + " %d\n", __func__, opt->printname, octet, + t); + return (EINVAL); + } + } + } + + *opt->result = htonl(tmp); + opt->has_opt = true; + return (0); +} + +int +debugnet_parse_ddb_cmd(const char *cmd, struct debugnet_ddb_config *result) +{ + struct ifnet *ifp; + int t, error; + bool want_ifp; + char ch; + + /* Assume v4, dotted decimal encoding for now. */ + db_cmd_radix = 10; + + struct my_inet_opt opt_client = { + .printname = "client", + .result = &result->dd_client, + }, + opt_server = { + .printname = "server", + .result = &result->dd_server, + }, + opt_gateway = { + .printname = "gateway", + .result = &result->dd_gateway, + }, + *cur_inet_opt; + + ifp = NULL; + memset(result, 0, sizeof(*result)); + + /* + * command [space] [-] [opt] [[space] [optarg]] ... + * + * db_command has already lexed 'command' for us. + */ + t = db_read_token(); + if (t == tWSPACE) + t = db_read_token(); + + while (t != tEOL) { + if (t != tMINUS) { + db_printf("%s: Bad syntax; expected '-', got %d\n", + cmd, t); + goto usage; + } + + t = db_read_token(); + if (t != tIDENT) { + db_printf("%s: Bad syntax; expected tIDENT, got %d\n", + cmd, t); + goto usage; + } + + if (strlen(db_tok_string) > 1) { + db_printf("%s: Bad syntax; expected single option " + "flag, got '%s'\n", cmd, db_tok_string); + goto usage; + } + + want_ifp = false; + cur_inet_opt = NULL; + switch ((ch = db_tok_string[0])) { + default: + DNETDEBUG("Unexpected: '%c'\n", ch); + /* FALLTHROUGH */ + case 'h': + goto usage; + case 'c': + cur_inet_opt = &opt_client; + break; + case 'g': + cur_inet_opt = &opt_gateway; + break; + case 's': + cur_inet_opt = &opt_server; + break; + case 'i': + want_ifp = true; + break; + } + + t = db_read_token(); + if (t != tWSPACE) { + db_printf("%s: Bad syntax; expected space after " + "flag %c, got %d\n", cmd, ch, t); + goto usage; + } + + if (want_ifp) { + t = db_read_token(); + if (t != tIDENT) { + db_printf("%s: Expected interface but got %d\n", + cmd, t); + goto usage; + } + + CURVNET_SET(vnet0); + /* + * We *don't* take a ref here because the only current + * consumer, db_netdump_cmd, does not need it. It + * (somewhat redundantly) extracts the if_name(), + * re-lookups the ifp, and takes its own reference. + */ + ifp = ifunit(db_tok_string); + CURVNET_RESTORE(); + if (ifp == NULL) { + db_printf("Could not locate interface %s\n", + db_tok_string); + goto cleanup; + } + } else { + MPASS(cur_inet_opt != NULL); + /* Assume IPv4 for now. */ + error = dn_parse_optarg_ipv4(cur_inet_opt); + if (error != 0) + goto cleanup; + } + + /* Skip (mandatory) whitespace after option, if not EOL. */ + t = db_read_token(); + if (t == tEOL) + break; + if (t != tWSPACE) { + db_printf("%s: Bad syntax; expected space after " + "flag %c option; got %d\n", cmd, ch, t); + goto usage; + } + t = db_read_token(); + } + + /* Currently, all three are required. */ + if (!opt_client.has_opt || !opt_server.has_opt || ifp == NULL) { + db_printf("%s needs all of client, server, and interface " + "specified.\n", cmd); + goto usage; + } + + result->dd_has_gateway = opt_gateway.has_opt; + + /* Iface validation stolen from netdump_configure. */ + if ((if_getflags(ifp) & IFF_UP) == 0) { + db_printf("%s: interface '%s' link is down\n", cmd, + if_name(ifp)); + error = ENXIO; + goto cleanup; + } + if (!DEBUGNET_SUPPORTED_NIC(ifp)) { + db_printf("%s: interface '%s' does not support debugnet\n", + cmd, if_name(ifp)); + error = ENODEV; + goto cleanup; + } + + result->dd_ifp = ifp; + + /* We parsed the full line to tEOL already, or bailed with an error. */ + return (0); + +usage: + db_printf("Usage: %s -s [-g ] -c " + "-i \n", cmd); + error = EINVAL; + /* FALLTHROUGH */ +cleanup: + db_skip_to_eol(); + return (error); +} +#endif /* DDB */ Index: sys/netinet/netdump/netdump_client.c =================================================================== --- sys/netinet/netdump/netdump_client.c +++ sys/netinet/netdump/netdump_client.c @@ -34,6 +34,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_ddb.h" + #include #include #include @@ -52,6 +54,11 @@ #include #include +#ifdef DDB +#include +#include +#endif + #include #include #include @@ -730,3 +737,72 @@ MODULE_VERSION(netdump, 1); DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); + +#ifdef DDB +/* + * Usage: netdump -s [-g -i + * + * Order is not significant. + * + * Currently, this command does not support configuring encryption or + * compression. + */ +DB_FUNC(netdump, db_netdump_cmd, db_cmd_table, CS_OWN | CS_LEX_SPACE, NULL) +{ + static struct diocskerneldump_arg conf; + static char blockbuf[NETDUMP_DATASIZE]; + static union { + struct dumperinfo di; + /* For valid di_devname. */ + char di_buf[sizeof(struct dumperinfo) + 1]; + } u; + + struct debugnet_ddb_config params; + int error; + + error = debugnet_parse_ddb_cmd("netdump", ¶ms); + if (error != 0) { + db_printf("Error configuring netdump: %d\n", error); + return; + } + + /* Translate to a netdump dumper config. */ + memset(&conf, 0, sizeof(conf)); + strlcpy(conf.kda_iface, if_name(params.dd_ifp), sizeof(conf.kda_iface)); + + conf.kda_af = AF_INET; + conf.kda_server.in4 = (struct in_addr) { params.dd_server }; + conf.kda_client.in4 = (struct in_addr) { params.dd_client }; + if (params.dd_has_gateway) + conf.kda_gateway.in4 = (struct in_addr) { params.dd_gateway }; + else + conf.kda_gateway.in4 = (struct in_addr) { INADDR_ANY }; + + /* Set the global netdump config to these options. */ + error = netdump_configure(&conf, curthread); + if (error != 0) { + db_printf("Error enabling netdump: %d\n", error); + return; + } + + /* Fake the generic dump configuration list entry to avoid malloc. */ + memset(&u.di_buf, 0, sizeof(u.di_buf)); + u.di.dumper_start = netdump_start; + u.di.dumper_hdr = netdump_write_headers; + u.di.dumper = netdump_dumper; + u.di.priv = NULL; + u.di.blocksize = NETDUMP_DATASIZE; + u.di.maxiosize = MAXDUMPPGS * PAGE_SIZE; + u.di.mediaoffset = 0; + u.di.mediasize = 0; + u.di.blockbuf = blockbuf; + + dumper_ddb_insert_static(&u.di); + + error = doadump(false); + + dumper_ddb_remove_static(&u.di); + if (error != 0) + db_printf("Cannot dump: %d", error); +} +#endif /* DDB */