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
This commit is contained in:
Mariusz Zaborski 2021-08-19 19:52:12 +02:00
parent c541bd368f
commit 2cdff9918e
4 changed files with 78 additions and 25 deletions

View file

@ -24,7 +24,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd April 18, 2021 .Dd August 19, 2021
.Dt BHYVE 8 .Dt BHYVE 8
.Os .Os
.Sh NAME .Sh NAME
@ -137,16 +137,22 @@ Force
.Nm .Nm
to exit when a guest issues an access to an I/O port that is not emulated. to exit when a guest issues an access to an I/O port that is not emulated.
This is intended for debug purposes. 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 Start a debug server that uses the GDB protocol to export guest state to a
debugger. debugger.
An IPv4 TCP socket will be bound to the supplied An IPv4 TCP socket will be bound to the supplied
.Ar bind_address
and
.Ar port .Ar port
to listen for debugger connections. to listen for debugger connections.
Only a single debugger may be attached to the debug server at a time. Only a single debugger may be attached to the debug server at a time.
If If the option begins with
.Ar port
begins with
.Sq w , .Sq w ,
.Nm .Nm
will pause execution at the first instruction waiting for a debugger to attach. will pause execution at the first instruction waiting for a debugger to attach.

View file

@ -1193,6 +1193,30 @@ parse_simple_config_file(const char *path)
fclose(fp); 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 static void
set_defaults(void) set_defaults(void)
{ {
@ -1256,11 +1280,7 @@ main(int argc, char *argv[])
set_config_bool("memory.guest_in_core", true); set_config_bool("memory.guest_in_core", true);
break; break;
case 'G': case 'G':
if (optarg[0] == 'w') { parse_gdb_options(optarg);
set_config_bool("gdb.wait", true);
optarg++;
}
set_config_value("gdb.port", optarg);
break; break;
case 'k': case 'k':
parse_simple_config_file(optarg); parse_simple_config_file(optarg);
@ -1447,10 +1467,7 @@ main(int argc, char *argv[])
if (get_config_bool("acpi_tables")) if (get_config_bool("acpi_tables"))
vmgenc_init(ctx); vmgenc_init(ctx);
value = get_config_value("gdb.port"); init_gdb(ctx);
if (value != NULL)
init_gdb(ctx, atoi(value), get_config_bool_default("gdb.wait",
false));
if (lpc_bootrom()) { if (lpc_bootrom()) {
if (vm_set_capability(ctx, BSP, VM_CAP_UNRESTRICTED_GUEST, 1)) { if (vm_set_capability(ctx, BSP, VM_CAP_UNRESTRICTED_GUEST, 1)) {

View file

@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <netdb.h>
#include <pthread.h> #include <pthread.h>
#include <pthread_np.h> #include <pthread_np.h>
#include <stdbool.h> #include <stdbool.h>
@ -59,6 +60,7 @@ __FBSDID("$FreeBSD$");
#include <vmmapi.h> #include <vmmapi.h>
#include "bhyverun.h" #include "bhyverun.h"
#include "config.h"
#include "gdb.h" #include "gdb.h"
#include "mem.h" #include "mem.h"
#include "mevent.h" #include "mevent.h"
@ -1818,12 +1820,35 @@ limit_gdb_socket(int s)
#endif #endif
void void
init_gdb(struct vmctx *_ctx, int sport, bool wait) init_gdb(struct vmctx *_ctx)
{ {
struct sockaddr_in sin;
int error, flags, optval, s; int error, flags, optval, s;
struct addrinfo hints;
struct addrinfo *gdbaddr;
const char *saddr, *value;
char *sport;
bool wait;
debug("==> starting on %d, %swaiting\n", sport, wait ? "" : "not "); 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 %s:%s, %swaiting\n",
saddr, sport, wait ? "" : "not ");
error = pthread_mutex_init(&gdb_lock, NULL); error = pthread_mutex_init(&gdb_lock, NULL);
if (error != 0) if (error != 0)
@ -1832,20 +1857,23 @@ init_gdb(struct vmctx *_ctx, int sport, bool wait)
if (error != 0) if (error != 0)
errc(1, error, "gdb cv init"); 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; ctx = _ctx;
s = socket(PF_INET, SOCK_STREAM, 0); s = socket(gdbaddr->ai_family, gdbaddr->ai_socktype, 0);
if (s < 0) if (s < 0)
err(1, "gdb socket create"); err(1, "gdb socket create");
optval = 1; optval = 1;
(void)setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); (void)setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
sin.sin_len = sizeof(sin); if (bind(s, gdbaddr->ai_addr, gdbaddr->ai_addrlen) < 0)
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)
err(1, "gdb socket bind"); err(1, "gdb socket bind");
if (listen(s, 1) < 0) if (listen(s, 1) < 0)
@ -1874,4 +1902,6 @@ init_gdb(struct vmctx *_ctx, int sport, bool wait)
#endif #endif
mevent_add(s, EVF_READ, new_connection, NULL); mevent_add(s, EVF_READ, new_connection, NULL);
gdb_active = true; gdb_active = true;
freeaddrinfo(gdbaddr);
free(sport);
} }

View file

@ -34,6 +34,6 @@ void gdb_cpu_add(int vcpu);
void gdb_cpu_breakpoint(int vcpu, struct vm_exit *vmexit); void gdb_cpu_breakpoint(int vcpu, struct vm_exit *vmexit);
void gdb_cpu_mtrap(int vcpu); void gdb_cpu_mtrap(int vcpu);
void gdb_cpu_suspend(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__ */ #endif /* !__GDB_H__ */