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$
.\"
.Dd April 18, 2021
.Dd August 19, 2021
.Dt BHYVE 8
.Os
.Sh NAME
@ -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.

View file

@ -1193,6 +1193,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)
{
@ -1256,11 +1280,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);
@ -1447,10 +1467,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)) {

View file

@ -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;
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);
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);
}

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_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__ */