From nobody Wed Feb 21 00:52:40 2024 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Tfd6J6sT2z5B1vZ; Wed, 21 Feb 2024 00:52:40 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Tfd6J6ZZJz4HDp; Wed, 21 Feb 2024 00:52:40 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1708476760; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=RDS/XdzhVIMaU1czgLA1+zlUP+SACDcq2uDl0NqMLd4=; b=P9NGzSdIh3gRSjBk0YMqGUjrQFBRYVCNHb5hA/aXRkETHi7I8j5Gb5m87aMjQzUsssL1hq N2GNpAxUHrujtAnJzdnNTQp3HfB0O+2Z9xlJJQTsBGvLq+j4ZBOEX7V/4oXfOPYElWQkUl 7F3EE6rRQVsf74e7tyHcGJBJMjXsEPb2sVHKV6YqMCv1WnS3s+cYwgMSaYx5l9YN0WGRwS Fp11L+Lfz9x9FuPACuyNK7MEwa8F2WaV9EvS3DLgrfLl1Aluvbsu4I5jKDE7RGwJnqbQsv T96KrlLCwGmJ/8wFHj1pR8pTHvqju0Z6l2+NyXKUusM/+US8uY5iUDIJGfu/8Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1708476760; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=RDS/XdzhVIMaU1czgLA1+zlUP+SACDcq2uDl0NqMLd4=; b=Kn9rFOpEPJHqSwKoCGrcso6zQHeiXewgn8Sc/zwb4iAmSCnOV+v3a+DHP5BSBYIGoq8LTn WUyfQwYYKRFur4vrzcS189CyTMuv8Y4hg0bSxjFMbQTnJc9dtPpcB8QpjcctJHIs8ame0P q/Blu5Yak08ZWZ+65+aZUKFppQrUG16jo4MpgOe4vfQqEcQBStiEgGx3pADsYlZrtpmz1r xP7RdvQLbOCyU/wdVA9b6xcVblO4MCHsD92kpAtAhmZ8rh0Yy8z/OyBM0EDdjbQOTzeUiG wj7aTzyjm25YPjO2xKtlkSaXYfXW/iUxBL9+EvbHbKuXmynxsHKmwhIl1Emp8Q== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1708476760; a=rsa-sha256; cv=none; b=JnfCSHjw+9FeZo61We/xcPIW5WuvWtuTKoXsN5Jy+6edx8DoGy4cmsOLUgZpZHHsSa/hWc 1RAR6PZeaKUjj6yrQ0RC6ekPaKIWmfLIhdl4qm/0LqhP97Jq4Nhtp8lAyxjAdOq0wmvKwt JiAP7o4mU0wLlm1ObzKLgcB00vEHrnWScKnvJ58bCI4Yl6T0XqOrRBRClLCxPsVKCfkIX/ UxSM7fmZPDCeKKiDYk8Do8d1bny7nvw4rJESwfEm8hseK1XgufNVORaXf2aqQWR1/V91Yj OQXVEzdTJ/BtUTM2J7TCthMIvgRT+eJoSMxluqk1EBPIhScdBAFBbNToHhJrUQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Tfd6J5Jv9zhZ0; Wed, 21 Feb 2024 00:52:40 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 41L0qeGw049518; Wed, 21 Feb 2024 00:52:40 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 41L0qepV049515; Wed, 21 Feb 2024 00:52:40 GMT (envelope-from git) Date: Wed, 21 Feb 2024 00:52:40 GMT Message-Id: <202402210052.41L0qepV049515@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Mark Johnston Subject: git: f81cdf24ba54 - main - bhyve: Add support for XML register definitions List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: f81cdf24ba5436367377f7c8e8f51f6df2a75ca7 Auto-Submitted: auto-generated The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=f81cdf24ba5436367377f7c8e8f51f6df2a75ca7 commit f81cdf24ba5436367377f7c8e8f51f6df2a75ca7 Author: Mark Johnston AuthorDate: 2024-02-21 00:21:29 +0000 Commit: Mark Johnston CommitDate: 2024-02-21 00:51:34 +0000 bhyve: Add support for XML register definitions This is useful for exposing additional registers to debuggers. For instance, control registers are now available on amd64 when using gdb to debug a guest. The stub indicates support by including the string "qXfer:features:read+" in its feature list. The debugger queries for target descriptions by sending the query "qXfer:features:read:" followed by a file path. The XML definitions are copied from QEMU and installed to /usr/share/bhyve/gdb. Note that we currently don't handle the SIMD registers at all, since that's of somewhat limited utility (for me at least) and since that requires new ioctls to fetch the register values. Reviewed by: jhb MFC after: 2 weeks Sponsored by: Innovate UK Differential Revision: https://reviews.freebsd.org/D43666 --- etc/mtree/BSD.usr.dist | 2 + usr.sbin/bhyve/Makefile | 1 + usr.sbin/bhyve/gdb.c | 106 ++++++++++++++++++++++++++- usr.sbin/bhyve/gdb/Makefile | 21 ++++++ usr.sbin/bhyve/gdb/amd64.xml | 165 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 294 insertions(+), 1 deletion(-) diff --git a/etc/mtree/BSD.usr.dist b/etc/mtree/BSD.usr.dist index a7738aaf6f78..0d43b657530b 100644 --- a/etc/mtree/BSD.usr.dist +++ b/etc/mtree/BSD.usr.dist @@ -184,6 +184,8 @@ atf tags=package=tests .. bhyve + gdb + .. kbdlayout .. .. diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile index b6cad38a6c39..c9d571daebbc 100644 --- a/usr.sbin/bhyve/Makefile +++ b/usr.sbin/bhyve/Makefile @@ -75,6 +75,7 @@ CFLAGS+= -DBHYVE_GDB .ifdef GDB_LOG CFLAGS+=-DGDB_LOG .endif +SUBDIR+= gdb .endif CFLAGS+=-I${.CURDIR} \ diff --git a/usr.sbin/bhyve/gdb.c b/usr.sbin/bhyve/gdb.c index 84e725f9085e..fbd62413e2c2 100644 --- a/usr.sbin/bhyve/gdb.c +++ b/usr.sbin/bhyve/gdb.c @@ -34,6 +34,8 @@ #include #include #include +#include + #include #include #include @@ -63,6 +65,8 @@ #include "mem.h" #include "mevent.h" +#define _PATH_GDB_XML "/usr/share/bhyve/gdb" + /* * GDB_SIGNAL_* numbers are part of the GDB remote protocol. Most stops * use SIGTRAP. @@ -85,6 +89,7 @@ static cpuset_t vcpus_active, vcpus_suspended, vcpus_waiting; static pthread_mutex_t gdb_lock; static pthread_cond_t idle_vcpus; static bool first_stop, report_next_stop, swbreak_enabled; +static int xml_dfd = -1; /* * An I/O buffer contains 'capacity' bytes of room at 'data'. For a @@ -169,8 +174,25 @@ static const struct gdb_reg { { .id = VM_REG_GUEST_ES, .size = 4 }, { .id = VM_REG_GUEST_FS, .size = 4 }, { .id = VM_REG_GUEST_GS, .size = 4 }, + /* + * Registers past this point are not included in a reply to a 'g' query, + * to provide compatibility with debuggers that do not fetch a target + * description. The debugger can query them individually with 'p' if it + * knows about them. + */ +#define GDB_REG_FIRST_EXT VM_REG_GUEST_FS_BASE + { .id = VM_REG_GUEST_FS_BASE, .size = 8 }, + { .id = VM_REG_GUEST_GS_BASE, .size = 8 }, + { .id = VM_REG_GUEST_KGS_BASE, .size = 8 }, + { .id = VM_REG_GUEST_CR0, .size = 8 }, + { .id = VM_REG_GUEST_CR2, .size = 8 }, + { .id = VM_REG_GUEST_CR3, .size = 8 }, + { .id = VM_REG_GUEST_CR4, .size = 8 }, + { .id = VM_REG_GUEST_TPR, .size = 8 }, + { .id = VM_REG_GUEST_EFER, .size = 8 }, }; +#define GDB_LOG #ifdef GDB_LOG #include #include @@ -1029,9 +1051,13 @@ gdb_read_regs(void) send_error(errno); return; } + start_packet(); - for (size_t i = 0; i < nitems(gdb_regset); i++) + for (size_t i = 0; i < nitems(gdb_regset); i++) { + if (gdb_regset[i].id == GDB_REG_FIRST_EXT) + break; append_unsigned_native(regvals[i], gdb_regset[i].size); + } finish_packet(); } @@ -1519,6 +1545,7 @@ check_features(const uint8_t *data, size_t len) /* This is an arbitrary limit. */ append_string("PacketSize=4096"); append_string(";swbreak+"); + append_string(";qXfer:features:read+"); finish_packet(); } @@ -1590,6 +1617,71 @@ gdb_query(const uint8_t *data, size_t len) start_packet(); append_asciihex(buf); finish_packet(); + } else if (command_equals(data, len, "qXfer:features:read:")) { + struct stat sb; + const char *xml; + const uint8_t *pathend; + char buf[64], path[PATH_MAX]; + size_t xmllen; + unsigned int doff, dlen; + int fd; + + data += strlen("qXfer:features:read:"); + len -= strlen("qXfer:features:read:"); + + pathend = memchr(data, ':', len); + if (pathend == NULL || + (size_t)(pathend - data) >= sizeof(path) - 1) { + send_error(EINVAL); + return; + } + memcpy(path, data, pathend - data); + path[pathend - data] = '\0'; + data += (pathend - data) + 1; + len -= (pathend - data) + 1; + + if (len > sizeof(buf) - 1) { + send_error(EINVAL); + return; + } + memcpy(buf, data, len); + buf[len] = '\0'; + if (sscanf(buf, "%x,%x", &doff, &dlen) != 2) { + send_error(EINVAL); + return; + } + + fd = openat(xml_dfd, path, O_RDONLY | O_RESOLVE_BENEATH); + if (fd < 0) { + send_error(errno); + return; + } + if (fstat(fd, &sb) < 0) { + send_error(errno); + close(fd); + return; + } + xml = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (xml == MAP_FAILED) { + send_error(errno); + close(fd); + return; + } + close(fd); + xmllen = sb.st_size; + + start_packet(); + if (doff >= xmllen) { + append_char('l'); + } else if (doff + dlen >= xmllen) { + append_char('l'); + append_packet_data(xml + doff, xmllen - doff); + } else { + append_char('m'); + append_packet_data(xml + doff, dlen); + } + finish_packet(); + (void)munmap(__DECONST(void *, xml), xmllen); } else send_empty_response(); } @@ -1917,6 +2009,9 @@ limit_gdb_socket(int s) void init_gdb(struct vmctx *_ctx) { +#ifndef WITHOUT_CAPSICUM + cap_rights_t rights; +#endif int error, flags, optval, s; struct addrinfo hints; struct addrinfo *gdbaddr; @@ -1997,4 +2092,13 @@ init_gdb(struct vmctx *_ctx) gdb_active = true; freeaddrinfo(gdbaddr); free(sport); + + xml_dfd = open(_PATH_GDB_XML, O_DIRECTORY); + if (xml_dfd == -1) + err(1, "Failed to open gdb xml directory"); +#ifndef WITHOUT_CAPSICUM + cap_rights_init(&rights, CAP_FSTAT, CAP_LOOKUP, CAP_MMAP_R, CAP_PREAD); + if (caph_rights_limit(xml_dfd, &rights) == -1) + err(1, "cap_rights_init"); +#endif } diff --git a/usr.sbin/bhyve/gdb/Makefile b/usr.sbin/bhyve/gdb/Makefile new file mode 100644 index 000000000000..a444b0cc4c69 --- /dev/null +++ b/usr.sbin/bhyve/gdb/Makefile @@ -0,0 +1,21 @@ +PACKAGE= bhyve +FILESDIR= ${SHAREDIR}/bhyve/gdb + +FILES+= target.xml + +.if ${MACHINE_ARCH} == "amd64" +XMLARCH= i386:x86-64 +FILES+= amd64.xml +.endif + +target.xml: .PHONY + @echo "" > ${.TARGET} + @echo "" >> ${.TARGET} + @echo "" >> ${.TARGET} + @echo " ${XMLARCH}" >> ${.TARGET} +.for file in ${FILES:Ntarget.xml} + @echo " " >> ${.TARGET} +.endfor + @echo "" >> ${.TARGET} + +.include diff --git a/usr.sbin/bhyve/gdb/amd64.xml b/usr.sbin/bhyve/gdb/amd64.xml new file mode 100644 index 000000000000..15bd270120d8 --- /dev/null +++ b/usr.sbin/bhyve/gdb/amd64.xml @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +