xref: /illumos-gate/usr/src/cmd/bhyve/gdb.c (revision 32640292339b07090f10ce34d455f98711077343)
14c87aefeSPatrick Mooney /*-
2*32640292SAndy Fiddaman  * SPDX-License-Identifier: BSD-2-Clause
34c87aefeSPatrick Mooney  *
44c87aefeSPatrick Mooney  * Copyright (c) 2017-2018 John H. Baldwin <jhb@FreeBSD.org>
54c87aefeSPatrick Mooney  *
64c87aefeSPatrick Mooney  * Redistribution and use in source and binary forms, with or without
74c87aefeSPatrick Mooney  * modification, are permitted provided that the following conditions
84c87aefeSPatrick Mooney  * are met:
94c87aefeSPatrick Mooney  * 1. Redistributions of source code must retain the above copyright
104c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer.
114c87aefeSPatrick Mooney  * 2. Redistributions in binary form must reproduce the above copyright
124c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer in the
134c87aefeSPatrick Mooney  *    documentation and/or other materials provided with the distribution.
144c87aefeSPatrick Mooney  *
154c87aefeSPatrick Mooney  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
164c87aefeSPatrick Mooney  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
174c87aefeSPatrick Mooney  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
184c87aefeSPatrick Mooney  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
194c87aefeSPatrick Mooney  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
204c87aefeSPatrick Mooney  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
214c87aefeSPatrick Mooney  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
224c87aefeSPatrick Mooney  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
234c87aefeSPatrick Mooney  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
244c87aefeSPatrick Mooney  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
254c87aefeSPatrick Mooney  * SUCH DAMAGE.
264c87aefeSPatrick Mooney  */
274c87aefeSPatrick Mooney 
284c87aefeSPatrick Mooney #include <sys/cdefs.h>
294c87aefeSPatrick Mooney 
304c87aefeSPatrick Mooney #include <sys/param.h>
314c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
324c87aefeSPatrick Mooney #include <sys/capsicum.h>
334c87aefeSPatrick Mooney #endif
3484659b24SMichael Zeller #ifdef __FreeBSD__
3584659b24SMichael Zeller #include <sys/endian.h>
3684659b24SMichael Zeller #else
3784659b24SMichael Zeller #include <endian.h>
3884659b24SMichael Zeller #endif
394c87aefeSPatrick Mooney #include <sys/ioctl.h>
404c87aefeSPatrick Mooney #include <sys/mman.h>
41154972afSPatrick Mooney #include <sys/queue.h>
424c87aefeSPatrick Mooney #include <sys/socket.h>
434c87aefeSPatrick Mooney #include <machine/atomic.h>
444c87aefeSPatrick Mooney #include <machine/specialreg.h>
454c87aefeSPatrick Mooney #include <machine/vmm.h>
464c87aefeSPatrick Mooney #include <netinet/in.h>
474c87aefeSPatrick Mooney #include <assert.h>
484c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
494c87aefeSPatrick Mooney #include <capsicum_helpers.h>
504c87aefeSPatrick Mooney #endif
514c87aefeSPatrick Mooney #include <err.h>
524c87aefeSPatrick Mooney #include <errno.h>
534c87aefeSPatrick Mooney #include <fcntl.h>
54b0de25cbSAndy Fiddaman #include <netdb.h>
554c87aefeSPatrick Mooney #include <pthread.h>
564c87aefeSPatrick Mooney #include <pthread_np.h>
574c87aefeSPatrick Mooney #include <stdbool.h>
584c87aefeSPatrick Mooney #include <stdio.h>
594c87aefeSPatrick Mooney #include <stdlib.h>
604c87aefeSPatrick Mooney #include <string.h>
614c87aefeSPatrick Mooney #include <sysexits.h>
624c87aefeSPatrick Mooney #include <unistd.h>
634c87aefeSPatrick Mooney #include <vmmapi.h>
644c87aefeSPatrick Mooney 
654c87aefeSPatrick Mooney #include "bhyverun.h"
66b0de25cbSAndy Fiddaman #include "config.h"
67154972afSPatrick Mooney #include "gdb.h"
684c87aefeSPatrick Mooney #include "mem.h"
694c87aefeSPatrick Mooney #include "mevent.h"
704c87aefeSPatrick Mooney 
714c87aefeSPatrick Mooney /*
724c87aefeSPatrick Mooney  * GDB_SIGNAL_* numbers are part of the GDB remote protocol.  Most stops
734c87aefeSPatrick Mooney  * use SIGTRAP.
744c87aefeSPatrick Mooney  */
754c87aefeSPatrick Mooney #define	GDB_SIGNAL_TRAP		5
764c87aefeSPatrick Mooney 
774c87aefeSPatrick Mooney static void gdb_resume_vcpus(void);
784c87aefeSPatrick Mooney static void check_command(int fd);
794c87aefeSPatrick Mooney 
804c87aefeSPatrick Mooney static struct mevent *read_event, *write_event;
814c87aefeSPatrick Mooney 
824c87aefeSPatrick Mooney static cpuset_t vcpus_active, vcpus_suspended, vcpus_waiting;
834c87aefeSPatrick Mooney static pthread_mutex_t gdb_lock;
844c87aefeSPatrick Mooney static pthread_cond_t idle_vcpus;
85154972afSPatrick Mooney static bool first_stop, report_next_stop, swbreak_enabled;
864c87aefeSPatrick Mooney 
874c87aefeSPatrick Mooney /*
884c87aefeSPatrick Mooney  * An I/O buffer contains 'capacity' bytes of room at 'data'.  For a
894c87aefeSPatrick Mooney  * read buffer, 'start' is unused and 'len' contains the number of
904c87aefeSPatrick Mooney  * valid bytes in the buffer.  For a write buffer, 'start' is set to
914c87aefeSPatrick Mooney  * the index of the next byte in 'data' to send, and 'len' contains
924c87aefeSPatrick Mooney  * the remaining number of valid bytes to send.
934c87aefeSPatrick Mooney  */
944c87aefeSPatrick Mooney struct io_buffer {
954c87aefeSPatrick Mooney 	uint8_t *data;
964c87aefeSPatrick Mooney 	size_t capacity;
974c87aefeSPatrick Mooney 	size_t start;
984c87aefeSPatrick Mooney 	size_t len;
994c87aefeSPatrick Mooney };
1004c87aefeSPatrick Mooney 
101154972afSPatrick Mooney struct breakpoint {
102154972afSPatrick Mooney 	uint64_t gpa;
103154972afSPatrick Mooney 	uint8_t shadow_inst;
104154972afSPatrick Mooney 	TAILQ_ENTRY(breakpoint) link;
105154972afSPatrick Mooney };
106154972afSPatrick Mooney 
107154972afSPatrick Mooney /*
108154972afSPatrick Mooney  * When a vCPU stops to due to an event that should be reported to the
109154972afSPatrick Mooney  * debugger, information about the event is stored in this structure.
110154972afSPatrick Mooney  * The vCPU thread then sets 'stopped_vcpu' if it is not already set
111154972afSPatrick Mooney  * and stops other vCPUs so the event can be reported.  The
112154972afSPatrick Mooney  * report_stop() function reports the event for the 'stopped_vcpu'
113154972afSPatrick Mooney  * vCPU.  When the debugger resumes execution via continue or step,
114154972afSPatrick Mooney  * the event for 'stopped_vcpu' is cleared.  vCPUs will loop in their
115154972afSPatrick Mooney  * event handlers until the associated event is reported or disabled.
116154972afSPatrick Mooney  *
117154972afSPatrick Mooney  * An idle vCPU will have all of the boolean fields set to false.
118154972afSPatrick Mooney  *
119154972afSPatrick Mooney  * When a vCPU is stepped, 'stepping' is set to true when the vCPU is
120154972afSPatrick Mooney  * released to execute the stepped instruction.  When the vCPU reports
121154972afSPatrick Mooney  * the stepping trap, 'stepped' is set.
122154972afSPatrick Mooney  *
123154972afSPatrick Mooney  * When a vCPU hits a breakpoint set by the debug server,
124154972afSPatrick Mooney  * 'hit_swbreak' is set to true.
125154972afSPatrick Mooney  */
126154972afSPatrick Mooney struct vcpu_state {
127154972afSPatrick Mooney 	bool stepping;
128154972afSPatrick Mooney 	bool stepped;
129154972afSPatrick Mooney 	bool hit_swbreak;
130154972afSPatrick Mooney };
131154972afSPatrick Mooney 
1324c87aefeSPatrick Mooney static struct io_buffer cur_comm, cur_resp;
1334c87aefeSPatrick Mooney static uint8_t cur_csum;
1344c87aefeSPatrick Mooney static struct vmctx *ctx;
1354c87aefeSPatrick Mooney static int cur_fd = -1;
136154972afSPatrick Mooney static TAILQ_HEAD(, breakpoint) breakpoints;
137154972afSPatrick Mooney static struct vcpu_state *vcpu_state;
138*32640292SAndy Fiddaman static struct vcpu **vcpus;
139154972afSPatrick Mooney static int cur_vcpu, stopped_vcpu;
1402b948146SAndy Fiddaman static bool gdb_active = false;
1414c87aefeSPatrick Mooney 
1424f3f3e9aSAndy Fiddaman static const int gdb_regset[] = {
1434c87aefeSPatrick Mooney 	VM_REG_GUEST_RAX,
1444c87aefeSPatrick Mooney 	VM_REG_GUEST_RBX,
1454c87aefeSPatrick Mooney 	VM_REG_GUEST_RCX,
1464c87aefeSPatrick Mooney 	VM_REG_GUEST_RDX,
1474c87aefeSPatrick Mooney 	VM_REG_GUEST_RSI,
1484c87aefeSPatrick Mooney 	VM_REG_GUEST_RDI,
1494c87aefeSPatrick Mooney 	VM_REG_GUEST_RBP,
1504c87aefeSPatrick Mooney 	VM_REG_GUEST_RSP,
1514c87aefeSPatrick Mooney 	VM_REG_GUEST_R8,
1524c87aefeSPatrick Mooney 	VM_REG_GUEST_R9,
1534c87aefeSPatrick Mooney 	VM_REG_GUEST_R10,
1544c87aefeSPatrick Mooney 	VM_REG_GUEST_R11,
1554c87aefeSPatrick Mooney 	VM_REG_GUEST_R12,
1564c87aefeSPatrick Mooney 	VM_REG_GUEST_R13,
1574c87aefeSPatrick Mooney 	VM_REG_GUEST_R14,
1584c87aefeSPatrick Mooney 	VM_REG_GUEST_R15,
1594c87aefeSPatrick Mooney 	VM_REG_GUEST_RIP,
1604c87aefeSPatrick Mooney 	VM_REG_GUEST_RFLAGS,
1614c87aefeSPatrick Mooney 	VM_REG_GUEST_CS,
1624c87aefeSPatrick Mooney 	VM_REG_GUEST_SS,
1634c87aefeSPatrick Mooney 	VM_REG_GUEST_DS,
1644c87aefeSPatrick Mooney 	VM_REG_GUEST_ES,
1654c87aefeSPatrick Mooney 	VM_REG_GUEST_FS,
1664c87aefeSPatrick Mooney 	VM_REG_GUEST_GS
1674c87aefeSPatrick Mooney };
1684c87aefeSPatrick Mooney 
1694f3f3e9aSAndy Fiddaman static const int gdb_regsize[] = {
1704c87aefeSPatrick Mooney 	8,
1714c87aefeSPatrick Mooney 	8,
1724c87aefeSPatrick Mooney 	8,
1734c87aefeSPatrick Mooney 	8,
1744c87aefeSPatrick Mooney 	8,
1754c87aefeSPatrick Mooney 	8,
1764c87aefeSPatrick Mooney 	8,
1774c87aefeSPatrick Mooney 	8,
1784c87aefeSPatrick Mooney 	8,
1794c87aefeSPatrick Mooney 	8,
1804c87aefeSPatrick Mooney 	8,
1814c87aefeSPatrick Mooney 	8,
1824c87aefeSPatrick Mooney 	8,
1834c87aefeSPatrick Mooney 	8,
1844c87aefeSPatrick Mooney 	8,
1854c87aefeSPatrick Mooney 	8,
1864c87aefeSPatrick Mooney 	8,
1874c87aefeSPatrick Mooney 	4,
1884c87aefeSPatrick Mooney 	4,
1894c87aefeSPatrick Mooney 	4,
1904c87aefeSPatrick Mooney 	4,
1914c87aefeSPatrick Mooney 	4,
1924c87aefeSPatrick Mooney 	4,
1934c87aefeSPatrick Mooney 	4
1944c87aefeSPatrick Mooney };
1954c87aefeSPatrick Mooney 
1964c87aefeSPatrick Mooney #ifdef GDB_LOG
1974c87aefeSPatrick Mooney #include <stdarg.h>
1984c87aefeSPatrick Mooney #include <stdio.h>
1994c87aefeSPatrick Mooney 
2004c87aefeSPatrick Mooney static void __printflike(1, 2)
debug(const char * fmt,...)2014c87aefeSPatrick Mooney debug(const char *fmt, ...)
2024c87aefeSPatrick Mooney {
2034c87aefeSPatrick Mooney 	static FILE *logfile;
2044c87aefeSPatrick Mooney 	va_list ap;
2054c87aefeSPatrick Mooney 
2064c87aefeSPatrick Mooney 	if (logfile == NULL) {
2074c87aefeSPatrick Mooney 		logfile = fopen("/tmp/bhyve_gdb.log", "w");
2084c87aefeSPatrick Mooney 		if (logfile == NULL)
2094c87aefeSPatrick Mooney 			return;
2104c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
2114c87aefeSPatrick Mooney 		if (caph_limit_stream(fileno(logfile), CAPH_WRITE) == -1) {
2124c87aefeSPatrick Mooney 			fclose(logfile);
2134c87aefeSPatrick Mooney 			logfile = NULL;
2144c87aefeSPatrick Mooney 			return;
2154c87aefeSPatrick Mooney 		}
2164c87aefeSPatrick Mooney #endif
2174c87aefeSPatrick Mooney 		setlinebuf(logfile);
2184c87aefeSPatrick Mooney 	}
2194c87aefeSPatrick Mooney 	va_start(ap, fmt);
2204c87aefeSPatrick Mooney 	vfprintf(logfile, fmt, ap);
2214c87aefeSPatrick Mooney 	va_end(ap);
2224c87aefeSPatrick Mooney }
2234c87aefeSPatrick Mooney #else
224154972afSPatrick Mooney #ifndef __FreeBSD__
225154972afSPatrick Mooney /*
226154972afSPatrick Mooney  * A totally empty debug() makes the compiler grumpy due to how its used with
227154972afSPatrick Mooney  * some control flow here.
228154972afSPatrick Mooney  */
229154972afSPatrick Mooney #define debug(...) do { } while (0)
230154972afSPatrick Mooney #else
2314c87aefeSPatrick Mooney #define debug(...)
2324c87aefeSPatrick Mooney #endif
233154972afSPatrick Mooney #endif
234154972afSPatrick Mooney 
235154972afSPatrick Mooney static void	remove_all_sw_breakpoints(void);
2364c87aefeSPatrick Mooney 
2374c87aefeSPatrick Mooney static int
guest_paging_info(struct vcpu * vcpu,struct vm_guest_paging * paging)238*32640292SAndy Fiddaman guest_paging_info(struct vcpu *vcpu, struct vm_guest_paging *paging)
2394c87aefeSPatrick Mooney {
2404c87aefeSPatrick Mooney 	uint64_t regs[4];
2414c87aefeSPatrick Mooney 	const int regset[4] = {
2424c87aefeSPatrick Mooney 		VM_REG_GUEST_CR0,
2434c87aefeSPatrick Mooney 		VM_REG_GUEST_CR3,
2444c87aefeSPatrick Mooney 		VM_REG_GUEST_CR4,
2454c87aefeSPatrick Mooney 		VM_REG_GUEST_EFER
2464c87aefeSPatrick Mooney 	};
2474c87aefeSPatrick Mooney 
248*32640292SAndy Fiddaman 	if (vm_get_register_set(vcpu, nitems(regset), regset, regs) == -1)
2494c87aefeSPatrick Mooney 		return (-1);
2504c87aefeSPatrick Mooney 
2514c87aefeSPatrick Mooney 	/*
2524c87aefeSPatrick Mooney 	 * For the debugger, always pretend to be the kernel (CPL 0),
2534c87aefeSPatrick Mooney 	 * and if long-mode is enabled, always parse addresses as if
2544c87aefeSPatrick Mooney 	 * in 64-bit mode.
2554c87aefeSPatrick Mooney 	 */
2564c87aefeSPatrick Mooney 	paging->cr3 = regs[1];
2574c87aefeSPatrick Mooney 	paging->cpl = 0;
2584c87aefeSPatrick Mooney 	if (regs[3] & EFER_LMA)
2594c87aefeSPatrick Mooney 		paging->cpu_mode = CPU_MODE_64BIT;
2604c87aefeSPatrick Mooney 	else if (regs[0] & CR0_PE)
2614c87aefeSPatrick Mooney 		paging->cpu_mode = CPU_MODE_PROTECTED;
2624c87aefeSPatrick Mooney 	else
2634c87aefeSPatrick Mooney 		paging->cpu_mode = CPU_MODE_REAL;
2644c87aefeSPatrick Mooney 	if (!(regs[0] & CR0_PG))
2654c87aefeSPatrick Mooney 		paging->paging_mode = PAGING_MODE_FLAT;
2664c87aefeSPatrick Mooney 	else if (!(regs[2] & CR4_PAE))
2674c87aefeSPatrick Mooney 		paging->paging_mode = PAGING_MODE_32;
2684c87aefeSPatrick Mooney 	else if (regs[3] & EFER_LME)
2694c87aefeSPatrick Mooney 		paging->paging_mode = PAGING_MODE_64;
2704c87aefeSPatrick Mooney 	else
2714c87aefeSPatrick Mooney 		paging->paging_mode = PAGING_MODE_PAE;
2724c87aefeSPatrick Mooney 	return (0);
2734c87aefeSPatrick Mooney }
2744c87aefeSPatrick Mooney 
2754c87aefeSPatrick Mooney /*
2764c87aefeSPatrick Mooney  * Map a guest virtual address to a physical address (for a given vcpu).
2774c87aefeSPatrick Mooney  * If a guest virtual address is valid, return 1.  If the address is
2784c87aefeSPatrick Mooney  * not valid, return 0.  If an error occurs obtaining the mapping,
2794c87aefeSPatrick Mooney  * return -1.
2804c87aefeSPatrick Mooney  */
2814c87aefeSPatrick Mooney static int
guest_vaddr2paddr(struct vcpu * vcpu,uint64_t vaddr,uint64_t * paddr)282*32640292SAndy Fiddaman guest_vaddr2paddr(struct vcpu *vcpu, uint64_t vaddr, uint64_t *paddr)
2834c87aefeSPatrick Mooney {
2844c87aefeSPatrick Mooney 	struct vm_guest_paging paging;
2854c87aefeSPatrick Mooney 	int fault;
2864c87aefeSPatrick Mooney 
2874c87aefeSPatrick Mooney 	if (guest_paging_info(vcpu, &paging) == -1)
2884c87aefeSPatrick Mooney 		return (-1);
2894c87aefeSPatrick Mooney 
2904c87aefeSPatrick Mooney 	/*
2914c87aefeSPatrick Mooney 	 * Always use PROT_READ.  We really care if the VA is
2924c87aefeSPatrick Mooney 	 * accessible, not if the current vCPU can write.
2934c87aefeSPatrick Mooney 	 */
294*32640292SAndy Fiddaman 	if (vm_gla2gpa_nofault(vcpu, &paging, vaddr, PROT_READ, paddr,
2954c87aefeSPatrick Mooney 	    &fault) == -1)
2964c87aefeSPatrick Mooney 		return (-1);
2974c87aefeSPatrick Mooney 	if (fault)
2984c87aefeSPatrick Mooney 		return (0);
2994c87aefeSPatrick Mooney 	return (1);
3004c87aefeSPatrick Mooney }
3014c87aefeSPatrick Mooney 
3024c87aefeSPatrick Mooney static void
io_buffer_reset(struct io_buffer * io)3034c87aefeSPatrick Mooney io_buffer_reset(struct io_buffer *io)
3044c87aefeSPatrick Mooney {
3054c87aefeSPatrick Mooney 
3064c87aefeSPatrick Mooney 	io->start = 0;
3074c87aefeSPatrick Mooney 	io->len = 0;
3084c87aefeSPatrick Mooney }
3094c87aefeSPatrick Mooney 
3104c87aefeSPatrick Mooney /* Available room for adding data. */
3114c87aefeSPatrick Mooney static size_t
io_buffer_avail(struct io_buffer * io)3124c87aefeSPatrick Mooney io_buffer_avail(struct io_buffer *io)
3134c87aefeSPatrick Mooney {
3144c87aefeSPatrick Mooney 
3154c87aefeSPatrick Mooney 	return (io->capacity - (io->start + io->len));
3164c87aefeSPatrick Mooney }
3174c87aefeSPatrick Mooney 
3184c87aefeSPatrick Mooney static uint8_t *
io_buffer_head(struct io_buffer * io)3194c87aefeSPatrick Mooney io_buffer_head(struct io_buffer *io)
3204c87aefeSPatrick Mooney {
3214c87aefeSPatrick Mooney 
3224c87aefeSPatrick Mooney 	return (io->data + io->start);
3234c87aefeSPatrick Mooney }
3244c87aefeSPatrick Mooney 
3254c87aefeSPatrick Mooney static uint8_t *
io_buffer_tail(struct io_buffer * io)3264c87aefeSPatrick Mooney io_buffer_tail(struct io_buffer *io)
3274c87aefeSPatrick Mooney {
3284c87aefeSPatrick Mooney 
3294c87aefeSPatrick Mooney 	return (io->data + io->start + io->len);
3304c87aefeSPatrick Mooney }
3314c87aefeSPatrick Mooney 
3324c87aefeSPatrick Mooney static void
io_buffer_advance(struct io_buffer * io,size_t amount)3334c87aefeSPatrick Mooney io_buffer_advance(struct io_buffer *io, size_t amount)
3344c87aefeSPatrick Mooney {
3354c87aefeSPatrick Mooney 
3364c87aefeSPatrick Mooney 	assert(amount <= io->len);
3374c87aefeSPatrick Mooney 	io->start += amount;
3384c87aefeSPatrick Mooney 	io->len -= amount;
3394c87aefeSPatrick Mooney }
3404c87aefeSPatrick Mooney 
3414c87aefeSPatrick Mooney static void
io_buffer_consume(struct io_buffer * io,size_t amount)3424c87aefeSPatrick Mooney io_buffer_consume(struct io_buffer *io, size_t amount)
3434c87aefeSPatrick Mooney {
3444c87aefeSPatrick Mooney 
3454c87aefeSPatrick Mooney 	io_buffer_advance(io, amount);
3464c87aefeSPatrick Mooney 	if (io->len == 0) {
3474c87aefeSPatrick Mooney 		io->start = 0;
3484c87aefeSPatrick Mooney 		return;
3494c87aefeSPatrick Mooney 	}
3504c87aefeSPatrick Mooney 
3514c87aefeSPatrick Mooney 	/*
3524c87aefeSPatrick Mooney 	 * XXX: Consider making this move optional and compacting on a
3534c87aefeSPatrick Mooney 	 * future read() before realloc().
3544c87aefeSPatrick Mooney 	 */
3554c87aefeSPatrick Mooney 	memmove(io->data, io_buffer_head(io), io->len);
3564c87aefeSPatrick Mooney 	io->start = 0;
3574c87aefeSPatrick Mooney }
3584c87aefeSPatrick Mooney 
3594c87aefeSPatrick Mooney static void
io_buffer_grow(struct io_buffer * io,size_t newsize)3604c87aefeSPatrick Mooney io_buffer_grow(struct io_buffer *io, size_t newsize)
3614c87aefeSPatrick Mooney {
3624c87aefeSPatrick Mooney 	uint8_t *new_data;
3634c87aefeSPatrick Mooney 	size_t avail, new_cap;
3644c87aefeSPatrick Mooney 
3654c87aefeSPatrick Mooney 	avail = io_buffer_avail(io);
3664c87aefeSPatrick Mooney 	if (newsize <= avail)
3674c87aefeSPatrick Mooney 		return;
3684c87aefeSPatrick Mooney 
3694c87aefeSPatrick Mooney 	new_cap = io->capacity + (newsize - avail);
3704c87aefeSPatrick Mooney 	new_data = realloc(io->data, new_cap);
3714c87aefeSPatrick Mooney 	if (new_data == NULL)
3724c87aefeSPatrick Mooney 		err(1, "Failed to grow GDB I/O buffer");
3734c87aefeSPatrick Mooney 	io->data = new_data;
3744c87aefeSPatrick Mooney 	io->capacity = new_cap;
3754c87aefeSPatrick Mooney }
3764c87aefeSPatrick Mooney 
3774c87aefeSPatrick Mooney static bool
response_pending(void)3784c87aefeSPatrick Mooney response_pending(void)
3794c87aefeSPatrick Mooney {
3804c87aefeSPatrick Mooney 
3814c87aefeSPatrick Mooney 	if (cur_resp.start == 0 && cur_resp.len == 0)
3824c87aefeSPatrick Mooney 		return (false);
3834c87aefeSPatrick Mooney 	if (cur_resp.start + cur_resp.len == 1 && cur_resp.data[0] == '+')
3844c87aefeSPatrick Mooney 		return (false);
3854c87aefeSPatrick Mooney 	return (true);
3864c87aefeSPatrick Mooney }
3874c87aefeSPatrick Mooney 
3884c87aefeSPatrick Mooney static void
close_connection(void)3894c87aefeSPatrick Mooney close_connection(void)
3904c87aefeSPatrick Mooney {
3914c87aefeSPatrick Mooney 
3924c87aefeSPatrick Mooney 	/*
3934c87aefeSPatrick Mooney 	 * XXX: This triggers a warning because mevent does the close
3944c87aefeSPatrick Mooney 	 * before the EV_DELETE.
3954c87aefeSPatrick Mooney 	 */
3964c87aefeSPatrick Mooney 	pthread_mutex_lock(&gdb_lock);
3974c87aefeSPatrick Mooney 	mevent_delete(write_event);
3984c87aefeSPatrick Mooney 	mevent_delete_close(read_event);
3994c87aefeSPatrick Mooney 	write_event = NULL;
4004c87aefeSPatrick Mooney 	read_event = NULL;
4014c87aefeSPatrick Mooney 	io_buffer_reset(&cur_comm);
4024c87aefeSPatrick Mooney 	io_buffer_reset(&cur_resp);
4034c87aefeSPatrick Mooney 	cur_fd = -1;
4044c87aefeSPatrick Mooney 
405154972afSPatrick Mooney 	remove_all_sw_breakpoints();
406154972afSPatrick Mooney 
407154972afSPatrick Mooney 	/* Clear any pending events. */
408154972afSPatrick Mooney 	memset(vcpu_state, 0, guest_ncpus * sizeof(*vcpu_state));
409154972afSPatrick Mooney 
4104c87aefeSPatrick Mooney 	/* Resume any stopped vCPUs. */
4114c87aefeSPatrick Mooney 	gdb_resume_vcpus();
4124c87aefeSPatrick Mooney 	pthread_mutex_unlock(&gdb_lock);
4134c87aefeSPatrick Mooney }
4144c87aefeSPatrick Mooney 
4154c87aefeSPatrick Mooney static uint8_t
hex_digit(uint8_t nibble)4164c87aefeSPatrick Mooney hex_digit(uint8_t nibble)
4174c87aefeSPatrick Mooney {
4184c87aefeSPatrick Mooney 
4194c87aefeSPatrick Mooney 	if (nibble <= 9)
4204c87aefeSPatrick Mooney 		return (nibble + '0');
4214c87aefeSPatrick Mooney 	else
4224c87aefeSPatrick Mooney 		return (nibble + 'a' - 10);
4234c87aefeSPatrick Mooney }
4244c87aefeSPatrick Mooney 
4254c87aefeSPatrick Mooney static uint8_t
parse_digit(uint8_t v)4264c87aefeSPatrick Mooney parse_digit(uint8_t v)
4274c87aefeSPatrick Mooney {
4284c87aefeSPatrick Mooney 
4294c87aefeSPatrick Mooney 	if (v >= '0' && v <= '9')
4304c87aefeSPatrick Mooney 		return (v - '0');
4314c87aefeSPatrick Mooney 	if (v >= 'a' && v <= 'f')
4324c87aefeSPatrick Mooney 		return (v - 'a' + 10);
4334c87aefeSPatrick Mooney 	if (v >= 'A' && v <= 'F')
4344c87aefeSPatrick Mooney 		return (v - 'A' + 10);
4354c87aefeSPatrick Mooney 	return (0xF);
4364c87aefeSPatrick Mooney }
4374c87aefeSPatrick Mooney 
4384c87aefeSPatrick Mooney /* Parses big-endian hexadecimal. */
4394c87aefeSPatrick Mooney static uintmax_t
parse_integer(const uint8_t * p,size_t len)4404c87aefeSPatrick Mooney parse_integer(const uint8_t *p, size_t len)
4414c87aefeSPatrick Mooney {
4424c87aefeSPatrick Mooney 	uintmax_t v;
4434c87aefeSPatrick Mooney 
4444c87aefeSPatrick Mooney 	v = 0;
4454c87aefeSPatrick Mooney 	while (len > 0) {
4464c87aefeSPatrick Mooney 		v <<= 4;
4474c87aefeSPatrick Mooney 		v |= parse_digit(*p);
4484c87aefeSPatrick Mooney 		p++;
4494c87aefeSPatrick Mooney 		len--;
4504c87aefeSPatrick Mooney 	}
4514c87aefeSPatrick Mooney 	return (v);
4524c87aefeSPatrick Mooney }
4534c87aefeSPatrick Mooney 
4544c87aefeSPatrick Mooney static uint8_t
parse_byte(const uint8_t * p)4554c87aefeSPatrick Mooney parse_byte(const uint8_t *p)
4564c87aefeSPatrick Mooney {
4574c87aefeSPatrick Mooney 
4584c87aefeSPatrick Mooney 	return (parse_digit(p[0]) << 4 | parse_digit(p[1]));
4594c87aefeSPatrick Mooney }
4604c87aefeSPatrick Mooney 
4614c87aefeSPatrick Mooney static void
send_pending_data(int fd)4624c87aefeSPatrick Mooney send_pending_data(int fd)
4634c87aefeSPatrick Mooney {
4644c87aefeSPatrick Mooney 	ssize_t nwritten;
4654c87aefeSPatrick Mooney 
4664c87aefeSPatrick Mooney 	if (cur_resp.len == 0) {
4674c87aefeSPatrick Mooney 		mevent_disable(write_event);
4684c87aefeSPatrick Mooney 		return;
4694c87aefeSPatrick Mooney 	}
4704c87aefeSPatrick Mooney 	nwritten = write(fd, io_buffer_head(&cur_resp), cur_resp.len);
4714c87aefeSPatrick Mooney 	if (nwritten == -1) {
4724c87aefeSPatrick Mooney 		warn("Write to GDB socket failed");
4734c87aefeSPatrick Mooney 		close_connection();
4744c87aefeSPatrick Mooney 	} else {
4754c87aefeSPatrick Mooney 		io_buffer_advance(&cur_resp, nwritten);
4764c87aefeSPatrick Mooney 		if (cur_resp.len == 0)
4774c87aefeSPatrick Mooney 			mevent_disable(write_event);
4784c87aefeSPatrick Mooney 		else
4794c87aefeSPatrick Mooney 			mevent_enable(write_event);
4804c87aefeSPatrick Mooney 	}
4814c87aefeSPatrick Mooney }
4824c87aefeSPatrick Mooney 
4834c87aefeSPatrick Mooney /* Append a single character to the output buffer. */
4844c87aefeSPatrick Mooney static void
send_char(uint8_t data)4854c87aefeSPatrick Mooney send_char(uint8_t data)
4864c87aefeSPatrick Mooney {
4874c87aefeSPatrick Mooney 	io_buffer_grow(&cur_resp, 1);
4884c87aefeSPatrick Mooney 	*io_buffer_tail(&cur_resp) = data;
4894c87aefeSPatrick Mooney 	cur_resp.len++;
4904c87aefeSPatrick Mooney }
4914c87aefeSPatrick Mooney 
4924c87aefeSPatrick Mooney /* Append an array of bytes to the output buffer. */
4934c87aefeSPatrick Mooney static void
send_data(const uint8_t * data,size_t len)4944c87aefeSPatrick Mooney send_data(const uint8_t *data, size_t len)
4954c87aefeSPatrick Mooney {
4964c87aefeSPatrick Mooney 
4974c87aefeSPatrick Mooney 	io_buffer_grow(&cur_resp, len);
4984c87aefeSPatrick Mooney 	memcpy(io_buffer_tail(&cur_resp), data, len);
4994c87aefeSPatrick Mooney 	cur_resp.len += len;
5004c87aefeSPatrick Mooney }
5014c87aefeSPatrick Mooney 
5024c87aefeSPatrick Mooney static void
format_byte(uint8_t v,uint8_t * buf)5034c87aefeSPatrick Mooney format_byte(uint8_t v, uint8_t *buf)
5044c87aefeSPatrick Mooney {
5054c87aefeSPatrick Mooney 
5064c87aefeSPatrick Mooney 	buf[0] = hex_digit(v >> 4);
5074c87aefeSPatrick Mooney 	buf[1] = hex_digit(v & 0xf);
5084c87aefeSPatrick Mooney }
5094c87aefeSPatrick Mooney 
5104c87aefeSPatrick Mooney /*
5114c87aefeSPatrick Mooney  * Append a single byte (formatted as two hex characters) to the
5124c87aefeSPatrick Mooney  * output buffer.
5134c87aefeSPatrick Mooney  */
5144c87aefeSPatrick Mooney static void
send_byte(uint8_t v)5154c87aefeSPatrick Mooney send_byte(uint8_t v)
5164c87aefeSPatrick Mooney {
5174c87aefeSPatrick Mooney 	uint8_t buf[2];
5184c87aefeSPatrick Mooney 
5194c87aefeSPatrick Mooney 	format_byte(v, buf);
5204c87aefeSPatrick Mooney 	send_data(buf, sizeof(buf));
5214c87aefeSPatrick Mooney }
5224c87aefeSPatrick Mooney 
5234c87aefeSPatrick Mooney static void
start_packet(void)5244c87aefeSPatrick Mooney start_packet(void)
5254c87aefeSPatrick Mooney {
5264c87aefeSPatrick Mooney 
5274c87aefeSPatrick Mooney 	send_char('$');
5284c87aefeSPatrick Mooney 	cur_csum = 0;
5294c87aefeSPatrick Mooney }
5304c87aefeSPatrick Mooney 
5314c87aefeSPatrick Mooney static void
finish_packet(void)5324c87aefeSPatrick Mooney finish_packet(void)
5334c87aefeSPatrick Mooney {
5344c87aefeSPatrick Mooney 
5354c87aefeSPatrick Mooney 	send_char('#');
5364c87aefeSPatrick Mooney 	send_byte(cur_csum);
5374c87aefeSPatrick Mooney 	debug("-> %.*s\n", (int)cur_resp.len, io_buffer_head(&cur_resp));
5384c87aefeSPatrick Mooney }
5394c87aefeSPatrick Mooney 
5404c87aefeSPatrick Mooney /*
5414c87aefeSPatrick Mooney  * Append a single character (for the packet payload) and update the
5424c87aefeSPatrick Mooney  * checksum.
5434c87aefeSPatrick Mooney  */
5444c87aefeSPatrick Mooney static void
append_char(uint8_t v)5454c87aefeSPatrick Mooney append_char(uint8_t v)
5464c87aefeSPatrick Mooney {
5474c87aefeSPatrick Mooney 
5484c87aefeSPatrick Mooney 	send_char(v);
5494c87aefeSPatrick Mooney 	cur_csum += v;
5504c87aefeSPatrick Mooney }
5514c87aefeSPatrick Mooney 
5524c87aefeSPatrick Mooney /*
5534c87aefeSPatrick Mooney  * Append an array of bytes (for the packet payload) and update the
5544c87aefeSPatrick Mooney  * checksum.
5554c87aefeSPatrick Mooney  */
5564c87aefeSPatrick Mooney static void
append_packet_data(const uint8_t * data,size_t len)5574c87aefeSPatrick Mooney append_packet_data(const uint8_t *data, size_t len)
5584c87aefeSPatrick Mooney {
5594c87aefeSPatrick Mooney 
5604c87aefeSPatrick Mooney 	send_data(data, len);
5614c87aefeSPatrick Mooney 	while (len > 0) {
5624c87aefeSPatrick Mooney 		cur_csum += *data;
5634c87aefeSPatrick Mooney 		data++;
5644c87aefeSPatrick Mooney 		len--;
5654c87aefeSPatrick Mooney 	}
5664c87aefeSPatrick Mooney }
5674c87aefeSPatrick Mooney 
5684c87aefeSPatrick Mooney static void
append_string(const char * str)5694c87aefeSPatrick Mooney append_string(const char *str)
5704c87aefeSPatrick Mooney {
5714c87aefeSPatrick Mooney 
5724c87aefeSPatrick Mooney #ifdef __FreeBSD__
5734c87aefeSPatrick Mooney 	append_packet_data(str, strlen(str));
5744c87aefeSPatrick Mooney #else
5754c87aefeSPatrick Mooney 	append_packet_data((const uint8_t *)str, strlen(str));
5764c87aefeSPatrick Mooney #endif
5774c87aefeSPatrick Mooney }
5784c87aefeSPatrick Mooney 
5794c87aefeSPatrick Mooney static void
append_byte(uint8_t v)5804c87aefeSPatrick Mooney append_byte(uint8_t v)
5814c87aefeSPatrick Mooney {
5824c87aefeSPatrick Mooney 	uint8_t buf[2];
5834c87aefeSPatrick Mooney 
5844c87aefeSPatrick Mooney 	format_byte(v, buf);
5854c87aefeSPatrick Mooney 	append_packet_data(buf, sizeof(buf));
5864c87aefeSPatrick Mooney }
5874c87aefeSPatrick Mooney 
5884c87aefeSPatrick Mooney static void
append_unsigned_native(uintmax_t value,size_t len)5894c87aefeSPatrick Mooney append_unsigned_native(uintmax_t value, size_t len)
5904c87aefeSPatrick Mooney {
5914c87aefeSPatrick Mooney 	size_t i;
5924c87aefeSPatrick Mooney 
5934c87aefeSPatrick Mooney 	for (i = 0; i < len; i++) {
5944c87aefeSPatrick Mooney 		append_byte(value);
5954c87aefeSPatrick Mooney 		value >>= 8;
5964c87aefeSPatrick Mooney 	}
5974c87aefeSPatrick Mooney }
5984c87aefeSPatrick Mooney 
5994c87aefeSPatrick Mooney static void
append_unsigned_be(uintmax_t value,size_t len)6004c87aefeSPatrick Mooney append_unsigned_be(uintmax_t value, size_t len)
6014c87aefeSPatrick Mooney {
6024c87aefeSPatrick Mooney 	char buf[len * 2];
6034c87aefeSPatrick Mooney 	size_t i;
6044c87aefeSPatrick Mooney 
6054c87aefeSPatrick Mooney 	for (i = 0; i < len; i++) {
6064c87aefeSPatrick Mooney #ifdef __FreeBSD__
6074c87aefeSPatrick Mooney 		format_byte(value, buf + (len - i - 1) * 2);
6084c87aefeSPatrick Mooney #else
6094c87aefeSPatrick Mooney 		format_byte(value, (uint8_t *)(buf + (len - i - 1) * 2));
6104c87aefeSPatrick Mooney #endif
6114c87aefeSPatrick Mooney 		value >>= 8;
6124c87aefeSPatrick Mooney 	}
6134c87aefeSPatrick Mooney #ifdef __FreeBSD__
6144c87aefeSPatrick Mooney 	append_packet_data(buf, sizeof(buf));
6154c87aefeSPatrick Mooney #else
6164c87aefeSPatrick Mooney 	append_packet_data((const uint8_t *)buf, sizeof(buf));
6174c87aefeSPatrick Mooney #endif
6184c87aefeSPatrick Mooney }
6194c87aefeSPatrick Mooney 
6204c87aefeSPatrick Mooney static void
append_integer(unsigned int value)6214c87aefeSPatrick Mooney append_integer(unsigned int value)
6224c87aefeSPatrick Mooney {
6234c87aefeSPatrick Mooney 
6244c87aefeSPatrick Mooney 	if (value == 0)
6254c87aefeSPatrick Mooney 		append_char('0');
6264c87aefeSPatrick Mooney 	else
627154972afSPatrick Mooney 		append_unsigned_be(value, (fls(value) + 7) / 8);
6284c87aefeSPatrick Mooney }
6294c87aefeSPatrick Mooney 
6304c87aefeSPatrick Mooney static void
append_asciihex(const char * str)6314c87aefeSPatrick Mooney append_asciihex(const char *str)
6324c87aefeSPatrick Mooney {
6334c87aefeSPatrick Mooney 
6344c87aefeSPatrick Mooney 	while (*str != '\0') {
6354c87aefeSPatrick Mooney 		append_byte(*str);
6364c87aefeSPatrick Mooney 		str++;
6374c87aefeSPatrick Mooney 	}
6384c87aefeSPatrick Mooney }
6394c87aefeSPatrick Mooney 
6404c87aefeSPatrick Mooney static void
send_empty_response(void)6414c87aefeSPatrick Mooney send_empty_response(void)
6424c87aefeSPatrick Mooney {
6434c87aefeSPatrick Mooney 
6444c87aefeSPatrick Mooney 	start_packet();
6454c87aefeSPatrick Mooney 	finish_packet();
6464c87aefeSPatrick Mooney }
6474c87aefeSPatrick Mooney 
6484c87aefeSPatrick Mooney static void
send_error(int error)6494c87aefeSPatrick Mooney send_error(int error)
6504c87aefeSPatrick Mooney {
6514c87aefeSPatrick Mooney 
6524c87aefeSPatrick Mooney 	start_packet();
6534c87aefeSPatrick Mooney 	append_char('E');
6544c87aefeSPatrick Mooney 	append_byte(error);
6554c87aefeSPatrick Mooney 	finish_packet();
6564c87aefeSPatrick Mooney }
6574c87aefeSPatrick Mooney 
6584c87aefeSPatrick Mooney static void
send_ok(void)6594c87aefeSPatrick Mooney send_ok(void)
6604c87aefeSPatrick Mooney {
6614c87aefeSPatrick Mooney 
6624c87aefeSPatrick Mooney 	start_packet();
6634c87aefeSPatrick Mooney 	append_string("OK");
6644c87aefeSPatrick Mooney 	finish_packet();
6654c87aefeSPatrick Mooney }
6664c87aefeSPatrick Mooney 
6674c87aefeSPatrick Mooney static int
parse_threadid(const uint8_t * data,size_t len)6684c87aefeSPatrick Mooney parse_threadid(const uint8_t *data, size_t len)
6694c87aefeSPatrick Mooney {
6704c87aefeSPatrick Mooney 
6714c87aefeSPatrick Mooney 	if (len == 1 && *data == '0')
6724c87aefeSPatrick Mooney 		return (0);
6734c87aefeSPatrick Mooney 	if (len == 2 && memcmp(data, "-1", 2) == 0)
6744c87aefeSPatrick Mooney 		return (-1);
6754c87aefeSPatrick Mooney 	if (len == 0)
6764c87aefeSPatrick Mooney 		return (-2);
6774c87aefeSPatrick Mooney 	return (parse_integer(data, len));
6784c87aefeSPatrick Mooney }
6794c87aefeSPatrick Mooney 
680154972afSPatrick Mooney /*
681154972afSPatrick Mooney  * Report the current stop event to the debugger.  If the stop is due
682154972afSPatrick Mooney  * to an event triggered on a specific vCPU such as a breakpoint or
683154972afSPatrick Mooney  * stepping trap, stopped_vcpu will be set to the vCPU triggering the
684154972afSPatrick Mooney  * stop.  If 'set_cur_vcpu' is true, then cur_vcpu will be updated to
685154972afSPatrick Mooney  * the reporting vCPU for vCPU events.
686154972afSPatrick Mooney  */
6874c87aefeSPatrick Mooney static void
report_stop(bool set_cur_vcpu)688154972afSPatrick Mooney report_stop(bool set_cur_vcpu)
6894c87aefeSPatrick Mooney {
690154972afSPatrick Mooney 	struct vcpu_state *vs;
6914c87aefeSPatrick Mooney 
6924c87aefeSPatrick Mooney 	start_packet();
693154972afSPatrick Mooney 	if (stopped_vcpu == -1) {
6944c87aefeSPatrick Mooney 		append_char('S');
695154972afSPatrick Mooney 		append_byte(GDB_SIGNAL_TRAP);
696154972afSPatrick Mooney 	} else {
697154972afSPatrick Mooney 		vs = &vcpu_state[stopped_vcpu];
698154972afSPatrick Mooney 		if (set_cur_vcpu)
699154972afSPatrick Mooney 			cur_vcpu = stopped_vcpu;
7004c87aefeSPatrick Mooney 		append_char('T');
7014c87aefeSPatrick Mooney 		append_byte(GDB_SIGNAL_TRAP);
7024c87aefeSPatrick Mooney 		append_string("thread:");
7034c87aefeSPatrick Mooney 		append_integer(stopped_vcpu + 1);
7044c87aefeSPatrick Mooney 		append_char(';');
705154972afSPatrick Mooney 		if (vs->hit_swbreak) {
706154972afSPatrick Mooney 			debug("$vCPU %d reporting swbreak\n", stopped_vcpu);
707154972afSPatrick Mooney 			if (swbreak_enabled)
708154972afSPatrick Mooney 				append_string("swbreak:;");
709154972afSPatrick Mooney 		} else if (vs->stepped)
710154972afSPatrick Mooney 			debug("$vCPU %d reporting step\n", stopped_vcpu);
711154972afSPatrick Mooney 		else
712154972afSPatrick Mooney 			debug("$vCPU %d reporting ???\n", stopped_vcpu);
7134c87aefeSPatrick Mooney 	}
7144c87aefeSPatrick Mooney 	finish_packet();
715154972afSPatrick Mooney 	report_next_stop = false;
716154972afSPatrick Mooney }
717154972afSPatrick Mooney 
718154972afSPatrick Mooney /*
719154972afSPatrick Mooney  * If this stop is due to a vCPU event, clear that event to mark it as
720154972afSPatrick Mooney  * acknowledged.
721154972afSPatrick Mooney  */
722154972afSPatrick Mooney static void
discard_stop(void)723154972afSPatrick Mooney discard_stop(void)
724154972afSPatrick Mooney {
725154972afSPatrick Mooney 	struct vcpu_state *vs;
726154972afSPatrick Mooney 
727154972afSPatrick Mooney 	if (stopped_vcpu != -1) {
728154972afSPatrick Mooney 		vs = &vcpu_state[stopped_vcpu];
729154972afSPatrick Mooney 		vs->hit_swbreak = false;
730154972afSPatrick Mooney 		vs->stepped = false;
731154972afSPatrick Mooney 		stopped_vcpu = -1;
732154972afSPatrick Mooney 	}
733154972afSPatrick Mooney 	report_next_stop = true;
7344c87aefeSPatrick Mooney }
7354c87aefeSPatrick Mooney 
7364c87aefeSPatrick Mooney static void
gdb_finish_suspend_vcpus(void)7374c87aefeSPatrick Mooney gdb_finish_suspend_vcpus(void)
7384c87aefeSPatrick Mooney {
7394c87aefeSPatrick Mooney 
7404c87aefeSPatrick Mooney 	if (first_stop) {
7414c87aefeSPatrick Mooney 		first_stop = false;
7424c87aefeSPatrick Mooney 		stopped_vcpu = -1;
743154972afSPatrick Mooney 	} else if (report_next_stop) {
744154972afSPatrick Mooney 		assert(!response_pending());
745154972afSPatrick Mooney 		report_stop(true);
7464c87aefeSPatrick Mooney 		send_pending_data(cur_fd);
7474c87aefeSPatrick Mooney 	}
7484c87aefeSPatrick Mooney }
7494c87aefeSPatrick Mooney 
750154972afSPatrick Mooney /*
751154972afSPatrick Mooney  * vCPU threads invoke this function whenever the vCPU enters the
752154972afSPatrick Mooney  * debug server to pause or report an event.  vCPU threads wait here
753154972afSPatrick Mooney  * as long as the debug server keeps them suspended.
754154972afSPatrick Mooney  */
7554c87aefeSPatrick Mooney static void
_gdb_cpu_suspend(struct vcpu * vcpu,bool report_stop)756*32640292SAndy Fiddaman _gdb_cpu_suspend(struct vcpu *vcpu, bool report_stop)
7574c87aefeSPatrick Mooney {
758*32640292SAndy Fiddaman 	int vcpuid = vcpu_id(vcpu);
7594c87aefeSPatrick Mooney 
760*32640292SAndy Fiddaman 	debug("$vCPU %d suspending\n", vcpuid);
761*32640292SAndy Fiddaman 	CPU_SET(vcpuid, &vcpus_waiting);
7624c87aefeSPatrick Mooney 	if (report_stop && CPU_CMP(&vcpus_waiting, &vcpus_suspended) == 0)
7634c87aefeSPatrick Mooney 		gdb_finish_suspend_vcpus();
764*32640292SAndy Fiddaman 	while (CPU_ISSET(vcpuid, &vcpus_suspended))
7654c87aefeSPatrick Mooney 		pthread_cond_wait(&idle_vcpus, &gdb_lock);
766*32640292SAndy Fiddaman 	CPU_CLR(vcpuid, &vcpus_waiting);
767*32640292SAndy Fiddaman 	debug("$vCPU %d resuming\n", vcpuid);
7684c87aefeSPatrick Mooney }
7694c87aefeSPatrick Mooney 
770154972afSPatrick Mooney /*
771154972afSPatrick Mooney  * Invoked at the start of a vCPU thread's execution to inform the
772154972afSPatrick Mooney  * debug server about the new thread.
773154972afSPatrick Mooney  */
7744c87aefeSPatrick Mooney void
gdb_cpu_add(struct vcpu * vcpu)775*32640292SAndy Fiddaman gdb_cpu_add(struct vcpu *vcpu)
7764c87aefeSPatrick Mooney {
777*32640292SAndy Fiddaman 	int vcpuid;
7784c87aefeSPatrick Mooney 
7792b948146SAndy Fiddaman 	if (!gdb_active)
7802b948146SAndy Fiddaman 		return;
781*32640292SAndy Fiddaman 	vcpuid = vcpu_id(vcpu);
782*32640292SAndy Fiddaman 	debug("$vCPU %d starting\n", vcpuid);
7834c87aefeSPatrick Mooney 	pthread_mutex_lock(&gdb_lock);
784*32640292SAndy Fiddaman 	assert(vcpuid < guest_ncpus);
785*32640292SAndy Fiddaman 	assert(vcpus[vcpuid] == NULL);
786*32640292SAndy Fiddaman 	vcpus[vcpuid] = vcpu;
787*32640292SAndy Fiddaman 	CPU_SET(vcpuid, &vcpus_active);
788154972afSPatrick Mooney 	if (!TAILQ_EMPTY(&breakpoints)) {
789*32640292SAndy Fiddaman 		vm_set_capability(vcpu, VM_CAP_BPT_EXIT, 1);
790154972afSPatrick Mooney 		debug("$vCPU %d enabled breakpoint exits\n", vcpu);
791154972afSPatrick Mooney 	}
7924c87aefeSPatrick Mooney 
7934c87aefeSPatrick Mooney 	/*
7944c87aefeSPatrick Mooney 	 * If a vcpu is added while vcpus are stopped, suspend the new
7954c87aefeSPatrick Mooney 	 * vcpu so that it will pop back out with a debug exit before
7964c87aefeSPatrick Mooney 	 * executing the first instruction.
7974c87aefeSPatrick Mooney 	 */
7984c87aefeSPatrick Mooney 	if (!CPU_EMPTY(&vcpus_suspended)) {
799*32640292SAndy Fiddaman 		CPU_SET(vcpuid, &vcpus_suspended);
8004c87aefeSPatrick Mooney 		_gdb_cpu_suspend(vcpu, false);
8014c87aefeSPatrick Mooney 	}
8024c87aefeSPatrick Mooney 	pthread_mutex_unlock(&gdb_lock);
8034c87aefeSPatrick Mooney }
8044c87aefeSPatrick Mooney 
805154972afSPatrick Mooney /*
806154972afSPatrick Mooney  * Invoked by vCPU before resuming execution.  This enables stepping
807154972afSPatrick Mooney  * if the vCPU is marked as stepping.
808154972afSPatrick Mooney  */
809154972afSPatrick Mooney static void
gdb_cpu_resume(struct vcpu * vcpu)810*32640292SAndy Fiddaman gdb_cpu_resume(struct vcpu *vcpu)
811154972afSPatrick Mooney {
812154972afSPatrick Mooney 	struct vcpu_state *vs;
813154972afSPatrick Mooney 	int error;
814154972afSPatrick Mooney 
815*32640292SAndy Fiddaman 	vs = &vcpu_state[vcpu_id(vcpu)];
816154972afSPatrick Mooney 
817154972afSPatrick Mooney 	/*
818154972afSPatrick Mooney 	 * Any pending event should already be reported before
819154972afSPatrick Mooney 	 * resuming.
820154972afSPatrick Mooney 	 */
821154972afSPatrick Mooney 	assert(vs->hit_swbreak == false);
822154972afSPatrick Mooney 	assert(vs->stepped == false);
823154972afSPatrick Mooney 	if (vs->stepping) {
824*32640292SAndy Fiddaman 		error = vm_set_capability(vcpu, VM_CAP_MTRAP_EXIT, 1);
825154972afSPatrick Mooney 		assert(error == 0);
826154972afSPatrick Mooney 	}
827154972afSPatrick Mooney }
828154972afSPatrick Mooney 
829154972afSPatrick Mooney /*
830154972afSPatrick Mooney  * Handler for VM_EXITCODE_DEBUG used to suspend a vCPU when the guest
831154972afSPatrick Mooney  * has been suspended due to an event on different vCPU or in response
832154972afSPatrick Mooney  * to a guest-wide suspend such as Ctrl-C or the stop on attach.
833154972afSPatrick Mooney  */
8344c87aefeSPatrick Mooney void
gdb_cpu_suspend(struct vcpu * vcpu)835*32640292SAndy Fiddaman gdb_cpu_suspend(struct vcpu *vcpu)
8364c87aefeSPatrick Mooney {
8374c87aefeSPatrick Mooney 
838b0de25cbSAndy Fiddaman 	if (!gdb_active)
839b0de25cbSAndy Fiddaman 		return;
8404c87aefeSPatrick Mooney 	pthread_mutex_lock(&gdb_lock);
8414c87aefeSPatrick Mooney 	_gdb_cpu_suspend(vcpu, true);
842154972afSPatrick Mooney 	gdb_cpu_resume(vcpu);
8434c87aefeSPatrick Mooney 	pthread_mutex_unlock(&gdb_lock);
8444c87aefeSPatrick Mooney }
8454c87aefeSPatrick Mooney 
8464c87aefeSPatrick Mooney static void
gdb_suspend_vcpus(void)8474c87aefeSPatrick Mooney gdb_suspend_vcpus(void)
8484c87aefeSPatrick Mooney {
8494c87aefeSPatrick Mooney 
8504c87aefeSPatrick Mooney 	assert(pthread_mutex_isowned_np(&gdb_lock));
8514c87aefeSPatrick Mooney 	debug("suspending all CPUs\n");
8524c87aefeSPatrick Mooney 	vcpus_suspended = vcpus_active;
853*32640292SAndy Fiddaman 	vm_suspend_all_cpus(ctx);
8544c87aefeSPatrick Mooney 	if (CPU_CMP(&vcpus_waiting, &vcpus_suspended) == 0)
8554c87aefeSPatrick Mooney 		gdb_finish_suspend_vcpus();
8564c87aefeSPatrick Mooney }
8574c87aefeSPatrick Mooney 
858154972afSPatrick Mooney /*
859154972afSPatrick Mooney  * Handler for VM_EXITCODE_MTRAP reported when a vCPU single-steps via
860154972afSPatrick Mooney  * the VT-x-specific MTRAP exit.
861154972afSPatrick Mooney  */
862154972afSPatrick Mooney void
gdb_cpu_mtrap(struct vcpu * vcpu)863*32640292SAndy Fiddaman gdb_cpu_mtrap(struct vcpu *vcpu)
864154972afSPatrick Mooney {
865154972afSPatrick Mooney 	struct vcpu_state *vs;
866*32640292SAndy Fiddaman 	int vcpuid;
867154972afSPatrick Mooney 
8682b948146SAndy Fiddaman 	if (!gdb_active)
8692b948146SAndy Fiddaman 		return;
870*32640292SAndy Fiddaman 	vcpuid = vcpu_id(vcpu);
871*32640292SAndy Fiddaman 	debug("$vCPU %d MTRAP\n", vcpuid);
872154972afSPatrick Mooney 	pthread_mutex_lock(&gdb_lock);
873*32640292SAndy Fiddaman 	vs = &vcpu_state[vcpuid];
874154972afSPatrick Mooney 	if (vs->stepping) {
875154972afSPatrick Mooney 		vs->stepping = false;
876154972afSPatrick Mooney 		vs->stepped = true;
877*32640292SAndy Fiddaman 		vm_set_capability(vcpu, VM_CAP_MTRAP_EXIT, 0);
878154972afSPatrick Mooney 		while (vs->stepped) {
879154972afSPatrick Mooney 			if (stopped_vcpu == -1) {
880*32640292SAndy Fiddaman 				debug("$vCPU %d reporting step\n", vcpuid);
881*32640292SAndy Fiddaman 				stopped_vcpu = vcpuid;
882154972afSPatrick Mooney 				gdb_suspend_vcpus();
883154972afSPatrick Mooney 			}
884154972afSPatrick Mooney 			_gdb_cpu_suspend(vcpu, true);
885154972afSPatrick Mooney 		}
886154972afSPatrick Mooney 		gdb_cpu_resume(vcpu);
887154972afSPatrick Mooney 	}
888154972afSPatrick Mooney 	pthread_mutex_unlock(&gdb_lock);
889154972afSPatrick Mooney }
890154972afSPatrick Mooney 
891154972afSPatrick Mooney static struct breakpoint *
find_breakpoint(uint64_t gpa)892154972afSPatrick Mooney find_breakpoint(uint64_t gpa)
893154972afSPatrick Mooney {
894154972afSPatrick Mooney 	struct breakpoint *bp;
895154972afSPatrick Mooney 
896154972afSPatrick Mooney 	TAILQ_FOREACH(bp, &breakpoints, link) {
897154972afSPatrick Mooney 		if (bp->gpa == gpa)
898154972afSPatrick Mooney 			return (bp);
899154972afSPatrick Mooney 	}
900154972afSPatrick Mooney 	return (NULL);
901154972afSPatrick Mooney }
902154972afSPatrick Mooney 
903154972afSPatrick Mooney void
gdb_cpu_breakpoint(struct vcpu * vcpu,struct vm_exit * vmexit)904*32640292SAndy Fiddaman gdb_cpu_breakpoint(struct vcpu *vcpu, struct vm_exit *vmexit)
905154972afSPatrick Mooney {
906154972afSPatrick Mooney 	struct breakpoint *bp;
907154972afSPatrick Mooney 	struct vcpu_state *vs;
908154972afSPatrick Mooney 	uint64_t gpa;
909*32640292SAndy Fiddaman 	int error, vcpuid;
910154972afSPatrick Mooney 
9112b948146SAndy Fiddaman 	if (!gdb_active) {
9122b948146SAndy Fiddaman 		fprintf(stderr, "vm_loop: unexpected VMEXIT_DEBUG\n");
9132b948146SAndy Fiddaman 		exit(4);
9142b948146SAndy Fiddaman 	}
915*32640292SAndy Fiddaman 	vcpuid = vcpu_id(vcpu);
916154972afSPatrick Mooney 	pthread_mutex_lock(&gdb_lock);
917154972afSPatrick Mooney 	error = guest_vaddr2paddr(vcpu, vmexit->rip, &gpa);
918154972afSPatrick Mooney 	assert(error == 1);
919154972afSPatrick Mooney 	bp = find_breakpoint(gpa);
920154972afSPatrick Mooney 	if (bp != NULL) {
921*32640292SAndy Fiddaman 		vs = &vcpu_state[vcpuid];
922154972afSPatrick Mooney 		assert(vs->stepping == false);
923154972afSPatrick Mooney 		assert(vs->stepped == false);
924154972afSPatrick Mooney 		assert(vs->hit_swbreak == false);
925154972afSPatrick Mooney 		vs->hit_swbreak = true;
926*32640292SAndy Fiddaman 		vm_set_register(vcpu, VM_REG_GUEST_RIP, vmexit->rip);
927154972afSPatrick Mooney 		for (;;) {
928154972afSPatrick Mooney 			if (stopped_vcpu == -1) {
929*32640292SAndy Fiddaman 				debug("$vCPU %d reporting breakpoint at rip %#lx\n",
930*32640292SAndy Fiddaman 				    vcpuid, vmexit->rip);
931*32640292SAndy Fiddaman 				stopped_vcpu = vcpuid;
932154972afSPatrick Mooney 				gdb_suspend_vcpus();
933154972afSPatrick Mooney 			}
934154972afSPatrick Mooney 			_gdb_cpu_suspend(vcpu, true);
935154972afSPatrick Mooney 			if (!vs->hit_swbreak) {
936154972afSPatrick Mooney 				/* Breakpoint reported. */
937154972afSPatrick Mooney 				break;
938154972afSPatrick Mooney 			}
939154972afSPatrick Mooney 			bp = find_breakpoint(gpa);
940154972afSPatrick Mooney 			if (bp == NULL) {
941154972afSPatrick Mooney 				/* Breakpoint was removed. */
942154972afSPatrick Mooney 				vs->hit_swbreak = false;
943154972afSPatrick Mooney 				break;
944154972afSPatrick Mooney 			}
945154972afSPatrick Mooney 		}
946154972afSPatrick Mooney 		gdb_cpu_resume(vcpu);
947154972afSPatrick Mooney 	} else {
948*32640292SAndy Fiddaman 		debug("$vCPU %d injecting breakpoint at rip %#lx\n", vcpuid,
949154972afSPatrick Mooney 		    vmexit->rip);
950*32640292SAndy Fiddaman 		error = vm_set_register(vcpu, VM_REG_GUEST_ENTRY_INST_LENGTH,
951*32640292SAndy Fiddaman 		    vmexit->u.bpt.inst_length);
952154972afSPatrick Mooney 		assert(error == 0);
953*32640292SAndy Fiddaman 		error = vm_inject_exception(vcpu, IDT_BP, 0, 0, 0);
954154972afSPatrick Mooney 		assert(error == 0);
955154972afSPatrick Mooney 	}
956154972afSPatrick Mooney 	pthread_mutex_unlock(&gdb_lock);
957154972afSPatrick Mooney }
958154972afSPatrick Mooney 
9594c87aefeSPatrick Mooney static bool
gdb_step_vcpu(struct vcpu * vcpu)960*32640292SAndy Fiddaman gdb_step_vcpu(struct vcpu *vcpu)
9614c87aefeSPatrick Mooney {
962*32640292SAndy Fiddaman 	int error, val, vcpuid;
9634c87aefeSPatrick Mooney 
964*32640292SAndy Fiddaman 	vcpuid = vcpu_id(vcpu);
965*32640292SAndy Fiddaman 	debug("$vCPU %d step\n", vcpuid);
966*32640292SAndy Fiddaman 	error = vm_get_capability(vcpu, VM_CAP_MTRAP_EXIT, &val);
9674c87aefeSPatrick Mooney 	if (error < 0)
9684c87aefeSPatrick Mooney 		return (false);
969154972afSPatrick Mooney 
970154972afSPatrick Mooney 	discard_stop();
971*32640292SAndy Fiddaman 	vcpu_state[vcpuid].stepping = true;
972*32640292SAndy Fiddaman 	vm_resume_cpu(vcpu);
973*32640292SAndy Fiddaman 	CPU_CLR(vcpuid, &vcpus_suspended);
9744c87aefeSPatrick Mooney 	pthread_cond_broadcast(&idle_vcpus);
9754c87aefeSPatrick Mooney 	return (true);
9764c87aefeSPatrick Mooney }
9774c87aefeSPatrick Mooney 
9784c87aefeSPatrick Mooney static void
gdb_resume_vcpus(void)9794c87aefeSPatrick Mooney gdb_resume_vcpus(void)
9804c87aefeSPatrick Mooney {
9814c87aefeSPatrick Mooney 
9824c87aefeSPatrick Mooney 	assert(pthread_mutex_isowned_np(&gdb_lock));
983*32640292SAndy Fiddaman 	vm_resume_all_cpus(ctx);
9844c87aefeSPatrick Mooney 	debug("resuming all CPUs\n");
9854c87aefeSPatrick Mooney 	CPU_ZERO(&vcpus_suspended);
9864c87aefeSPatrick Mooney 	pthread_cond_broadcast(&idle_vcpus);
9874c87aefeSPatrick Mooney }
9884c87aefeSPatrick Mooney 
9894c87aefeSPatrick Mooney static void
gdb_read_regs(void)9904c87aefeSPatrick Mooney gdb_read_regs(void)
9914c87aefeSPatrick Mooney {
9924c87aefeSPatrick Mooney 	uint64_t regvals[nitems(gdb_regset)];
9934c87aefeSPatrick Mooney 
994*32640292SAndy Fiddaman 	if (vm_get_register_set(vcpus[cur_vcpu], nitems(gdb_regset),
9954c87aefeSPatrick Mooney 	    gdb_regset, regvals) == -1) {
9964c87aefeSPatrick Mooney 		send_error(errno);
9974c87aefeSPatrick Mooney 		return;
9984c87aefeSPatrick Mooney 	}
9994c87aefeSPatrick Mooney 	start_packet();
100059d65d31SAndy Fiddaman 	for (size_t i = 0; i < nitems(regvals); i++)
10014c87aefeSPatrick Mooney 		append_unsigned_native(regvals[i], gdb_regsize[i]);
10024c87aefeSPatrick Mooney 	finish_packet();
10034c87aefeSPatrick Mooney }
10044c87aefeSPatrick Mooney 
10054c87aefeSPatrick Mooney static void
gdb_read_mem(const uint8_t * data,size_t len)10064c87aefeSPatrick Mooney gdb_read_mem(const uint8_t *data, size_t len)
10074c87aefeSPatrick Mooney {
10084c87aefeSPatrick Mooney 	uint64_t gpa, gva, val;
10094c87aefeSPatrick Mooney 	uint8_t *cp;
10104c87aefeSPatrick Mooney 	size_t resid, todo, bytes;
10114c87aefeSPatrick Mooney 	bool started;
10124c87aefeSPatrick Mooney 	int error;
10134c87aefeSPatrick Mooney 
10144c87aefeSPatrick Mooney 	/* Skip 'm' */
10154c87aefeSPatrick Mooney 	data += 1;
10164c87aefeSPatrick Mooney 	len -= 1;
10174c87aefeSPatrick Mooney 
10184c87aefeSPatrick Mooney 	/* Parse and consume address. */
10194c87aefeSPatrick Mooney 	cp = memchr(data, ',', len);
10204c87aefeSPatrick Mooney 	if (cp == NULL || cp == data) {
10214c87aefeSPatrick Mooney 		send_error(EINVAL);
10224c87aefeSPatrick Mooney 		return;
10234c87aefeSPatrick Mooney 	}
10244c87aefeSPatrick Mooney 	gva = parse_integer(data, cp - data);
10254c87aefeSPatrick Mooney 	len -= (cp - data) + 1;
10264c87aefeSPatrick Mooney 	data += (cp - data) + 1;
10274c87aefeSPatrick Mooney 
10284c87aefeSPatrick Mooney 	/* Parse length. */
10294c87aefeSPatrick Mooney 	resid = parse_integer(data, len);
10304c87aefeSPatrick Mooney 
10314c87aefeSPatrick Mooney 	started = false;
10324c87aefeSPatrick Mooney 	while (resid > 0) {
1033*32640292SAndy Fiddaman 		error = guest_vaddr2paddr(vcpus[cur_vcpu], gva, &gpa);
10344c87aefeSPatrick Mooney 		if (error == -1) {
10354c87aefeSPatrick Mooney 			if (started)
10364c87aefeSPatrick Mooney 				finish_packet();
10374c87aefeSPatrick Mooney 			else
10384c87aefeSPatrick Mooney 				send_error(errno);
10394c87aefeSPatrick Mooney 			return;
10404c87aefeSPatrick Mooney 		}
10414c87aefeSPatrick Mooney 		if (error == 0) {
10424c87aefeSPatrick Mooney 			if (started)
10434c87aefeSPatrick Mooney 				finish_packet();
10444c87aefeSPatrick Mooney 			else
10454c87aefeSPatrick Mooney 				send_error(EFAULT);
10464c87aefeSPatrick Mooney 			return;
10474c87aefeSPatrick Mooney 		}
10484c87aefeSPatrick Mooney 
10494c87aefeSPatrick Mooney 		/* Read bytes from current page. */
10504c87aefeSPatrick Mooney 		todo = getpagesize() - gpa % getpagesize();
10514c87aefeSPatrick Mooney 		if (todo > resid)
10524c87aefeSPatrick Mooney 			todo = resid;
10534c87aefeSPatrick Mooney 
10544c87aefeSPatrick Mooney 		cp = paddr_guest2host(ctx, gpa, todo);
10554c87aefeSPatrick Mooney 		if (cp != NULL) {
10564c87aefeSPatrick Mooney 			/*
10574c87aefeSPatrick Mooney 			 * If this page is guest RAM, read it a byte
10584c87aefeSPatrick Mooney 			 * at a time.
10594c87aefeSPatrick Mooney 			 */
10604c87aefeSPatrick Mooney 			if (!started) {
10614c87aefeSPatrick Mooney 				start_packet();
10624c87aefeSPatrick Mooney 				started = true;
10634c87aefeSPatrick Mooney 			}
10644c87aefeSPatrick Mooney 			while (todo > 0) {
10654c87aefeSPatrick Mooney 				append_byte(*cp);
10664c87aefeSPatrick Mooney 				cp++;
10674c87aefeSPatrick Mooney 				gpa++;
10684c87aefeSPatrick Mooney 				gva++;
10694c87aefeSPatrick Mooney 				resid--;
10704c87aefeSPatrick Mooney 				todo--;
10714c87aefeSPatrick Mooney 			}
10724c87aefeSPatrick Mooney 		} else {
10734c87aefeSPatrick Mooney 			/*
10744c87aefeSPatrick Mooney 			 * If this page isn't guest RAM, try to handle
10754c87aefeSPatrick Mooney 			 * it via MMIO.  For MMIO requests, use
10764c87aefeSPatrick Mooney 			 * aligned reads of words when possible.
10774c87aefeSPatrick Mooney 			 */
10784c87aefeSPatrick Mooney 			while (todo > 0) {
10794c87aefeSPatrick Mooney 				if (gpa & 1 || todo == 1)
10804c87aefeSPatrick Mooney 					bytes = 1;
10814c87aefeSPatrick Mooney 				else if (gpa & 2 || todo == 2)
10824c87aefeSPatrick Mooney 					bytes = 2;
10834c87aefeSPatrick Mooney 				else
10844c87aefeSPatrick Mooney 					bytes = 4;
1085*32640292SAndy Fiddaman 				error = read_mem(vcpus[cur_vcpu], gpa, &val,
10864c87aefeSPatrick Mooney 				    bytes);
10874c87aefeSPatrick Mooney 				if (error == 0) {
10884c87aefeSPatrick Mooney 					if (!started) {
10894c87aefeSPatrick Mooney 						start_packet();
10904c87aefeSPatrick Mooney 						started = true;
10914c87aefeSPatrick Mooney 					}
10924c87aefeSPatrick Mooney 					gpa += bytes;
10934c87aefeSPatrick Mooney 					gva += bytes;
10944c87aefeSPatrick Mooney 					resid -= bytes;
10954c87aefeSPatrick Mooney 					todo -= bytes;
10964c87aefeSPatrick Mooney 					while (bytes > 0) {
10974c87aefeSPatrick Mooney 						append_byte(val);
10984c87aefeSPatrick Mooney 						val >>= 8;
10994c87aefeSPatrick Mooney 						bytes--;
11004c87aefeSPatrick Mooney 					}
11014c87aefeSPatrick Mooney 				} else {
11024c87aefeSPatrick Mooney 					if (started)
11034c87aefeSPatrick Mooney 						finish_packet();
11044c87aefeSPatrick Mooney 					else
11054c87aefeSPatrick Mooney 						send_error(EFAULT);
11064c87aefeSPatrick Mooney 					return;
11074c87aefeSPatrick Mooney 				}
11084c87aefeSPatrick Mooney 			}
11094c87aefeSPatrick Mooney 		}
11104c87aefeSPatrick Mooney 		assert(resid == 0 || gpa % getpagesize() == 0);
11114c87aefeSPatrick Mooney 	}
11124c87aefeSPatrick Mooney 	if (!started)
11134c87aefeSPatrick Mooney 		start_packet();
11144c87aefeSPatrick Mooney 	finish_packet();
11154c87aefeSPatrick Mooney }
11164c87aefeSPatrick Mooney 
11174c87aefeSPatrick Mooney static void
gdb_write_mem(const uint8_t * data,size_t len)11184c87aefeSPatrick Mooney gdb_write_mem(const uint8_t *data, size_t len)
11194c87aefeSPatrick Mooney {
11204c87aefeSPatrick Mooney 	uint64_t gpa, gva, val;
11214c87aefeSPatrick Mooney 	uint8_t *cp;
11224c87aefeSPatrick Mooney 	size_t resid, todo, bytes;
11234c87aefeSPatrick Mooney 	int error;
11244c87aefeSPatrick Mooney 
11254c87aefeSPatrick Mooney 	/* Skip 'M' */
11264c87aefeSPatrick Mooney 	data += 1;
11274c87aefeSPatrick Mooney 	len -= 1;
11284c87aefeSPatrick Mooney 
11294c87aefeSPatrick Mooney 	/* Parse and consume address. */
11304c87aefeSPatrick Mooney 	cp = memchr(data, ',', len);
11314c87aefeSPatrick Mooney 	if (cp == NULL || cp == data) {
11324c87aefeSPatrick Mooney 		send_error(EINVAL);
11334c87aefeSPatrick Mooney 		return;
11344c87aefeSPatrick Mooney 	}
11354c87aefeSPatrick Mooney 	gva = parse_integer(data, cp - data);
11364c87aefeSPatrick Mooney 	len -= (cp - data) + 1;
11374c87aefeSPatrick Mooney 	data += (cp - data) + 1;
11384c87aefeSPatrick Mooney 
11394c87aefeSPatrick Mooney 	/* Parse and consume length. */
11404c87aefeSPatrick Mooney 	cp = memchr(data, ':', len);
11414c87aefeSPatrick Mooney 	if (cp == NULL || cp == data) {
11424c87aefeSPatrick Mooney 		send_error(EINVAL);
11434c87aefeSPatrick Mooney 		return;
11444c87aefeSPatrick Mooney 	}
11454c87aefeSPatrick Mooney 	resid = parse_integer(data, cp - data);
11464c87aefeSPatrick Mooney 	len -= (cp - data) + 1;
11474c87aefeSPatrick Mooney 	data += (cp - data) + 1;
11484c87aefeSPatrick Mooney 
11494c87aefeSPatrick Mooney 	/* Verify the available bytes match the length. */
11504c87aefeSPatrick Mooney 	if (len != resid * 2) {
11514c87aefeSPatrick Mooney 		send_error(EINVAL);
11524c87aefeSPatrick Mooney 		return;
11534c87aefeSPatrick Mooney 	}
11544c87aefeSPatrick Mooney 
11554c87aefeSPatrick Mooney 	while (resid > 0) {
1156*32640292SAndy Fiddaman 		error = guest_vaddr2paddr(vcpus[cur_vcpu], gva, &gpa);
11574c87aefeSPatrick Mooney 		if (error == -1) {
11584c87aefeSPatrick Mooney 			send_error(errno);
11594c87aefeSPatrick Mooney 			return;
11604c87aefeSPatrick Mooney 		}
11614c87aefeSPatrick Mooney 		if (error == 0) {
11624c87aefeSPatrick Mooney 			send_error(EFAULT);
11634c87aefeSPatrick Mooney 			return;
11644c87aefeSPatrick Mooney 		}
11654c87aefeSPatrick Mooney 
11664c87aefeSPatrick Mooney 		/* Write bytes to current page. */
11674c87aefeSPatrick Mooney 		todo = getpagesize() - gpa % getpagesize();
11684c87aefeSPatrick Mooney 		if (todo > resid)
11694c87aefeSPatrick Mooney 			todo = resid;
11704c87aefeSPatrick Mooney 
11714c87aefeSPatrick Mooney 		cp = paddr_guest2host(ctx, gpa, todo);
11724c87aefeSPatrick Mooney 		if (cp != NULL) {
11734c87aefeSPatrick Mooney 			/*
11744c87aefeSPatrick Mooney 			 * If this page is guest RAM, write it a byte
11754c87aefeSPatrick Mooney 			 * at a time.
11764c87aefeSPatrick Mooney 			 */
11774c87aefeSPatrick Mooney 			while (todo > 0) {
11784c87aefeSPatrick Mooney 				assert(len >= 2);
11794c87aefeSPatrick Mooney 				*cp = parse_byte(data);
11804c87aefeSPatrick Mooney 				data += 2;
11814c87aefeSPatrick Mooney 				len -= 2;
11824c87aefeSPatrick Mooney 				cp++;
11834c87aefeSPatrick Mooney 				gpa++;
11844c87aefeSPatrick Mooney 				gva++;
11854c87aefeSPatrick Mooney 				resid--;
11864c87aefeSPatrick Mooney 				todo--;
11874c87aefeSPatrick Mooney 			}
11884c87aefeSPatrick Mooney 		} else {
11894c87aefeSPatrick Mooney 			/*
11904c87aefeSPatrick Mooney 			 * If this page isn't guest RAM, try to handle
11914c87aefeSPatrick Mooney 			 * it via MMIO.  For MMIO requests, use
11924c87aefeSPatrick Mooney 			 * aligned writes of words when possible.
11934c87aefeSPatrick Mooney 			 */
11944c87aefeSPatrick Mooney 			while (todo > 0) {
11954c87aefeSPatrick Mooney 				if (gpa & 1 || todo == 1) {
11964c87aefeSPatrick Mooney 					bytes = 1;
11974c87aefeSPatrick Mooney 					val = parse_byte(data);
11984c87aefeSPatrick Mooney 				} else if (gpa & 2 || todo == 2) {
11994c87aefeSPatrick Mooney 					bytes = 2;
120084659b24SMichael Zeller 					val = be16toh(parse_integer(data, 4));
12014c87aefeSPatrick Mooney 				} else {
12024c87aefeSPatrick Mooney 					bytes = 4;
120384659b24SMichael Zeller 					val = be32toh(parse_integer(data, 8));
12044c87aefeSPatrick Mooney 				}
1205*32640292SAndy Fiddaman 				error = write_mem(vcpus[cur_vcpu], gpa, val,
12064c87aefeSPatrick Mooney 				    bytes);
12074c87aefeSPatrick Mooney 				if (error == 0) {
12084c87aefeSPatrick Mooney 					gpa += bytes;
12094c87aefeSPatrick Mooney 					gva += bytes;
12104c87aefeSPatrick Mooney 					resid -= bytes;
12114c87aefeSPatrick Mooney 					todo -= bytes;
12124c87aefeSPatrick Mooney 					data += 2 * bytes;
12134c87aefeSPatrick Mooney 					len -= 2 * bytes;
12144c87aefeSPatrick Mooney 				} else {
12154c87aefeSPatrick Mooney 					send_error(EFAULT);
12164c87aefeSPatrick Mooney 					return;
12174c87aefeSPatrick Mooney 				}
12184c87aefeSPatrick Mooney 			}
12194c87aefeSPatrick Mooney 		}
12204c87aefeSPatrick Mooney 		assert(resid == 0 || gpa % getpagesize() == 0);
12214c87aefeSPatrick Mooney 	}
12224c87aefeSPatrick Mooney 	assert(len == 0);
12234c87aefeSPatrick Mooney 	send_ok();
12244c87aefeSPatrick Mooney }
12254c87aefeSPatrick Mooney 
12264c87aefeSPatrick Mooney static bool
set_breakpoint_caps(bool enable)1227154972afSPatrick Mooney set_breakpoint_caps(bool enable)
1228154972afSPatrick Mooney {
1229154972afSPatrick Mooney 	cpuset_t mask;
1230154972afSPatrick Mooney 	int vcpu;
1231154972afSPatrick Mooney 
1232154972afSPatrick Mooney 	mask = vcpus_active;
1233154972afSPatrick Mooney 	while (!CPU_EMPTY(&mask)) {
1234154972afSPatrick Mooney 		vcpu = CPU_FFS(&mask) - 1;
1235154972afSPatrick Mooney 		CPU_CLR(vcpu, &mask);
1236*32640292SAndy Fiddaman 		if (vm_set_capability(vcpus[vcpu], VM_CAP_BPT_EXIT,
1237154972afSPatrick Mooney 		    enable ? 1 : 0) < 0)
1238154972afSPatrick Mooney 			return (false);
1239154972afSPatrick Mooney 		debug("$vCPU %d %sabled breakpoint exits\n", vcpu,
1240154972afSPatrick Mooney 		    enable ? "en" : "dis");
1241154972afSPatrick Mooney 	}
1242154972afSPatrick Mooney 	return (true);
1243154972afSPatrick Mooney }
1244154972afSPatrick Mooney 
1245154972afSPatrick Mooney static void
remove_all_sw_breakpoints(void)1246154972afSPatrick Mooney remove_all_sw_breakpoints(void)
1247154972afSPatrick Mooney {
1248154972afSPatrick Mooney 	struct breakpoint *bp, *nbp;
1249154972afSPatrick Mooney 	uint8_t *cp;
1250154972afSPatrick Mooney 
1251154972afSPatrick Mooney 	if (TAILQ_EMPTY(&breakpoints))
1252154972afSPatrick Mooney 		return;
1253154972afSPatrick Mooney 
1254154972afSPatrick Mooney 	TAILQ_FOREACH_SAFE(bp, &breakpoints, link, nbp) {
1255154972afSPatrick Mooney 		debug("remove breakpoint at %#lx\n", bp->gpa);
1256154972afSPatrick Mooney 		cp = paddr_guest2host(ctx, bp->gpa, 1);
1257154972afSPatrick Mooney 		*cp = bp->shadow_inst;
1258154972afSPatrick Mooney 		TAILQ_REMOVE(&breakpoints, bp, link);
1259154972afSPatrick Mooney 		free(bp);
1260154972afSPatrick Mooney 	}
1261154972afSPatrick Mooney 	TAILQ_INIT(&breakpoints);
1262154972afSPatrick Mooney 	set_breakpoint_caps(false);
1263154972afSPatrick Mooney }
1264154972afSPatrick Mooney 
1265154972afSPatrick Mooney static void
update_sw_breakpoint(uint64_t gva,int kind,bool insert)1266154972afSPatrick Mooney update_sw_breakpoint(uint64_t gva, int kind, bool insert)
1267154972afSPatrick Mooney {
1268154972afSPatrick Mooney 	struct breakpoint *bp;
1269154972afSPatrick Mooney 	uint64_t gpa;
1270154972afSPatrick Mooney 	uint8_t *cp;
1271154972afSPatrick Mooney 	int error;
1272154972afSPatrick Mooney 
1273154972afSPatrick Mooney 	if (kind != 1) {
1274154972afSPatrick Mooney 		send_error(EINVAL);
1275154972afSPatrick Mooney 		return;
1276154972afSPatrick Mooney 	}
1277154972afSPatrick Mooney 
1278*32640292SAndy Fiddaman 	error = guest_vaddr2paddr(vcpus[cur_vcpu], gva, &gpa);
1279154972afSPatrick Mooney 	if (error == -1) {
1280154972afSPatrick Mooney 		send_error(errno);
1281154972afSPatrick Mooney 		return;
1282154972afSPatrick Mooney 	}
1283154972afSPatrick Mooney 	if (error == 0) {
1284154972afSPatrick Mooney 		send_error(EFAULT);
1285154972afSPatrick Mooney 		return;
1286154972afSPatrick Mooney 	}
1287154972afSPatrick Mooney 
1288154972afSPatrick Mooney 	cp = paddr_guest2host(ctx, gpa, 1);
1289154972afSPatrick Mooney 
1290154972afSPatrick Mooney 	/* Only permit breakpoints in guest RAM. */
1291154972afSPatrick Mooney 	if (cp == NULL) {
1292154972afSPatrick Mooney 		send_error(EFAULT);
1293154972afSPatrick Mooney 		return;
1294154972afSPatrick Mooney 	}
1295154972afSPatrick Mooney 
1296154972afSPatrick Mooney 	/* Find any existing breakpoint. */
1297154972afSPatrick Mooney 	bp = find_breakpoint(gpa);
1298154972afSPatrick Mooney 
1299154972afSPatrick Mooney 	/*
1300154972afSPatrick Mooney 	 * Silently ignore duplicate commands since the protocol
1301154972afSPatrick Mooney 	 * requires these packets to be idempotent.
1302154972afSPatrick Mooney 	 */
1303154972afSPatrick Mooney 	if (insert) {
1304154972afSPatrick Mooney 		if (bp == NULL) {
1305154972afSPatrick Mooney 			if (TAILQ_EMPTY(&breakpoints) &&
1306154972afSPatrick Mooney 			    !set_breakpoint_caps(true)) {
1307154972afSPatrick Mooney 				send_empty_response();
1308154972afSPatrick Mooney 				return;
1309154972afSPatrick Mooney 			}
1310154972afSPatrick Mooney 			bp = malloc(sizeof(*bp));
1311154972afSPatrick Mooney 			bp->gpa = gpa;
1312154972afSPatrick Mooney 			bp->shadow_inst = *cp;
1313154972afSPatrick Mooney 			*cp = 0xcc;	/* INT 3 */
1314154972afSPatrick Mooney 			TAILQ_INSERT_TAIL(&breakpoints, bp, link);
1315154972afSPatrick Mooney 			debug("new breakpoint at %#lx\n", gpa);
1316154972afSPatrick Mooney 		}
1317154972afSPatrick Mooney 	} else {
1318154972afSPatrick Mooney 		if (bp != NULL) {
1319154972afSPatrick Mooney 			debug("remove breakpoint at %#lx\n", gpa);
1320154972afSPatrick Mooney 			*cp = bp->shadow_inst;
1321154972afSPatrick Mooney 			TAILQ_REMOVE(&breakpoints, bp, link);
1322154972afSPatrick Mooney 			free(bp);
1323154972afSPatrick Mooney 			if (TAILQ_EMPTY(&breakpoints))
1324154972afSPatrick Mooney 				set_breakpoint_caps(false);
1325154972afSPatrick Mooney 		}
1326154972afSPatrick Mooney 	}
1327154972afSPatrick Mooney 	send_ok();
1328154972afSPatrick Mooney }
1329154972afSPatrick Mooney 
1330154972afSPatrick Mooney static void
parse_breakpoint(const uint8_t * data,size_t len)1331154972afSPatrick Mooney parse_breakpoint(const uint8_t *data, size_t len)
1332154972afSPatrick Mooney {
1333154972afSPatrick Mooney 	uint64_t gva;
1334154972afSPatrick Mooney 	uint8_t *cp;
1335154972afSPatrick Mooney 	bool insert;
1336154972afSPatrick Mooney 	int kind, type;
1337154972afSPatrick Mooney 
1338154972afSPatrick Mooney 	insert = data[0] == 'Z';
1339154972afSPatrick Mooney 
1340154972afSPatrick Mooney 	/* Skip 'Z/z' */
1341154972afSPatrick Mooney 	data += 1;
1342154972afSPatrick Mooney 	len -= 1;
1343154972afSPatrick Mooney 
1344154972afSPatrick Mooney 	/* Parse and consume type. */
1345154972afSPatrick Mooney 	cp = memchr(data, ',', len);
1346154972afSPatrick Mooney 	if (cp == NULL || cp == data) {
1347154972afSPatrick Mooney 		send_error(EINVAL);
1348154972afSPatrick Mooney 		return;
1349154972afSPatrick Mooney 	}
1350154972afSPatrick Mooney 	type = parse_integer(data, cp - data);
1351154972afSPatrick Mooney 	len -= (cp - data) + 1;
1352154972afSPatrick Mooney 	data += (cp - data) + 1;
1353154972afSPatrick Mooney 
1354154972afSPatrick Mooney 	/* Parse and consume address. */
1355154972afSPatrick Mooney 	cp = memchr(data, ',', len);
1356154972afSPatrick Mooney 	if (cp == NULL || cp == data) {
1357154972afSPatrick Mooney 		send_error(EINVAL);
1358154972afSPatrick Mooney 		return;
1359154972afSPatrick Mooney 	}
1360154972afSPatrick Mooney 	gva = parse_integer(data, cp - data);
1361154972afSPatrick Mooney 	len -= (cp - data) + 1;
1362154972afSPatrick Mooney 	data += (cp - data) + 1;
1363154972afSPatrick Mooney 
1364154972afSPatrick Mooney 	/* Parse and consume kind. */
1365154972afSPatrick Mooney 	cp = memchr(data, ';', len);
1366154972afSPatrick Mooney 	if (cp == data) {
1367154972afSPatrick Mooney 		send_error(EINVAL);
1368154972afSPatrick Mooney 		return;
1369154972afSPatrick Mooney 	}
1370154972afSPatrick Mooney 	if (cp != NULL) {
1371154972afSPatrick Mooney 		/*
1372154972afSPatrick Mooney 		 * We do not advertise support for either the
1373154972afSPatrick Mooney 		 * ConditionalBreakpoints or BreakpointCommands
1374154972afSPatrick Mooney 		 * features, so we should not be getting conditions or
1375154972afSPatrick Mooney 		 * commands from the remote end.
1376154972afSPatrick Mooney 		 */
1377154972afSPatrick Mooney 		send_empty_response();
1378154972afSPatrick Mooney 		return;
1379154972afSPatrick Mooney 	}
1380154972afSPatrick Mooney 	kind = parse_integer(data, len);
1381154972afSPatrick Mooney 	data += len;
1382154972afSPatrick Mooney 	len = 0;
1383154972afSPatrick Mooney 
1384154972afSPatrick Mooney 	switch (type) {
1385154972afSPatrick Mooney 	case 0:
1386154972afSPatrick Mooney 		update_sw_breakpoint(gva, kind, insert);
1387154972afSPatrick Mooney 		break;
1388154972afSPatrick Mooney 	default:
1389154972afSPatrick Mooney 		send_empty_response();
1390154972afSPatrick Mooney 		break;
1391154972afSPatrick Mooney 	}
1392154972afSPatrick Mooney }
1393154972afSPatrick Mooney 
1394154972afSPatrick Mooney static bool
command_equals(const uint8_t * data,size_t len,const char * cmd)13954c87aefeSPatrick Mooney command_equals(const uint8_t *data, size_t len, const char *cmd)
13964c87aefeSPatrick Mooney {
13974c87aefeSPatrick Mooney 
13984c87aefeSPatrick Mooney 	if (strlen(cmd) > len)
13994c87aefeSPatrick Mooney 		return (false);
14004c87aefeSPatrick Mooney 	return (memcmp(data, cmd, strlen(cmd)) == 0);
14014c87aefeSPatrick Mooney }
14024c87aefeSPatrick Mooney 
14034c87aefeSPatrick Mooney static void
check_features(const uint8_t * data,size_t len)14044c87aefeSPatrick Mooney check_features(const uint8_t *data, size_t len)
14054c87aefeSPatrick Mooney {
14064c87aefeSPatrick Mooney 	char *feature, *next_feature, *str, *value;
14074c87aefeSPatrick Mooney 	bool supported;
14084c87aefeSPatrick Mooney 
14094c87aefeSPatrick Mooney 	str = malloc(len + 1);
14104c87aefeSPatrick Mooney 	memcpy(str, data, len);
14114c87aefeSPatrick Mooney 	str[len] = '\0';
14124c87aefeSPatrick Mooney 	next_feature = str;
14134c87aefeSPatrick Mooney 
14144c87aefeSPatrick Mooney 	while ((feature = strsep(&next_feature, ";")) != NULL) {
14154c87aefeSPatrick Mooney 		/*
14164c87aefeSPatrick Mooney 		 * Null features shouldn't exist, but skip if they
14174c87aefeSPatrick Mooney 		 * do.
14184c87aefeSPatrick Mooney 		 */
14194c87aefeSPatrick Mooney 		if (strcmp(feature, "") == 0)
14204c87aefeSPatrick Mooney 			continue;
14214c87aefeSPatrick Mooney 
14224c87aefeSPatrick Mooney 		/*
14234c87aefeSPatrick Mooney 		 * Look for the value or supported / not supported
14244c87aefeSPatrick Mooney 		 * flag.
14254c87aefeSPatrick Mooney 		 */
14264c87aefeSPatrick Mooney 		value = strchr(feature, '=');
14274c87aefeSPatrick Mooney 		if (value != NULL) {
14284c87aefeSPatrick Mooney 			*value = '\0';
14294c87aefeSPatrick Mooney 			value++;
14304c87aefeSPatrick Mooney 			supported = true;
14314c87aefeSPatrick Mooney 		} else {
14324c87aefeSPatrick Mooney 			value = feature + strlen(feature) - 1;
14334c87aefeSPatrick Mooney 			switch (*value) {
14344c87aefeSPatrick Mooney 			case '+':
14354c87aefeSPatrick Mooney 				supported = true;
14364c87aefeSPatrick Mooney 				break;
14374c87aefeSPatrick Mooney 			case '-':
14384c87aefeSPatrick Mooney 				supported = false;
14394c87aefeSPatrick Mooney 				break;
14404c87aefeSPatrick Mooney 			default:
14414c87aefeSPatrick Mooney 				/*
14424c87aefeSPatrick Mooney 				 * This is really a protocol error,
14434c87aefeSPatrick Mooney 				 * but we just ignore malformed
14444c87aefeSPatrick Mooney 				 * features for ease of
14454c87aefeSPatrick Mooney 				 * implementation.
14464c87aefeSPatrick Mooney 				 */
14474c87aefeSPatrick Mooney 				continue;
14484c87aefeSPatrick Mooney 			}
14494c87aefeSPatrick Mooney 			value = NULL;
14504c87aefeSPatrick Mooney 		}
14514c87aefeSPatrick Mooney 
1452154972afSPatrick Mooney 		if (strcmp(feature, "swbreak") == 0)
1453154972afSPatrick Mooney 			swbreak_enabled = supported;
1454154972afSPatrick Mooney 
14554c87aefeSPatrick Mooney #ifndef __FreeBSD__
14564c87aefeSPatrick Mooney 		/*
14574c87aefeSPatrick Mooney 		 * The compiler dislikes 'supported' being set but never used.
14584c87aefeSPatrick Mooney 		 * Make it happy here.
14594c87aefeSPatrick Mooney 		 */
14604c87aefeSPatrick Mooney 		if (supported) {
14614c87aefeSPatrick Mooney 			debug("feature '%s' supported\n", feature);
14624c87aefeSPatrick Mooney 		}
14634c87aefeSPatrick Mooney #endif /* __FreeBSD__ */
14644c87aefeSPatrick Mooney 	}
14654c87aefeSPatrick Mooney 	free(str);
14664c87aefeSPatrick Mooney 
14674c87aefeSPatrick Mooney 	start_packet();
14684c87aefeSPatrick Mooney 
14694c87aefeSPatrick Mooney 	/* This is an arbitrary limit. */
14704c87aefeSPatrick Mooney 	append_string("PacketSize=4096");
1471154972afSPatrick Mooney 	append_string(";swbreak+");
14724c87aefeSPatrick Mooney 	finish_packet();
14734c87aefeSPatrick Mooney }
14744c87aefeSPatrick Mooney 
14754c87aefeSPatrick Mooney static void
gdb_query(const uint8_t * data,size_t len)14764c87aefeSPatrick Mooney gdb_query(const uint8_t *data, size_t len)
14774c87aefeSPatrick Mooney {
14784c87aefeSPatrick Mooney 
14794c87aefeSPatrick Mooney 	/*
14804c87aefeSPatrick Mooney 	 * TODO:
14814c87aefeSPatrick Mooney 	 * - qSearch
14824c87aefeSPatrick Mooney 	 */
14834c87aefeSPatrick Mooney 	if (command_equals(data, len, "qAttached")) {
14844c87aefeSPatrick Mooney 		start_packet();
14854c87aefeSPatrick Mooney 		append_char('1');
14864c87aefeSPatrick Mooney 		finish_packet();
14874c87aefeSPatrick Mooney 	} else if (command_equals(data, len, "qC")) {
14884c87aefeSPatrick Mooney 		start_packet();
14894c87aefeSPatrick Mooney 		append_string("QC");
14904c87aefeSPatrick Mooney 		append_integer(cur_vcpu + 1);
14914c87aefeSPatrick Mooney 		finish_packet();
14924c87aefeSPatrick Mooney 	} else if (command_equals(data, len, "qfThreadInfo")) {
14934c87aefeSPatrick Mooney 		cpuset_t mask;
14944c87aefeSPatrick Mooney 		bool first;
14954c87aefeSPatrick Mooney 		int vcpu;
14964c87aefeSPatrick Mooney 
14974c87aefeSPatrick Mooney 		if (CPU_EMPTY(&vcpus_active)) {
14984c87aefeSPatrick Mooney 			send_error(EINVAL);
14994c87aefeSPatrick Mooney 			return;
15004c87aefeSPatrick Mooney 		}
15014c87aefeSPatrick Mooney 		mask = vcpus_active;
15024c87aefeSPatrick Mooney 		start_packet();
15034c87aefeSPatrick Mooney 		append_char('m');
15044c87aefeSPatrick Mooney 		first = true;
15054c87aefeSPatrick Mooney 		while (!CPU_EMPTY(&mask)) {
15064c87aefeSPatrick Mooney 			vcpu = CPU_FFS(&mask) - 1;
15074c87aefeSPatrick Mooney 			CPU_CLR(vcpu, &mask);
15084c87aefeSPatrick Mooney 			if (first)
15094c87aefeSPatrick Mooney 				first = false;
15104c87aefeSPatrick Mooney 			else
15114c87aefeSPatrick Mooney 				append_char(',');
15124c87aefeSPatrick Mooney 			append_integer(vcpu + 1);
15134c87aefeSPatrick Mooney 		}
15144c87aefeSPatrick Mooney 		finish_packet();
15154c87aefeSPatrick Mooney 	} else if (command_equals(data, len, "qsThreadInfo")) {
15164c87aefeSPatrick Mooney 		start_packet();
15174c87aefeSPatrick Mooney 		append_char('l');
15184c87aefeSPatrick Mooney 		finish_packet();
15194c87aefeSPatrick Mooney 	} else if (command_equals(data, len, "qSupported")) {
15204c87aefeSPatrick Mooney 		data += strlen("qSupported");
15214c87aefeSPatrick Mooney 		len -= strlen("qSupported");
15224c87aefeSPatrick Mooney 		check_features(data, len);
15234c87aefeSPatrick Mooney 	} else if (command_equals(data, len, "qThreadExtraInfo")) {
15244c87aefeSPatrick Mooney 		char buf[16];
15254c87aefeSPatrick Mooney 		int tid;
15264c87aefeSPatrick Mooney 
15274c87aefeSPatrick Mooney 		data += strlen("qThreadExtraInfo");
15284c87aefeSPatrick Mooney 		len -= strlen("qThreadExtraInfo");
15294c87aefeSPatrick Mooney 		if (*data != ',') {
15304c87aefeSPatrick Mooney 			send_error(EINVAL);
15314c87aefeSPatrick Mooney 			return;
15324c87aefeSPatrick Mooney 		}
15334c87aefeSPatrick Mooney 		tid = parse_threadid(data + 1, len - 1);
15344c87aefeSPatrick Mooney 		if (tid <= 0 || !CPU_ISSET(tid - 1, &vcpus_active)) {
15354c87aefeSPatrick Mooney 			send_error(EINVAL);
15364c87aefeSPatrick Mooney 			return;
15374c87aefeSPatrick Mooney 		}
15384c87aefeSPatrick Mooney 
15394c87aefeSPatrick Mooney 		snprintf(buf, sizeof(buf), "vCPU %d", tid - 1);
15404c87aefeSPatrick Mooney 		start_packet();
15414c87aefeSPatrick Mooney 		append_asciihex(buf);
15424c87aefeSPatrick Mooney 		finish_packet();
15434c87aefeSPatrick Mooney 	} else
15444c87aefeSPatrick Mooney 		send_empty_response();
15454c87aefeSPatrick Mooney }
15464c87aefeSPatrick Mooney 
15474c87aefeSPatrick Mooney static void
handle_command(const uint8_t * data,size_t len)15484c87aefeSPatrick Mooney handle_command(const uint8_t *data, size_t len)
15494c87aefeSPatrick Mooney {
15504c87aefeSPatrick Mooney 
15514c87aefeSPatrick Mooney 	/* Reject packets with a sequence-id. */
15524c87aefeSPatrick Mooney 	if (len >= 3 && data[0] >= '0' && data[0] <= '9' &&
15534c87aefeSPatrick Mooney 	    data[0] >= '0' && data[0] <= '9' && data[2] == ':') {
15544c87aefeSPatrick Mooney 		send_empty_response();
15554c87aefeSPatrick Mooney 		return;
15564c87aefeSPatrick Mooney 	}
15574c87aefeSPatrick Mooney 
15584c87aefeSPatrick Mooney 	switch (*data) {
15594c87aefeSPatrick Mooney 	case 'c':
15604c87aefeSPatrick Mooney 		if (len != 1) {
15614c87aefeSPatrick Mooney 			send_error(EINVAL);
15624c87aefeSPatrick Mooney 			break;
15634c87aefeSPatrick Mooney 		}
15644c87aefeSPatrick Mooney 
1565154972afSPatrick Mooney 		discard_stop();
15664c87aefeSPatrick Mooney 		gdb_resume_vcpus();
15674c87aefeSPatrick Mooney 		break;
15684c87aefeSPatrick Mooney 	case 'D':
15694c87aefeSPatrick Mooney 		send_ok();
15704c87aefeSPatrick Mooney 
15714c87aefeSPatrick Mooney 		/* TODO: Resume any stopped CPUs. */
15724c87aefeSPatrick Mooney 		break;
15734c87aefeSPatrick Mooney 	case 'g': {
15744c87aefeSPatrick Mooney 		gdb_read_regs();
15754c87aefeSPatrick Mooney 		break;
15764c87aefeSPatrick Mooney 	}
15774c87aefeSPatrick Mooney 	case 'H': {
15784c87aefeSPatrick Mooney 		int tid;
15794c87aefeSPatrick Mooney 
15804c87aefeSPatrick Mooney 		if (data[1] != 'g' && data[1] != 'c') {
15814c87aefeSPatrick Mooney 			send_error(EINVAL);
15824c87aefeSPatrick Mooney 			break;
15834c87aefeSPatrick Mooney 		}
15844c87aefeSPatrick Mooney 		tid = parse_threadid(data + 2, len - 2);
15854c87aefeSPatrick Mooney 		if (tid == -2) {
15864c87aefeSPatrick Mooney 			send_error(EINVAL);
15874c87aefeSPatrick Mooney 			break;
15884c87aefeSPatrick Mooney 		}
15894c87aefeSPatrick Mooney 
15904c87aefeSPatrick Mooney 		if (CPU_EMPTY(&vcpus_active)) {
15914c87aefeSPatrick Mooney 			send_error(EINVAL);
15924c87aefeSPatrick Mooney 			break;
15934c87aefeSPatrick Mooney 		}
15944c87aefeSPatrick Mooney 		if (tid == -1 || tid == 0)
15954c87aefeSPatrick Mooney 			cur_vcpu = CPU_FFS(&vcpus_active) - 1;
15964c87aefeSPatrick Mooney 		else if (CPU_ISSET(tid - 1, &vcpus_active))
15974c87aefeSPatrick Mooney 			cur_vcpu = tid - 1;
15984c87aefeSPatrick Mooney 		else {
15994c87aefeSPatrick Mooney 			send_error(EINVAL);
16004c87aefeSPatrick Mooney 			break;
16014c87aefeSPatrick Mooney 		}
16024c87aefeSPatrick Mooney 		send_ok();
16034c87aefeSPatrick Mooney 		break;
16044c87aefeSPatrick Mooney 	}
16054c87aefeSPatrick Mooney 	case 'm':
16064c87aefeSPatrick Mooney 		gdb_read_mem(data, len);
16074c87aefeSPatrick Mooney 		break;
16084c87aefeSPatrick Mooney 	case 'M':
16094c87aefeSPatrick Mooney 		gdb_write_mem(data, len);
16104c87aefeSPatrick Mooney 		break;
16114c87aefeSPatrick Mooney 	case 'T': {
16124c87aefeSPatrick Mooney 		int tid;
16134c87aefeSPatrick Mooney 
16144c87aefeSPatrick Mooney 		tid = parse_threadid(data + 1, len - 1);
16154c87aefeSPatrick Mooney 		if (tid <= 0 || !CPU_ISSET(tid - 1, &vcpus_active)) {
16164c87aefeSPatrick Mooney 			send_error(EINVAL);
16174c87aefeSPatrick Mooney 			return;
16184c87aefeSPatrick Mooney 		}
16194c87aefeSPatrick Mooney 		send_ok();
16204c87aefeSPatrick Mooney 		break;
16214c87aefeSPatrick Mooney 	}
16224c87aefeSPatrick Mooney 	case 'q':
16234c87aefeSPatrick Mooney 		gdb_query(data, len);
16244c87aefeSPatrick Mooney 		break;
16254c87aefeSPatrick Mooney 	case 's':
16264c87aefeSPatrick Mooney 		if (len != 1) {
16274c87aefeSPatrick Mooney 			send_error(EINVAL);
16284c87aefeSPatrick Mooney 			break;
16294c87aefeSPatrick Mooney 		}
16304c87aefeSPatrick Mooney 
16314c87aefeSPatrick Mooney 		/* Don't send a reply until a stop occurs. */
1632*32640292SAndy Fiddaman 		if (!gdb_step_vcpu(vcpus[cur_vcpu])) {
16334c87aefeSPatrick Mooney 			send_error(EOPNOTSUPP);
16344c87aefeSPatrick Mooney 			break;
16354c87aefeSPatrick Mooney 		}
16364c87aefeSPatrick Mooney 		break;
1637154972afSPatrick Mooney 	case 'z':
1638154972afSPatrick Mooney 	case 'Z':
1639154972afSPatrick Mooney 		parse_breakpoint(data, len);
1640154972afSPatrick Mooney 		break;
16414c87aefeSPatrick Mooney 	case '?':
1642154972afSPatrick Mooney 		report_stop(false);
16434c87aefeSPatrick Mooney 		break;
16444c87aefeSPatrick Mooney 	case 'G': /* TODO */
16454c87aefeSPatrick Mooney 	case 'v':
16464c87aefeSPatrick Mooney 		/* Handle 'vCont' */
16474c87aefeSPatrick Mooney 		/* 'vCtrlC' */
16484c87aefeSPatrick Mooney 	case 'p': /* TODO */
16494c87aefeSPatrick Mooney 	case 'P': /* TODO */
16504c87aefeSPatrick Mooney 	case 'Q': /* TODO */
16514c87aefeSPatrick Mooney 	case 't': /* TODO */
16524c87aefeSPatrick Mooney 	case 'X': /* TODO */
16534c87aefeSPatrick Mooney 	default:
16544c87aefeSPatrick Mooney 		send_empty_response();
16554c87aefeSPatrick Mooney 	}
16564c87aefeSPatrick Mooney }
16574c87aefeSPatrick Mooney 
16584c87aefeSPatrick Mooney /* Check for a valid packet in the command buffer. */
16594c87aefeSPatrick Mooney static void
check_command(int fd)16604c87aefeSPatrick Mooney check_command(int fd)
16614c87aefeSPatrick Mooney {
16624c87aefeSPatrick Mooney 	uint8_t *head, *hash, *p, sum;
16634c87aefeSPatrick Mooney 	size_t avail, plen;
16644c87aefeSPatrick Mooney 
16654c87aefeSPatrick Mooney 	for (;;) {
16664c87aefeSPatrick Mooney 		avail = cur_comm.len;
16674c87aefeSPatrick Mooney 		if (avail == 0)
16684c87aefeSPatrick Mooney 			return;
16694c87aefeSPatrick Mooney 		head = io_buffer_head(&cur_comm);
16704c87aefeSPatrick Mooney 		switch (*head) {
16714c87aefeSPatrick Mooney 		case 0x03:
16724c87aefeSPatrick Mooney 			debug("<- Ctrl-C\n");
16734c87aefeSPatrick Mooney 			io_buffer_consume(&cur_comm, 1);
16744c87aefeSPatrick Mooney 
16754c87aefeSPatrick Mooney 			gdb_suspend_vcpus();
16764c87aefeSPatrick Mooney 			break;
16774c87aefeSPatrick Mooney 		case '+':
16784c87aefeSPatrick Mooney 			/* ACK of previous response. */
16794c87aefeSPatrick Mooney 			debug("<- +\n");
16804c87aefeSPatrick Mooney 			if (response_pending())
16814c87aefeSPatrick Mooney 				io_buffer_reset(&cur_resp);
16824c87aefeSPatrick Mooney 			io_buffer_consume(&cur_comm, 1);
1683154972afSPatrick Mooney 			if (stopped_vcpu != -1 && report_next_stop) {
1684154972afSPatrick Mooney 				report_stop(true);
16854c87aefeSPatrick Mooney 				send_pending_data(fd);
16864c87aefeSPatrick Mooney 			}
16874c87aefeSPatrick Mooney 			break;
16884c87aefeSPatrick Mooney 		case '-':
16894c87aefeSPatrick Mooney 			/* NACK of previous response. */
16904c87aefeSPatrick Mooney 			debug("<- -\n");
16914c87aefeSPatrick Mooney 			if (response_pending()) {
16924c87aefeSPatrick Mooney 				cur_resp.len += cur_resp.start;
16934c87aefeSPatrick Mooney 				cur_resp.start = 0;
16944c87aefeSPatrick Mooney 				if (cur_resp.data[0] == '+')
16954c87aefeSPatrick Mooney 					io_buffer_advance(&cur_resp, 1);
16964c87aefeSPatrick Mooney 				debug("-> %.*s\n", (int)cur_resp.len,
16974c87aefeSPatrick Mooney 				    io_buffer_head(&cur_resp));
16984c87aefeSPatrick Mooney 			}
16994c87aefeSPatrick Mooney 			io_buffer_consume(&cur_comm, 1);
17004c87aefeSPatrick Mooney 			send_pending_data(fd);
17014c87aefeSPatrick Mooney 			break;
17024c87aefeSPatrick Mooney 		case '$':
17034c87aefeSPatrick Mooney 			/* Packet. */
17044c87aefeSPatrick Mooney 
17054c87aefeSPatrick Mooney 			if (response_pending()) {
17064c87aefeSPatrick Mooney 				warnx("New GDB command while response in "
17074c87aefeSPatrick Mooney 				    "progress");
17084c87aefeSPatrick Mooney 				io_buffer_reset(&cur_resp);
17094c87aefeSPatrick Mooney 			}
17104c87aefeSPatrick Mooney 
17114c87aefeSPatrick Mooney 			/* Is packet complete? */
17124c87aefeSPatrick Mooney 			hash = memchr(head, '#', avail);
17134c87aefeSPatrick Mooney 			if (hash == NULL)
17144c87aefeSPatrick Mooney 				return;
17154c87aefeSPatrick Mooney 			plen = (hash - head + 1) + 2;
17164c87aefeSPatrick Mooney 			if (avail < plen)
17174c87aefeSPatrick Mooney 				return;
17184c87aefeSPatrick Mooney 			debug("<- %.*s\n", (int)plen, head);
17194c87aefeSPatrick Mooney 
17204c87aefeSPatrick Mooney 			/* Verify checksum. */
17214c87aefeSPatrick Mooney 			for (sum = 0, p = head + 1; p < hash; p++)
17224c87aefeSPatrick Mooney 				sum += *p;
17234c87aefeSPatrick Mooney 			if (sum != parse_byte(hash + 1)) {
17244c87aefeSPatrick Mooney 				io_buffer_consume(&cur_comm, plen);
17254c87aefeSPatrick Mooney 				debug("-> -\n");
17264c87aefeSPatrick Mooney 				send_char('-');
17274c87aefeSPatrick Mooney 				send_pending_data(fd);
17284c87aefeSPatrick Mooney 				break;
17294c87aefeSPatrick Mooney 			}
17304c87aefeSPatrick Mooney 			send_char('+');
17314c87aefeSPatrick Mooney 
17324c87aefeSPatrick Mooney 			handle_command(head + 1, hash - (head + 1));
17334c87aefeSPatrick Mooney 			io_buffer_consume(&cur_comm, plen);
17344c87aefeSPatrick Mooney 			if (!response_pending()) {
17354c87aefeSPatrick Mooney 				debug("-> +\n");
17364c87aefeSPatrick Mooney 			}
17374c87aefeSPatrick Mooney 			send_pending_data(fd);
17384c87aefeSPatrick Mooney 			break;
17394c87aefeSPatrick Mooney 		default:
17404c87aefeSPatrick Mooney 			/* XXX: Possibly drop connection instead. */
17414c87aefeSPatrick Mooney 			debug("-> %02x\n", *head);
17424c87aefeSPatrick Mooney 			io_buffer_consume(&cur_comm, 1);
17434c87aefeSPatrick Mooney 			break;
17444c87aefeSPatrick Mooney 		}
17454c87aefeSPatrick Mooney 	}
17464c87aefeSPatrick Mooney }
17474c87aefeSPatrick Mooney 
17484c87aefeSPatrick Mooney static void
gdb_readable(int fd,enum ev_type event __unused,void * arg __unused)174959d65d31SAndy Fiddaman gdb_readable(int fd, enum ev_type event __unused, void *arg __unused)
17504c87aefeSPatrick Mooney {
175159d65d31SAndy Fiddaman 	size_t pending;
17524c87aefeSPatrick Mooney 	ssize_t nread;
175359d65d31SAndy Fiddaman 	int n;
17544c87aefeSPatrick Mooney 
175559d65d31SAndy Fiddaman 	if (ioctl(fd, FIONREAD, &n) == -1) {
17564c87aefeSPatrick Mooney 		warn("FIONREAD on GDB socket");
17574c87aefeSPatrick Mooney 		return;
17584c87aefeSPatrick Mooney 	}
175959d65d31SAndy Fiddaman 	assert(n >= 0);
176059d65d31SAndy Fiddaman 	pending = n;
17614c87aefeSPatrick Mooney 
17624c87aefeSPatrick Mooney 	/*
17634c87aefeSPatrick Mooney 	 * 'pending' might be zero due to EOF.  We need to call read
17644c87aefeSPatrick Mooney 	 * with a non-zero length to detect EOF.
17654c87aefeSPatrick Mooney 	 */
17664c87aefeSPatrick Mooney 	if (pending == 0)
17674c87aefeSPatrick Mooney 		pending = 1;
17684c87aefeSPatrick Mooney 
17694c87aefeSPatrick Mooney 	/* Ensure there is room in the command buffer. */
17704c87aefeSPatrick Mooney 	io_buffer_grow(&cur_comm, pending);
17714c87aefeSPatrick Mooney 	assert(io_buffer_avail(&cur_comm) >= pending);
17724c87aefeSPatrick Mooney 
17734c87aefeSPatrick Mooney 	nread = read(fd, io_buffer_tail(&cur_comm), io_buffer_avail(&cur_comm));
17744c87aefeSPatrick Mooney 	if (nread == 0) {
17754c87aefeSPatrick Mooney 		close_connection();
17764c87aefeSPatrick Mooney 	} else if (nread == -1) {
17774c87aefeSPatrick Mooney 		if (errno == EAGAIN)
17784c87aefeSPatrick Mooney 			return;
17794c87aefeSPatrick Mooney 
17804c87aefeSPatrick Mooney 		warn("Read from GDB socket");
17814c87aefeSPatrick Mooney 		close_connection();
17824c87aefeSPatrick Mooney 	} else {
17834c87aefeSPatrick Mooney 		cur_comm.len += nread;
17844c87aefeSPatrick Mooney 		pthread_mutex_lock(&gdb_lock);
17854c87aefeSPatrick Mooney 		check_command(fd);
17864c87aefeSPatrick Mooney 		pthread_mutex_unlock(&gdb_lock);
17874c87aefeSPatrick Mooney 	}
17884c87aefeSPatrick Mooney }
17894c87aefeSPatrick Mooney 
17904c87aefeSPatrick Mooney static void
gdb_writable(int fd,enum ev_type event __unused,void * arg __unused)179159d65d31SAndy Fiddaman gdb_writable(int fd, enum ev_type event __unused, void *arg __unused)
17924c87aefeSPatrick Mooney {
17934c87aefeSPatrick Mooney 
17944c87aefeSPatrick Mooney 	send_pending_data(fd);
17954c87aefeSPatrick Mooney }
17964c87aefeSPatrick Mooney 
17974c87aefeSPatrick Mooney static void
new_connection(int fd,enum ev_type event __unused,void * arg)179859d65d31SAndy Fiddaman new_connection(int fd, enum ev_type event __unused, void *arg)
17994c87aefeSPatrick Mooney {
18004c87aefeSPatrick Mooney 	int optval, s;
18014c87aefeSPatrick Mooney 
18024c87aefeSPatrick Mooney 	s = accept4(fd, NULL, NULL, SOCK_NONBLOCK);
18034c87aefeSPatrick Mooney 	if (s == -1) {
18044c87aefeSPatrick Mooney 		if (arg != NULL)
18054c87aefeSPatrick Mooney 			err(1, "Failed accepting initial GDB connection");
18064c87aefeSPatrick Mooney 
18074c87aefeSPatrick Mooney 		/* Silently ignore errors post-startup. */
18084c87aefeSPatrick Mooney 		return;
18094c87aefeSPatrick Mooney 	}
18104c87aefeSPatrick Mooney 
18114c87aefeSPatrick Mooney 	optval = 1;
18124c87aefeSPatrick Mooney 	if (setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) ==
18134c87aefeSPatrick Mooney 	    -1) {
18144c87aefeSPatrick Mooney 		warn("Failed to disable SIGPIPE for GDB connection");
18154c87aefeSPatrick Mooney 		close(s);
18164c87aefeSPatrick Mooney 		return;
18174c87aefeSPatrick Mooney 	}
18184c87aefeSPatrick Mooney 
18194c87aefeSPatrick Mooney 	pthread_mutex_lock(&gdb_lock);
18204c87aefeSPatrick Mooney 	if (cur_fd != -1) {
18214c87aefeSPatrick Mooney 		close(s);
18224c87aefeSPatrick Mooney 		warnx("Ignoring additional GDB connection.");
18234c87aefeSPatrick Mooney 	}
18244c87aefeSPatrick Mooney 
18254c87aefeSPatrick Mooney 	read_event = mevent_add(s, EVF_READ, gdb_readable, NULL);
18264c87aefeSPatrick Mooney 	if (read_event == NULL) {
18274c87aefeSPatrick Mooney 		if (arg != NULL)
18284c87aefeSPatrick Mooney 			err(1, "Failed to setup initial GDB connection");
18294c87aefeSPatrick Mooney 		pthread_mutex_unlock(&gdb_lock);
18304c87aefeSPatrick Mooney 		return;
18314c87aefeSPatrick Mooney 	}
18324c87aefeSPatrick Mooney 	write_event = mevent_add(s, EVF_WRITE, gdb_writable, NULL);
18334c87aefeSPatrick Mooney 	if (write_event == NULL) {
18344c87aefeSPatrick Mooney 		if (arg != NULL)
18354c87aefeSPatrick Mooney 			err(1, "Failed to setup initial GDB connection");
18364c87aefeSPatrick Mooney 		mevent_delete_close(read_event);
18374c87aefeSPatrick Mooney 		read_event = NULL;
18384c87aefeSPatrick Mooney 	}
18394c87aefeSPatrick Mooney 
18404c87aefeSPatrick Mooney 	cur_fd = s;
18414c87aefeSPatrick Mooney 	cur_vcpu = 0;
18424c87aefeSPatrick Mooney 	stopped_vcpu = -1;
18434c87aefeSPatrick Mooney 
18444c87aefeSPatrick Mooney 	/* Break on attach. */
18454c87aefeSPatrick Mooney 	first_stop = true;
1846154972afSPatrick Mooney 	report_next_stop = false;
18474c87aefeSPatrick Mooney 	gdb_suspend_vcpus();
18484c87aefeSPatrick Mooney 	pthread_mutex_unlock(&gdb_lock);
18494c87aefeSPatrick Mooney }
18504c87aefeSPatrick Mooney 
18514c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
18524f3f3e9aSAndy Fiddaman static void
limit_gdb_socket(int s)18534c87aefeSPatrick Mooney limit_gdb_socket(int s)
18544c87aefeSPatrick Mooney {
18554c87aefeSPatrick Mooney 	cap_rights_t rights;
18564c87aefeSPatrick Mooney 	unsigned long ioctls[] = { FIONREAD };
18574c87aefeSPatrick Mooney 
18584c87aefeSPatrick Mooney 	cap_rights_init(&rights, CAP_ACCEPT, CAP_EVENT, CAP_READ, CAP_WRITE,
18594c87aefeSPatrick Mooney 	    CAP_SETSOCKOPT, CAP_IOCTL);
18604c87aefeSPatrick Mooney 	if (caph_rights_limit(s, &rights) == -1)
18614c87aefeSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
18624c87aefeSPatrick Mooney 	if (caph_ioctls_limit(s, ioctls, nitems(ioctls)) == -1)
18634c87aefeSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
18644c87aefeSPatrick Mooney }
18654c87aefeSPatrick Mooney #endif
18664c87aefeSPatrick Mooney 
1867c3d209caSPatrick Mooney 
1868c3d209caSPatrick Mooney #ifndef __FreeBSD__
1869c3d209caSPatrick Mooney /*
1870c3d209caSPatrick Mooney  * Equivalent to init_gdb() below, but without configuring the listening socket.
1871c3d209caSPatrick Mooney  * This will allow the bhyve process to tolerate mdb attaching/detaching from
1872c3d209caSPatrick Mooney  * the instance while it is running.
1873c3d209caSPatrick Mooney  */
1874c3d209caSPatrick Mooney void
init_mdb(struct vmctx * _ctx)1875b0de25cbSAndy Fiddaman init_mdb(struct vmctx *_ctx)
1876c3d209caSPatrick Mooney {
1877c3d209caSPatrick Mooney 	int error;
1878b0de25cbSAndy Fiddaman 	bool wait;
1879b0de25cbSAndy Fiddaman 
1880b0de25cbSAndy Fiddaman 	wait = get_config_bool_default("gdb.wait", false);
1881c3d209caSPatrick Mooney 
1882c3d209caSPatrick Mooney 	error = pthread_mutex_init(&gdb_lock, NULL);
1883c3d209caSPatrick Mooney 	if (error != 0)
1884c3d209caSPatrick Mooney 		errc(1, error, "gdb mutex init");
1885c3d209caSPatrick Mooney 	error = pthread_cond_init(&idle_vcpus, NULL);
1886c3d209caSPatrick Mooney 	if (error != 0)
1887c3d209caSPatrick Mooney 		errc(1, error, "gdb cv init");
1888c3d209caSPatrick Mooney 
1889c3d209caSPatrick Mooney 	ctx = _ctx;
1890c3d209caSPatrick Mooney 	stopped_vcpu = -1;
1891c3d209caSPatrick Mooney 	TAILQ_INIT(&breakpoints);
1892c3d209caSPatrick Mooney 	vcpu_state = calloc(guest_ncpus, sizeof(*vcpu_state));
1893c3d209caSPatrick Mooney 	if (wait) {
1894c3d209caSPatrick Mooney 		/*
1895c3d209caSPatrick Mooney 		 * Set vcpu 0 in vcpus_suspended.  This will trigger the
1896c3d209caSPatrick Mooney 		 * logic in gdb_cpu_add() to suspend the first vcpu before
1897c3d209caSPatrick Mooney 		 * it starts execution.  The vcpu will remain suspended
1898c3d209caSPatrick Mooney 		 * until a debugger connects.
1899c3d209caSPatrick Mooney 		 */
1900c3d209caSPatrick Mooney 		CPU_SET(0, &vcpus_suspended);
1901c3d209caSPatrick Mooney 		stopped_vcpu = 0;
1902c3d209caSPatrick Mooney 	}
1903c3d209caSPatrick Mooney }
1904c3d209caSPatrick Mooney #endif
1905c3d209caSPatrick Mooney 
19064c87aefeSPatrick Mooney void
init_gdb(struct vmctx * _ctx)1907b0de25cbSAndy Fiddaman init_gdb(struct vmctx *_ctx)
19084c87aefeSPatrick Mooney {
1909b0de25cbSAndy Fiddaman 	int error, flags, optval, s;
1910b0de25cbSAndy Fiddaman 	struct addrinfo hints;
1911b0de25cbSAndy Fiddaman 	struct addrinfo *gdbaddr;
1912b0de25cbSAndy Fiddaman 	const char *saddr, *value;
1913b0de25cbSAndy Fiddaman 	char *sport;
1914b0de25cbSAndy Fiddaman 	bool wait;
19154c87aefeSPatrick Mooney 
1916b0de25cbSAndy Fiddaman 	value = get_config_value("gdb.port");
1917b0de25cbSAndy Fiddaman 	if (value == NULL)
1918b0de25cbSAndy Fiddaman 		return;
1919b0de25cbSAndy Fiddaman 	sport = strdup(value);
1920b0de25cbSAndy Fiddaman 	if (sport == NULL)
1921b0de25cbSAndy Fiddaman 		errx(4, "Failed to allocate memory");
1922b0de25cbSAndy Fiddaman 
1923b0de25cbSAndy Fiddaman 	wait = get_config_bool_default("gdb.wait", false);
1924b0de25cbSAndy Fiddaman 
1925b0de25cbSAndy Fiddaman 	saddr = get_config_value("gdb.address");
1926b0de25cbSAndy Fiddaman 	if (saddr == NULL) {
1927b0de25cbSAndy Fiddaman 		saddr = "localhost";
1928b0de25cbSAndy Fiddaman 	}
1929b0de25cbSAndy Fiddaman 
1930b0de25cbSAndy Fiddaman 	debug("==> starting on %s:%s, %swaiting\n",
1931b0de25cbSAndy Fiddaman 	    saddr, sport, wait ? "" : "not ");
19324c87aefeSPatrick Mooney 
19334c87aefeSPatrick Mooney 	error = pthread_mutex_init(&gdb_lock, NULL);
19344c87aefeSPatrick Mooney 	if (error != 0)
19354c87aefeSPatrick Mooney 		errc(1, error, "gdb mutex init");
19364c87aefeSPatrick Mooney 	error = pthread_cond_init(&idle_vcpus, NULL);
19374c87aefeSPatrick Mooney 	if (error != 0)
19384c87aefeSPatrick Mooney 		errc(1, error, "gdb cv init");
19394c87aefeSPatrick Mooney 
1940b0de25cbSAndy Fiddaman 	memset(&hints, 0, sizeof(hints));
1941b0de25cbSAndy Fiddaman 	hints.ai_family = AF_UNSPEC;
1942b0de25cbSAndy Fiddaman 	hints.ai_socktype = SOCK_STREAM;
1943b0de25cbSAndy Fiddaman 	hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE;
1944b0de25cbSAndy Fiddaman 
1945d7b72f7bSAndy Fiddaman 	error = getaddrinfo(saddr, sport, &hints, &gdbaddr);
1946d7b72f7bSAndy Fiddaman 	if (error != 0)
1947d7b72f7bSAndy Fiddaman 		errx(1, "gdb address resolution: %s", gai_strerror(error));
1948b0de25cbSAndy Fiddaman 
19494c87aefeSPatrick Mooney 	ctx = _ctx;
1950b0de25cbSAndy Fiddaman 	s = socket(gdbaddr->ai_family, gdbaddr->ai_socktype, 0);
19514c87aefeSPatrick Mooney 	if (s < 0)
19524c87aefeSPatrick Mooney 		err(1, "gdb socket create");
19534c87aefeSPatrick Mooney 
1954b0de25cbSAndy Fiddaman 	optval = 1;
1955b0de25cbSAndy Fiddaman 	(void)setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
19564c87aefeSPatrick Mooney 
1957b0de25cbSAndy Fiddaman 	if (bind(s, gdbaddr->ai_addr, gdbaddr->ai_addrlen) < 0)
19584c87aefeSPatrick Mooney 		err(1, "gdb socket bind");
19594c87aefeSPatrick Mooney 
19604c87aefeSPatrick Mooney 	if (listen(s, 1) < 0)
19614c87aefeSPatrick Mooney 		err(1, "gdb socket listen");
19624c87aefeSPatrick Mooney 
1963154972afSPatrick Mooney 	stopped_vcpu = -1;
1964154972afSPatrick Mooney 	TAILQ_INIT(&breakpoints);
1965*32640292SAndy Fiddaman 	vcpus = calloc(guest_ncpus, sizeof(*vcpus));
1966154972afSPatrick Mooney 	vcpu_state = calloc(guest_ncpus, sizeof(*vcpu_state));
19674c87aefeSPatrick Mooney 	if (wait) {
19684c87aefeSPatrick Mooney 		/*
19694c87aefeSPatrick Mooney 		 * Set vcpu 0 in vcpus_suspended.  This will trigger the
19704c87aefeSPatrick Mooney 		 * logic in gdb_cpu_add() to suspend the first vcpu before
19714c87aefeSPatrick Mooney 		 * it starts execution.  The vcpu will remain suspended
19724c87aefeSPatrick Mooney 		 * until a debugger connects.
19734c87aefeSPatrick Mooney 		 */
19744c87aefeSPatrick Mooney 		CPU_SET(0, &vcpus_suspended);
1975154972afSPatrick Mooney 		stopped_vcpu = 0;
19764c87aefeSPatrick Mooney 	}
19774c87aefeSPatrick Mooney 
19784c87aefeSPatrick Mooney 	flags = fcntl(s, F_GETFL);
19794c87aefeSPatrick Mooney 	if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
19804c87aefeSPatrick Mooney 		err(1, "Failed to mark gdb socket non-blocking");
19814c87aefeSPatrick Mooney 
19824c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
19834c87aefeSPatrick Mooney 	limit_gdb_socket(s);
19844c87aefeSPatrick Mooney #endif
19854c87aefeSPatrick Mooney 	mevent_add(s, EVF_READ, new_connection, NULL);
19862b948146SAndy Fiddaman 	gdb_active = true;
1987b0de25cbSAndy Fiddaman 	freeaddrinfo(gdbaddr);
1988b0de25cbSAndy Fiddaman 	free(sport);
19894c87aefeSPatrick Mooney }
1990