Index: usr.sbin/bhyve/bhyve.8 =================================================================== --- usr.sbin/bhyve/bhyve.8 +++ usr.sbin/bhyve/bhyve.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 18, 2021 +.Dd April 6, 2021 .Dt BHYVE 8 .Os .Sh NAME @@ -133,16 +133,22 @@ .Nm to exit when a guest issues an access to an I/O port that is not emulated. This is intended for debug purposes. -.It Fl G Ar port +.It Fl G Xo +.Sm off +.Oo Ar w Oc +.Oo Ar bind_address: Oc +.Ar port +.Sm on +.Xc Start a debug server that uses the GDB protocol to export guest state to a debugger. An IPv4 TCP socket will be bound to the supplied +.Ar bind_address +and .Ar port to listen for debugger connections. Only a single debugger may be attached to the debug server at a time. -If -.Ar port -begins with +If the option begins with .Sq w , .Nm will pause execution at the first instruction waiting for a debugger to attach. Index: usr.sbin/bhyve/bhyverun.c =================================================================== --- usr.sbin/bhyve/bhyverun.c +++ usr.sbin/bhyve/bhyverun.c @@ -1255,11 +1255,7 @@ set_config_bool("memory.guest_in_core", true); break; case 'G': - if (optarg[0] == 'w') { - set_config_bool("gdb.wait", true); - optarg++; - } - set_config_value("gdb.port", optarg); + set_config_value("gdb.address", optarg); break; case 'k': parse_simple_config_file(optarg); @@ -1446,10 +1442,7 @@ if (get_config_bool("acpi_tables")) vmgenc_init(ctx); - value = get_config_value("gdb.port"); - if (value != NULL) - init_gdb(ctx, atoi(value), get_config_bool_default("gdb.wait", - false)); + init_gdb(ctx, get_config_value("gdb.address")); if (lpc_bootrom()) { if (vm_set_capability(ctx, BSP, VM_CAP_UNRESTRICTED_GUEST, 1)) { Index: usr.sbin/bhyve/gdb.h =================================================================== --- usr.sbin/bhyve/gdb.h +++ usr.sbin/bhyve/gdb.h @@ -34,6 +34,6 @@ void gdb_cpu_breakpoint(int vcpu, struct vm_exit *vmexit); void gdb_cpu_mtrap(int vcpu); void gdb_cpu_suspend(int vcpu); -void init_gdb(struct vmctx *ctx, int sport, bool wait); +void init_gdb(struct vmctx *ctx, const char *optarg); #endif /* !__GDB_H__ */ Index: usr.sbin/bhyve/gdb.c =================================================================== --- usr.sbin/bhyve/gdb.c +++ usr.sbin/bhyve/gdb.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -1817,13 +1818,60 @@ } #endif +static void +parse_gdb_options(char *optarg, const char **saddr, const char **sport, bool *wait) +{ + char *colon; + + if (optarg[0] == 'w') { + *wait = true; + optarg++; + } else { + *wait = false; + } + + colon = strrchr(optarg, ':'); + if (colon == NULL) { + *saddr = NULL; + *sport = optarg; + return; + } + + *colon = '\0'; + colon++; + *saddr = optarg; + *sport = colon; +} + void -init_gdb(struct vmctx *_ctx, int sport, bool wait) +init_gdb(struct vmctx *_ctx, const char *optarg) { - struct sockaddr_in sin; int error, flags, s; + struct addrinfo hints; + struct addrinfo *gdbaddr; + const char *saddr, *sport; + bool wait; + char *str; - debug("==> starting on %d, %swaiting\n", sport, wait ? "" : "not "); + if (optarg == NULL) + return; + + str = strdup(optarg); + if (str == NULL) + errx(4, "Failed to allocate memory"); + + parse_gdb_options(str, &saddr, &sport, &wait); + + if (!saddr) { +#if defined(INET) + saddr = "0.0.0.0"; +#elif defined(INET6) + saddr = "[::]"; +#endif + } + + debug("==> starting on %s:%s, %swaiting\n", + saddr, sport, wait ? "" : "not "); error = pthread_mutex_init(&gdb_lock, NULL); if (error != 0) @@ -1832,17 +1880,20 @@ if (error != 0) errc(1, error, "gdb cv init"); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE; + + if (getaddrinfo(saddr, sport, &hints, &gdbaddr) != 0) + err(1, "gdb address resolve"); + ctx = _ctx; - s = socket(PF_INET, SOCK_STREAM, 0); + s = socket(gdbaddr->ai_family, gdbaddr->ai_socktype, 0); if (s < 0) err(1, "gdb socket create"); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(INADDR_ANY); - sin.sin_port = htons(sport); - - if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) + if (bind(s, gdbaddr->ai_addr, gdbaddr->ai_addrlen) < 0) err(1, "gdb socket bind"); if (listen(s, 1) < 0) @@ -1871,4 +1922,6 @@ #endif mevent_add(s, EVF_READ, new_connection, NULL); gdb_active = true; + freeaddrinfo(gdbaddr); + free(str); }