git: fd8bed8b21b5 - stable/13 - byhve: add option to specify IP address for gdb

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Thu, 10 Nov 2022 21:02:22 UTC
The branch stable/13 has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=fd8bed8b21b5607dc1665de3344f0d371e2cce3b

commit fd8bed8b21b5607dc1665de3344f0d371e2cce3b
Author:     Mariusz Zaborski <oshogbo@FreeBSD.org>
AuthorDate: 2021-08-19 17:52:12 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2022-11-10 20:54:37 +0000

    byhve: add option to specify IP address for gdb
    
    Allow user to specify the IP address available for gdb debugger.
    
    Reviewed by:    jhb, grehan, rgrimes, bcr (man pages)
    Differential Revision:  https://reviews.freebsd.org/D29607
    
    (cherry picked from commit 2cdff9918e79dcd9bfcaa919b8364afa41cd1e02)
---
 usr.sbin/bhyve/bhyve.8    | 14 +++++++++----
 usr.sbin/bhyve/bhyverun.c | 35 ++++++++++++++++++++++++---------
 usr.sbin/bhyve/gdb.c      | 50 +++++++++++++++++++++++++++++++++++++----------
 usr.sbin/bhyve/gdb.h      |  2 +-
 4 files changed, 77 insertions(+), 24 deletions(-)

diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8
index 1de8c516b785..6d78ad872f63 100644
--- a/usr.sbin/bhyve/bhyve.8
+++ b/usr.sbin/bhyve/bhyve.8
@@ -137,16 +137,22 @@ Force
 .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.
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
index fec4ca29de80..e9fc3c98ddeb 100644
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -1186,6 +1186,30 @@ parse_simple_config_file(const char *path)
 	fclose(fp);
 }
 
+static void
+parse_gdb_options(char *optarg)
+{
+	const char *sport;
+	char *colon;
+
+	if (optarg[0] == 'w') {
+		set_config_bool("gdb.wait", true);
+		optarg++;
+	}
+
+	colon = strrchr(optarg, ':');
+	if (colon == NULL) {
+		sport = optarg;
+	} else {
+		*colon = '\0';
+		colon++;
+		sport = colon;
+		set_config_value("gdb.address", optarg);
+	}
+
+	set_config_value("gdb.port", sport);
+}
+
 static void
 set_defaults(void)
 {
@@ -1249,11 +1273,7 @@ main(int argc, char *argv[])
 			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);
+			parse_gdb_options(optarg);
 			break;
 		case 'k':
 			parse_simple_config_file(optarg);
@@ -1440,10 +1460,7 @@ main(int argc, char *argv[])
 	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);
 
 	if (lpc_bootrom()) {
 		if (vm_set_capability(ctx, BSP, VM_CAP_UNRESTRICTED_GUEST, 1)) {
diff --git a/usr.sbin/bhyve/gdb.c b/usr.sbin/bhyve/gdb.c
index dd6f19d476f0..40f226701a1a 100644
--- a/usr.sbin/bhyve/gdb.c
+++ b/usr.sbin/bhyve/gdb.c
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <netdb.h>
 #include <pthread.h>
 #include <pthread_np.h>
 #include <stdbool.h>
@@ -59,6 +60,7 @@ __FBSDID("$FreeBSD$");
 #include <vmmapi.h>
 
 #include "bhyverun.h"
+#include "config.h"
 #include "gdb.h"
 #include "mem.h"
 #include "mevent.h"
@@ -1818,12 +1820,35 @@ limit_gdb_socket(int s)
 #endif
 
 void
-init_gdb(struct vmctx *_ctx, int sport, bool wait)
+init_gdb(struct vmctx *_ctx)
 {
-	struct sockaddr_in sin;
 	int error, flags, optval, s;
+	struct addrinfo hints;
+	struct addrinfo *gdbaddr;
+	const char *saddr, *value;
+	char *sport;
+	bool wait;
+
+	value = get_config_value("gdb.port");
+	if (value == NULL)
+		return;
+	sport = strdup(value);
+	if (sport == NULL)
+		errx(4, "Failed to allocate memory");
+
+	wait = get_config_bool_default("gdb.wait", false);
+
+	saddr = get_config_value("gdb.address");
+	if (saddr == NULL) {
+#if defined(INET)
+		saddr = "0.0.0.0";
+#elif defined(INET6)
+		saddr = "[::]";
+#endif
+	}
 
-	debug("==> starting on %d, %swaiting\n", sport, wait ? "" : "not ");
+	debug("==> starting on %s:%s, %swaiting\n",
+	    saddr, sport, wait ? "" : "not ");
 
 	error = pthread_mutex_init(&gdb_lock, NULL);
 	if (error != 0)
@@ -1832,20 +1857,23 @@ init_gdb(struct vmctx *_ctx, int sport, bool wait)
 	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");
 
 	optval = 1;
 	(void)setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
 
-	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)
@@ -1874,4 +1902,6 @@ init_gdb(struct vmctx *_ctx, int sport, bool wait)
 #endif
 	mevent_add(s, EVF_READ, new_connection, NULL);
 	gdb_active = true;
+	freeaddrinfo(gdbaddr);
+	free(sport);
 }
diff --git a/usr.sbin/bhyve/gdb.h b/usr.sbin/bhyve/gdb.h
index 93396c1c6705..c5fa522c63e0 100644
--- a/usr.sbin/bhyve/gdb.h
+++ b/usr.sbin/bhyve/gdb.h
@@ -34,6 +34,6 @@ void	gdb_cpu_add(int vcpu);
 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);
 
 #endif /* !__GDB_H__ */