xref: /illumos-gate/usr/src/cmd/bhyve/gdb.c (revision 4f3f3e9a1dee62c031fa67cfe64e11d6dd3fab1b)
14c87aefeSPatrick Mooney /*-
24c87aefeSPatrick Mooney  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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 __FBSDID("$FreeBSD$");
304c87aefeSPatrick Mooney 
314c87aefeSPatrick Mooney #include <sys/param.h>
324c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
334c87aefeSPatrick Mooney #include <sys/capsicum.h>
344c87aefeSPatrick Mooney #endif
3584659b24SMichael Zeller #ifdef __FreeBSD__
3684659b24SMichael Zeller #include <sys/endian.h>
3784659b24SMichael Zeller #else
3884659b24SMichael Zeller #include <endian.h>
3984659b24SMichael Zeller #endif
404c87aefeSPatrick Mooney #include <sys/ioctl.h>
414c87aefeSPatrick Mooney #include <sys/mman.h>
42154972afSPatrick Mooney #include <sys/queue.h>
434c87aefeSPatrick Mooney #include <sys/socket.h>
444c87aefeSPatrick Mooney #include <machine/atomic.h>
454c87aefeSPatrick Mooney #include <machine/specialreg.h>
464c87aefeSPatrick Mooney #include <machine/vmm.h>
474c87aefeSPatrick Mooney #include <netinet/in.h>
484c87aefeSPatrick Mooney #include <assert.h>
494c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
504c87aefeSPatrick Mooney #include <capsicum_helpers.h>
514c87aefeSPatrick Mooney #endif
524c87aefeSPatrick Mooney #include <err.h>
534c87aefeSPatrick Mooney #include <errno.h>
544c87aefeSPatrick Mooney #include <fcntl.h>
55b0de25cbSAndy Fiddaman #include <netdb.h>
564c87aefeSPatrick Mooney #include <pthread.h>
574c87aefeSPatrick Mooney #include <pthread_np.h>
584c87aefeSPatrick Mooney #include <stdbool.h>
594c87aefeSPatrick Mooney #include <stdio.h>
604c87aefeSPatrick Mooney #include <stdlib.h>
614c87aefeSPatrick Mooney #include <string.h>
624c87aefeSPatrick Mooney #include <sysexits.h>
634c87aefeSPatrick Mooney #include <unistd.h>
644c87aefeSPatrick Mooney #include <vmmapi.h>
654c87aefeSPatrick Mooney 
664c87aefeSPatrick Mooney #include "bhyverun.h"
67b0de25cbSAndy Fiddaman #include "config.h"
68154972afSPatrick Mooney #include "gdb.h"
694c87aefeSPatrick Mooney #include "mem.h"
704c87aefeSPatrick Mooney #include "mevent.h"
714c87aefeSPatrick Mooney 
724c87aefeSPatrick Mooney /*
734c87aefeSPatrick Mooney  * GDB_SIGNAL_* numbers are part of the GDB remote protocol.  Most stops
744c87aefeSPatrick Mooney  * use SIGTRAP.
754c87aefeSPatrick Mooney  */
764c87aefeSPatrick Mooney #define	GDB_SIGNAL_TRAP		5
774c87aefeSPatrick Mooney 
784c87aefeSPatrick Mooney static void gdb_resume_vcpus(void);
794c87aefeSPatrick Mooney static void check_command(int fd);
804c87aefeSPatrick Mooney 
814c87aefeSPatrick Mooney static struct mevent *read_event, *write_event;
824c87aefeSPatrick Mooney 
834c87aefeSPatrick Mooney static cpuset_t vcpus_active, vcpus_suspended, vcpus_waiting;
844c87aefeSPatrick Mooney static pthread_mutex_t gdb_lock;
854c87aefeSPatrick Mooney static pthread_cond_t idle_vcpus;
86154972afSPatrick Mooney static bool first_stop, report_next_stop, swbreak_enabled;
874c87aefeSPatrick Mooney 
884c87aefeSPatrick Mooney /*
894c87aefeSPatrick Mooney  * An I/O buffer contains 'capacity' bytes of room at 'data'.  For a
904c87aefeSPatrick Mooney  * read buffer, 'start' is unused and 'len' contains the number of
914c87aefeSPatrick Mooney  * valid bytes in the buffer.  For a write buffer, 'start' is set to
924c87aefeSPatrick Mooney  * the index of the next byte in 'data' to send, and 'len' contains
934c87aefeSPatrick Mooney  * the remaining number of valid bytes to send.
944c87aefeSPatrick Mooney  */
954c87aefeSPatrick Mooney struct io_buffer {
964c87aefeSPatrick Mooney 	uint8_t *data;
974c87aefeSPatrick Mooney 	size_t capacity;
984c87aefeSPatrick Mooney 	size_t start;
994c87aefeSPatrick Mooney 	size_t len;
1004c87aefeSPatrick Mooney };
1014c87aefeSPatrick Mooney 
102154972afSPatrick Mooney struct breakpoint {
103154972afSPatrick Mooney 	uint64_t gpa;
104154972afSPatrick Mooney 	uint8_t shadow_inst;
105154972afSPatrick Mooney 	TAILQ_ENTRY(breakpoint) link;
106154972afSPatrick Mooney };
107154972afSPatrick Mooney 
108154972afSPatrick Mooney /*
109154972afSPatrick Mooney  * When a vCPU stops to due to an event that should be reported to the
110154972afSPatrick Mooney  * debugger, information about the event is stored in this structure.
111154972afSPatrick Mooney  * The vCPU thread then sets 'stopped_vcpu' if it is not already set
112154972afSPatrick Mooney  * and stops other vCPUs so the event can be reported.  The
113154972afSPatrick Mooney  * report_stop() function reports the event for the 'stopped_vcpu'
114154972afSPatrick Mooney  * vCPU.  When the debugger resumes execution via continue or step,
115154972afSPatrick Mooney  * the event for 'stopped_vcpu' is cleared.  vCPUs will loop in their
116154972afSPatrick Mooney  * event handlers until the associated event is reported or disabled.
117154972afSPatrick Mooney  *
118154972afSPatrick Mooney  * An idle vCPU will have all of the boolean fields set to false.
119154972afSPatrick Mooney  *
120154972afSPatrick Mooney  * When a vCPU is stepped, 'stepping' is set to true when the vCPU is
121154972afSPatrick Mooney  * released to execute the stepped instruction.  When the vCPU reports
122154972afSPatrick Mooney  * the stepping trap, 'stepped' is set.
123154972afSPatrick Mooney  *
124154972afSPatrick Mooney  * When a vCPU hits a breakpoint set by the debug server,
125154972afSPatrick Mooney  * 'hit_swbreak' is set to true.
126154972afSPatrick Mooney  */
127154972afSPatrick Mooney struct vcpu_state {
128154972afSPatrick Mooney 	bool stepping;
129154972afSPatrick Mooney 	bool stepped;
130154972afSPatrick Mooney 	bool hit_swbreak;
131154972afSPatrick Mooney };
132154972afSPatrick Mooney 
1334c87aefeSPatrick Mooney static struct io_buffer cur_comm, cur_resp;
1344c87aefeSPatrick Mooney static uint8_t cur_csum;
1354c87aefeSPatrick Mooney static struct vmctx *ctx;
1364c87aefeSPatrick Mooney static int cur_fd = -1;
137154972afSPatrick Mooney static TAILQ_HEAD(, breakpoint) breakpoints;
138154972afSPatrick Mooney static struct vcpu_state *vcpu_state;
139154972afSPatrick Mooney static int cur_vcpu, stopped_vcpu;
1402b948146SAndy Fiddaman static bool gdb_active = false;
1414c87aefeSPatrick Mooney 
142*4f3f3e9aSAndy 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 
169*4f3f3e9aSAndy 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)
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
2384c87aefeSPatrick Mooney guest_paging_info(int 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 
2484c87aefeSPatrick Mooney 	if (vm_get_register_set(ctx, 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
2824c87aefeSPatrick Mooney guest_vaddr2paddr(int 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 	 */
2944c87aefeSPatrick Mooney 	if (vm_gla2gpa_nofault(ctx, 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
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
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
7564c87aefeSPatrick Mooney _gdb_cpu_suspend(int vcpu, bool report_stop)
7574c87aefeSPatrick Mooney {
7584c87aefeSPatrick Mooney 
7594c87aefeSPatrick Mooney 	debug("$vCPU %d suspending\n", vcpu);
7604c87aefeSPatrick Mooney 	CPU_SET(vcpu, &vcpus_waiting);
7614c87aefeSPatrick Mooney 	if (report_stop && CPU_CMP(&vcpus_waiting, &vcpus_suspended) == 0)
7624c87aefeSPatrick Mooney 		gdb_finish_suspend_vcpus();
763154972afSPatrick Mooney 	while (CPU_ISSET(vcpu, &vcpus_suspended))
7644c87aefeSPatrick Mooney 		pthread_cond_wait(&idle_vcpus, &gdb_lock);
7654c87aefeSPatrick Mooney 	CPU_CLR(vcpu, &vcpus_waiting);
7664c87aefeSPatrick Mooney 	debug("$vCPU %d resuming\n", vcpu);
7674c87aefeSPatrick Mooney }
7684c87aefeSPatrick Mooney 
769154972afSPatrick Mooney /*
770154972afSPatrick Mooney  * Invoked at the start of a vCPU thread's execution to inform the
771154972afSPatrick Mooney  * debug server about the new thread.
772154972afSPatrick Mooney  */
7734c87aefeSPatrick Mooney void
7744c87aefeSPatrick Mooney gdb_cpu_add(int vcpu)
7754c87aefeSPatrick Mooney {
7764c87aefeSPatrick Mooney 
7772b948146SAndy Fiddaman 	if (!gdb_active)
7782b948146SAndy Fiddaman 		return;
7794c87aefeSPatrick Mooney 	debug("$vCPU %d starting\n", vcpu);
7804c87aefeSPatrick Mooney 	pthread_mutex_lock(&gdb_lock);
781154972afSPatrick Mooney 	assert(vcpu < guest_ncpus);
7824c87aefeSPatrick Mooney 	CPU_SET(vcpu, &vcpus_active);
783154972afSPatrick Mooney 	if (!TAILQ_EMPTY(&breakpoints)) {
784154972afSPatrick Mooney 		vm_set_capability(ctx, vcpu, VM_CAP_BPT_EXIT, 1);
785154972afSPatrick Mooney 		debug("$vCPU %d enabled breakpoint exits\n", vcpu);
786154972afSPatrick Mooney 	}
7874c87aefeSPatrick Mooney 
7884c87aefeSPatrick Mooney 	/*
7894c87aefeSPatrick Mooney 	 * If a vcpu is added while vcpus are stopped, suspend the new
7904c87aefeSPatrick Mooney 	 * vcpu so that it will pop back out with a debug exit before
7914c87aefeSPatrick Mooney 	 * executing the first instruction.
7924c87aefeSPatrick Mooney 	 */
7934c87aefeSPatrick Mooney 	if (!CPU_EMPTY(&vcpus_suspended)) {
7944c87aefeSPatrick Mooney 		CPU_SET(vcpu, &vcpus_suspended);
7954c87aefeSPatrick Mooney 		_gdb_cpu_suspend(vcpu, false);
7964c87aefeSPatrick Mooney 	}
7974c87aefeSPatrick Mooney 	pthread_mutex_unlock(&gdb_lock);
7984c87aefeSPatrick Mooney }
7994c87aefeSPatrick Mooney 
800154972afSPatrick Mooney /*
801154972afSPatrick Mooney  * Invoked by vCPU before resuming execution.  This enables stepping
802154972afSPatrick Mooney  * if the vCPU is marked as stepping.
803154972afSPatrick Mooney  */
804154972afSPatrick Mooney static void
805154972afSPatrick Mooney gdb_cpu_resume(int vcpu)
806154972afSPatrick Mooney {
807154972afSPatrick Mooney 	struct vcpu_state *vs;
808154972afSPatrick Mooney 	int error;
809154972afSPatrick Mooney 
810154972afSPatrick Mooney 	vs = &vcpu_state[vcpu];
811154972afSPatrick Mooney 
812154972afSPatrick Mooney 	/*
813154972afSPatrick Mooney 	 * Any pending event should already be reported before
814154972afSPatrick Mooney 	 * resuming.
815154972afSPatrick Mooney 	 */
816154972afSPatrick Mooney 	assert(vs->hit_swbreak == false);
817154972afSPatrick Mooney 	assert(vs->stepped == false);
818154972afSPatrick Mooney 	if (vs->stepping) {
819154972afSPatrick Mooney 		error = vm_set_capability(ctx, vcpu, VM_CAP_MTRAP_EXIT, 1);
820154972afSPatrick Mooney 		assert(error == 0);
821154972afSPatrick Mooney 	}
822154972afSPatrick Mooney }
823154972afSPatrick Mooney 
824154972afSPatrick Mooney /*
825154972afSPatrick Mooney  * Handler for VM_EXITCODE_DEBUG used to suspend a vCPU when the guest
826154972afSPatrick Mooney  * has been suspended due to an event on different vCPU or in response
827154972afSPatrick Mooney  * to a guest-wide suspend such as Ctrl-C or the stop on attach.
828154972afSPatrick Mooney  */
8294c87aefeSPatrick Mooney void
8304c87aefeSPatrick Mooney gdb_cpu_suspend(int vcpu)
8314c87aefeSPatrick Mooney {
8324c87aefeSPatrick Mooney 
833b0de25cbSAndy Fiddaman 	if (!gdb_active)
834b0de25cbSAndy Fiddaman 		return;
8354c87aefeSPatrick Mooney 	pthread_mutex_lock(&gdb_lock);
8364c87aefeSPatrick Mooney 	_gdb_cpu_suspend(vcpu, true);
837154972afSPatrick Mooney 	gdb_cpu_resume(vcpu);
8384c87aefeSPatrick Mooney 	pthread_mutex_unlock(&gdb_lock);
8394c87aefeSPatrick Mooney }
8404c87aefeSPatrick Mooney 
8414c87aefeSPatrick Mooney static void
8424c87aefeSPatrick Mooney gdb_suspend_vcpus(void)
8434c87aefeSPatrick Mooney {
8444c87aefeSPatrick Mooney 
8454c87aefeSPatrick Mooney 	assert(pthread_mutex_isowned_np(&gdb_lock));
8464c87aefeSPatrick Mooney 	debug("suspending all CPUs\n");
8474c87aefeSPatrick Mooney 	vcpus_suspended = vcpus_active;
8484c87aefeSPatrick Mooney 	vm_suspend_cpu(ctx, -1);
8494c87aefeSPatrick Mooney 	if (CPU_CMP(&vcpus_waiting, &vcpus_suspended) == 0)
8504c87aefeSPatrick Mooney 		gdb_finish_suspend_vcpus();
8514c87aefeSPatrick Mooney }
8524c87aefeSPatrick Mooney 
853154972afSPatrick Mooney /*
854154972afSPatrick Mooney  * Handler for VM_EXITCODE_MTRAP reported when a vCPU single-steps via
855154972afSPatrick Mooney  * the VT-x-specific MTRAP exit.
856154972afSPatrick Mooney  */
857154972afSPatrick Mooney void
858154972afSPatrick Mooney gdb_cpu_mtrap(int vcpu)
859154972afSPatrick Mooney {
860154972afSPatrick Mooney 	struct vcpu_state *vs;
861154972afSPatrick Mooney 
8622b948146SAndy Fiddaman 	if (!gdb_active)
8632b948146SAndy Fiddaman 		return;
864154972afSPatrick Mooney 	debug("$vCPU %d MTRAP\n", vcpu);
865154972afSPatrick Mooney 	pthread_mutex_lock(&gdb_lock);
866154972afSPatrick Mooney 	vs = &vcpu_state[vcpu];
867154972afSPatrick Mooney 	if (vs->stepping) {
868154972afSPatrick Mooney 		vs->stepping = false;
869154972afSPatrick Mooney 		vs->stepped = true;
870154972afSPatrick Mooney 		vm_set_capability(ctx, vcpu, VM_CAP_MTRAP_EXIT, 0);
871154972afSPatrick Mooney 		while (vs->stepped) {
872154972afSPatrick Mooney 			if (stopped_vcpu == -1) {
873154972afSPatrick Mooney 				debug("$vCPU %d reporting step\n", vcpu);
874154972afSPatrick Mooney 				stopped_vcpu = vcpu;
875154972afSPatrick Mooney 				gdb_suspend_vcpus();
876154972afSPatrick Mooney 			}
877154972afSPatrick Mooney 			_gdb_cpu_suspend(vcpu, true);
878154972afSPatrick Mooney 		}
879154972afSPatrick Mooney 		gdb_cpu_resume(vcpu);
880154972afSPatrick Mooney 	}
881154972afSPatrick Mooney 	pthread_mutex_unlock(&gdb_lock);
882154972afSPatrick Mooney }
883154972afSPatrick Mooney 
884154972afSPatrick Mooney static struct breakpoint *
885154972afSPatrick Mooney find_breakpoint(uint64_t gpa)
886154972afSPatrick Mooney {
887154972afSPatrick Mooney 	struct breakpoint *bp;
888154972afSPatrick Mooney 
889154972afSPatrick Mooney 	TAILQ_FOREACH(bp, &breakpoints, link) {
890154972afSPatrick Mooney 		if (bp->gpa == gpa)
891154972afSPatrick Mooney 			return (bp);
892154972afSPatrick Mooney 	}
893154972afSPatrick Mooney 	return (NULL);
894154972afSPatrick Mooney }
895154972afSPatrick Mooney 
896154972afSPatrick Mooney void
897154972afSPatrick Mooney gdb_cpu_breakpoint(int vcpu, struct vm_exit *vmexit)
898154972afSPatrick Mooney {
899154972afSPatrick Mooney 	struct breakpoint *bp;
900154972afSPatrick Mooney 	struct vcpu_state *vs;
901154972afSPatrick Mooney 	uint64_t gpa;
902154972afSPatrick Mooney 	int error;
903154972afSPatrick Mooney 
9042b948146SAndy Fiddaman 	if (!gdb_active) {
9052b948146SAndy Fiddaman 		fprintf(stderr, "vm_loop: unexpected VMEXIT_DEBUG\n");
9062b948146SAndy Fiddaman 		exit(4);
9072b948146SAndy Fiddaman 	}
908154972afSPatrick Mooney 	pthread_mutex_lock(&gdb_lock);
909154972afSPatrick Mooney 	error = guest_vaddr2paddr(vcpu, vmexit->rip, &gpa);
910154972afSPatrick Mooney 	assert(error == 1);
911154972afSPatrick Mooney 	bp = find_breakpoint(gpa);
912154972afSPatrick Mooney 	if (bp != NULL) {
913154972afSPatrick Mooney 		vs = &vcpu_state[vcpu];
914154972afSPatrick Mooney 		assert(vs->stepping == false);
915154972afSPatrick Mooney 		assert(vs->stepped == false);
916154972afSPatrick Mooney 		assert(vs->hit_swbreak == false);
917154972afSPatrick Mooney 		vs->hit_swbreak = true;
918154972afSPatrick Mooney 		vm_set_register(ctx, vcpu, VM_REG_GUEST_RIP, vmexit->rip);
919154972afSPatrick Mooney 		for (;;) {
920154972afSPatrick Mooney 			if (stopped_vcpu == -1) {
921154972afSPatrick Mooney 				debug("$vCPU %d reporting breakpoint at rip %#lx\n", vcpu,
922154972afSPatrick Mooney 				    vmexit->rip);
923154972afSPatrick Mooney 				stopped_vcpu = vcpu;
924154972afSPatrick Mooney 				gdb_suspend_vcpus();
925154972afSPatrick Mooney 			}
926154972afSPatrick Mooney 			_gdb_cpu_suspend(vcpu, true);
927154972afSPatrick Mooney 			if (!vs->hit_swbreak) {
928154972afSPatrick Mooney 				/* Breakpoint reported. */
929154972afSPatrick Mooney 				break;
930154972afSPatrick Mooney 			}
931154972afSPatrick Mooney 			bp = find_breakpoint(gpa);
932154972afSPatrick Mooney 			if (bp == NULL) {
933154972afSPatrick Mooney 				/* Breakpoint was removed. */
934154972afSPatrick Mooney 				vs->hit_swbreak = false;
935154972afSPatrick Mooney 				break;
936154972afSPatrick Mooney 			}
937154972afSPatrick Mooney 		}
938154972afSPatrick Mooney 		gdb_cpu_resume(vcpu);
939154972afSPatrick Mooney 	} else {
940154972afSPatrick Mooney 		debug("$vCPU %d injecting breakpoint at rip %#lx\n", vcpu,
941154972afSPatrick Mooney 		    vmexit->rip);
942154972afSPatrick Mooney 		error = vm_set_register(ctx, vcpu,
943154972afSPatrick Mooney 		    VM_REG_GUEST_ENTRY_INST_LENGTH, vmexit->u.bpt.inst_length);
944154972afSPatrick Mooney 		assert(error == 0);
945154972afSPatrick Mooney 		error = vm_inject_exception(ctx, vcpu, IDT_BP, 0, 0, 0);
946154972afSPatrick Mooney 		assert(error == 0);
947154972afSPatrick Mooney 	}
948154972afSPatrick Mooney 	pthread_mutex_unlock(&gdb_lock);
949154972afSPatrick Mooney }
950154972afSPatrick Mooney 
9514c87aefeSPatrick Mooney static bool
9524c87aefeSPatrick Mooney gdb_step_vcpu(int vcpu)
9534c87aefeSPatrick Mooney {
9544c87aefeSPatrick Mooney 	int error, val;
9554c87aefeSPatrick Mooney 
9564c87aefeSPatrick Mooney 	debug("$vCPU %d step\n", vcpu);
9574c87aefeSPatrick Mooney 	error = vm_get_capability(ctx, vcpu, VM_CAP_MTRAP_EXIT, &val);
9584c87aefeSPatrick Mooney 	if (error < 0)
9594c87aefeSPatrick Mooney 		return (false);
960154972afSPatrick Mooney 
961154972afSPatrick Mooney 	discard_stop();
962154972afSPatrick Mooney 	vcpu_state[vcpu].stepping = true;
9634c87aefeSPatrick Mooney 	vm_resume_cpu(ctx, vcpu);
964154972afSPatrick Mooney 	CPU_CLR(vcpu, &vcpus_suspended);
9654c87aefeSPatrick Mooney 	pthread_cond_broadcast(&idle_vcpus);
9664c87aefeSPatrick Mooney 	return (true);
9674c87aefeSPatrick Mooney }
9684c87aefeSPatrick Mooney 
9694c87aefeSPatrick Mooney static void
9704c87aefeSPatrick Mooney gdb_resume_vcpus(void)
9714c87aefeSPatrick Mooney {
9724c87aefeSPatrick Mooney 
9734c87aefeSPatrick Mooney 	assert(pthread_mutex_isowned_np(&gdb_lock));
9744c87aefeSPatrick Mooney 	vm_resume_cpu(ctx, -1);
9754c87aefeSPatrick Mooney 	debug("resuming all CPUs\n");
9764c87aefeSPatrick Mooney 	CPU_ZERO(&vcpus_suspended);
9774c87aefeSPatrick Mooney 	pthread_cond_broadcast(&idle_vcpus);
9784c87aefeSPatrick Mooney }
9794c87aefeSPatrick Mooney 
9804c87aefeSPatrick Mooney static void
9814c87aefeSPatrick Mooney gdb_read_regs(void)
9824c87aefeSPatrick Mooney {
9834c87aefeSPatrick Mooney 	uint64_t regvals[nitems(gdb_regset)];
9844c87aefeSPatrick Mooney 	int i;
9854c87aefeSPatrick Mooney 
9864c87aefeSPatrick Mooney 	if (vm_get_register_set(ctx, cur_vcpu, nitems(gdb_regset),
9874c87aefeSPatrick Mooney 	    gdb_regset, regvals) == -1) {
9884c87aefeSPatrick Mooney 		send_error(errno);
9894c87aefeSPatrick Mooney 		return;
9904c87aefeSPatrick Mooney 	}
9914c87aefeSPatrick Mooney 	start_packet();
9924c87aefeSPatrick Mooney 	for (i = 0; i < nitems(regvals); i++)
9934c87aefeSPatrick Mooney 		append_unsigned_native(regvals[i], gdb_regsize[i]);
9944c87aefeSPatrick Mooney 	finish_packet();
9954c87aefeSPatrick Mooney }
9964c87aefeSPatrick Mooney 
9974c87aefeSPatrick Mooney static void
9984c87aefeSPatrick Mooney gdb_read_mem(const uint8_t *data, size_t len)
9994c87aefeSPatrick Mooney {
10004c87aefeSPatrick Mooney 	uint64_t gpa, gva, val;
10014c87aefeSPatrick Mooney 	uint8_t *cp;
10024c87aefeSPatrick Mooney 	size_t resid, todo, bytes;
10034c87aefeSPatrick Mooney 	bool started;
10044c87aefeSPatrick Mooney 	int error;
10054c87aefeSPatrick Mooney 
10064c87aefeSPatrick Mooney 	/* Skip 'm' */
10074c87aefeSPatrick Mooney 	data += 1;
10084c87aefeSPatrick Mooney 	len -= 1;
10094c87aefeSPatrick Mooney 
10104c87aefeSPatrick Mooney 	/* Parse and consume address. */
10114c87aefeSPatrick Mooney 	cp = memchr(data, ',', len);
10124c87aefeSPatrick Mooney 	if (cp == NULL || cp == data) {
10134c87aefeSPatrick Mooney 		send_error(EINVAL);
10144c87aefeSPatrick Mooney 		return;
10154c87aefeSPatrick Mooney 	}
10164c87aefeSPatrick Mooney 	gva = parse_integer(data, cp - data);
10174c87aefeSPatrick Mooney 	len -= (cp - data) + 1;
10184c87aefeSPatrick Mooney 	data += (cp - data) + 1;
10194c87aefeSPatrick Mooney 
10204c87aefeSPatrick Mooney 	/* Parse length. */
10214c87aefeSPatrick Mooney 	resid = parse_integer(data, len);
10224c87aefeSPatrick Mooney 
10234c87aefeSPatrick Mooney 	started = false;
10244c87aefeSPatrick Mooney 	while (resid > 0) {
10254c87aefeSPatrick Mooney 		error = guest_vaddr2paddr(cur_vcpu, gva, &gpa);
10264c87aefeSPatrick Mooney 		if (error == -1) {
10274c87aefeSPatrick Mooney 			if (started)
10284c87aefeSPatrick Mooney 				finish_packet();
10294c87aefeSPatrick Mooney 			else
10304c87aefeSPatrick Mooney 				send_error(errno);
10314c87aefeSPatrick Mooney 			return;
10324c87aefeSPatrick Mooney 		}
10334c87aefeSPatrick Mooney 		if (error == 0) {
10344c87aefeSPatrick Mooney 			if (started)
10354c87aefeSPatrick Mooney 				finish_packet();
10364c87aefeSPatrick Mooney 			else
10374c87aefeSPatrick Mooney 				send_error(EFAULT);
10384c87aefeSPatrick Mooney 			return;
10394c87aefeSPatrick Mooney 		}
10404c87aefeSPatrick Mooney 
10414c87aefeSPatrick Mooney 		/* Read bytes from current page. */
10424c87aefeSPatrick Mooney 		todo = getpagesize() - gpa % getpagesize();
10434c87aefeSPatrick Mooney 		if (todo > resid)
10444c87aefeSPatrick Mooney 			todo = resid;
10454c87aefeSPatrick Mooney 
10464c87aefeSPatrick Mooney 		cp = paddr_guest2host(ctx, gpa, todo);
10474c87aefeSPatrick Mooney 		if (cp != NULL) {
10484c87aefeSPatrick Mooney 			/*
10494c87aefeSPatrick Mooney 			 * If this page is guest RAM, read it a byte
10504c87aefeSPatrick Mooney 			 * at a time.
10514c87aefeSPatrick Mooney 			 */
10524c87aefeSPatrick Mooney 			if (!started) {
10534c87aefeSPatrick Mooney 				start_packet();
10544c87aefeSPatrick Mooney 				started = true;
10554c87aefeSPatrick Mooney 			}
10564c87aefeSPatrick Mooney 			while (todo > 0) {
10574c87aefeSPatrick Mooney 				append_byte(*cp);
10584c87aefeSPatrick Mooney 				cp++;
10594c87aefeSPatrick Mooney 				gpa++;
10604c87aefeSPatrick Mooney 				gva++;
10614c87aefeSPatrick Mooney 				resid--;
10624c87aefeSPatrick Mooney 				todo--;
10634c87aefeSPatrick Mooney 			}
10644c87aefeSPatrick Mooney 		} else {
10654c87aefeSPatrick Mooney 			/*
10664c87aefeSPatrick Mooney 			 * If this page isn't guest RAM, try to handle
10674c87aefeSPatrick Mooney 			 * it via MMIO.  For MMIO requests, use
10684c87aefeSPatrick Mooney 			 * aligned reads of words when possible.
10694c87aefeSPatrick Mooney 			 */
10704c87aefeSPatrick Mooney 			while (todo > 0) {
10714c87aefeSPatrick Mooney 				if (gpa & 1 || todo == 1)
10724c87aefeSPatrick Mooney 					bytes = 1;
10734c87aefeSPatrick Mooney 				else if (gpa & 2 || todo == 2)
10744c87aefeSPatrick Mooney 					bytes = 2;
10754c87aefeSPatrick Mooney 				else
10764c87aefeSPatrick Mooney 					bytes = 4;
10774c87aefeSPatrick Mooney 				error = read_mem(ctx, cur_vcpu, gpa, &val,
10784c87aefeSPatrick Mooney 				    bytes);
10794c87aefeSPatrick Mooney 				if (error == 0) {
10804c87aefeSPatrick Mooney 					if (!started) {
10814c87aefeSPatrick Mooney 						start_packet();
10824c87aefeSPatrick Mooney 						started = true;
10834c87aefeSPatrick Mooney 					}
10844c87aefeSPatrick Mooney 					gpa += bytes;
10854c87aefeSPatrick Mooney 					gva += bytes;
10864c87aefeSPatrick Mooney 					resid -= bytes;
10874c87aefeSPatrick Mooney 					todo -= bytes;
10884c87aefeSPatrick Mooney 					while (bytes > 0) {
10894c87aefeSPatrick Mooney 						append_byte(val);
10904c87aefeSPatrick Mooney 						val >>= 8;
10914c87aefeSPatrick Mooney 						bytes--;
10924c87aefeSPatrick Mooney 					}
10934c87aefeSPatrick Mooney 				} else {
10944c87aefeSPatrick Mooney 					if (started)
10954c87aefeSPatrick Mooney 						finish_packet();
10964c87aefeSPatrick Mooney 					else
10974c87aefeSPatrick Mooney 						send_error(EFAULT);
10984c87aefeSPatrick Mooney 					return;
10994c87aefeSPatrick Mooney 				}
11004c87aefeSPatrick Mooney 			}
11014c87aefeSPatrick Mooney 		}
11024c87aefeSPatrick Mooney 		assert(resid == 0 || gpa % getpagesize() == 0);
11034c87aefeSPatrick Mooney 	}
11044c87aefeSPatrick Mooney 	if (!started)
11054c87aefeSPatrick Mooney 		start_packet();
11064c87aefeSPatrick Mooney 	finish_packet();
11074c87aefeSPatrick Mooney }
11084c87aefeSPatrick Mooney 
11094c87aefeSPatrick Mooney static void
11104c87aefeSPatrick Mooney gdb_write_mem(const uint8_t *data, size_t len)
11114c87aefeSPatrick Mooney {
11124c87aefeSPatrick Mooney 	uint64_t gpa, gva, val;
11134c87aefeSPatrick Mooney 	uint8_t *cp;
11144c87aefeSPatrick Mooney 	size_t resid, todo, bytes;
11154c87aefeSPatrick Mooney 	int error;
11164c87aefeSPatrick Mooney 
11174c87aefeSPatrick Mooney 	/* Skip 'M' */
11184c87aefeSPatrick Mooney 	data += 1;
11194c87aefeSPatrick Mooney 	len -= 1;
11204c87aefeSPatrick Mooney 
11214c87aefeSPatrick Mooney 	/* Parse and consume address. */
11224c87aefeSPatrick Mooney 	cp = memchr(data, ',', len);
11234c87aefeSPatrick Mooney 	if (cp == NULL || cp == data) {
11244c87aefeSPatrick Mooney 		send_error(EINVAL);
11254c87aefeSPatrick Mooney 		return;
11264c87aefeSPatrick Mooney 	}
11274c87aefeSPatrick Mooney 	gva = parse_integer(data, cp - data);
11284c87aefeSPatrick Mooney 	len -= (cp - data) + 1;
11294c87aefeSPatrick Mooney 	data += (cp - data) + 1;
11304c87aefeSPatrick Mooney 
11314c87aefeSPatrick Mooney 	/* Parse and consume length. */
11324c87aefeSPatrick Mooney 	cp = memchr(data, ':', len);
11334c87aefeSPatrick Mooney 	if (cp == NULL || cp == data) {
11344c87aefeSPatrick Mooney 		send_error(EINVAL);
11354c87aefeSPatrick Mooney 		return;
11364c87aefeSPatrick Mooney 	}
11374c87aefeSPatrick Mooney 	resid = parse_integer(data, cp - data);
11384c87aefeSPatrick Mooney 	len -= (cp - data) + 1;
11394c87aefeSPatrick Mooney 	data += (cp - data) + 1;
11404c87aefeSPatrick Mooney 
11414c87aefeSPatrick Mooney 	/* Verify the available bytes match the length. */
11424c87aefeSPatrick Mooney 	if (len != resid * 2) {
11434c87aefeSPatrick Mooney 		send_error(EINVAL);
11444c87aefeSPatrick Mooney 		return;
11454c87aefeSPatrick Mooney 	}
11464c87aefeSPatrick Mooney 
11474c87aefeSPatrick Mooney 	while (resid > 0) {
11484c87aefeSPatrick Mooney 		error = guest_vaddr2paddr(cur_vcpu, gva, &gpa);
11494c87aefeSPatrick Mooney 		if (error == -1) {
11504c87aefeSPatrick Mooney 			send_error(errno);
11514c87aefeSPatrick Mooney 			return;
11524c87aefeSPatrick Mooney 		}
11534c87aefeSPatrick Mooney 		if (error == 0) {
11544c87aefeSPatrick Mooney 			send_error(EFAULT);
11554c87aefeSPatrick Mooney 			return;
11564c87aefeSPatrick Mooney 		}
11574c87aefeSPatrick Mooney 
11584c87aefeSPatrick Mooney 		/* Write bytes to current page. */
11594c87aefeSPatrick Mooney 		todo = getpagesize() - gpa % getpagesize();
11604c87aefeSPatrick Mooney 		if (todo > resid)
11614c87aefeSPatrick Mooney 			todo = resid;
11624c87aefeSPatrick Mooney 
11634c87aefeSPatrick Mooney 		cp = paddr_guest2host(ctx, gpa, todo);
11644c87aefeSPatrick Mooney 		if (cp != NULL) {
11654c87aefeSPatrick Mooney 			/*
11664c87aefeSPatrick Mooney 			 * If this page is guest RAM, write it a byte
11674c87aefeSPatrick Mooney 			 * at a time.
11684c87aefeSPatrick Mooney 			 */
11694c87aefeSPatrick Mooney 			while (todo > 0) {
11704c87aefeSPatrick Mooney 				assert(len >= 2);
11714c87aefeSPatrick Mooney 				*cp = parse_byte(data);
11724c87aefeSPatrick Mooney 				data += 2;
11734c87aefeSPatrick Mooney 				len -= 2;
11744c87aefeSPatrick Mooney 				cp++;
11754c87aefeSPatrick Mooney 				gpa++;
11764c87aefeSPatrick Mooney 				gva++;
11774c87aefeSPatrick Mooney 				resid--;
11784c87aefeSPatrick Mooney 				todo--;
11794c87aefeSPatrick Mooney 			}
11804c87aefeSPatrick Mooney 		} else {
11814c87aefeSPatrick Mooney 			/*
11824c87aefeSPatrick Mooney 			 * If this page isn't guest RAM, try to handle
11834c87aefeSPatrick Mooney 			 * it via MMIO.  For MMIO requests, use
11844c87aefeSPatrick Mooney 			 * aligned writes of words when possible.
11854c87aefeSPatrick Mooney 			 */
11864c87aefeSPatrick Mooney 			while (todo > 0) {
11874c87aefeSPatrick Mooney 				if (gpa & 1 || todo == 1) {
11884c87aefeSPatrick Mooney 					bytes = 1;
11894c87aefeSPatrick Mooney 					val = parse_byte(data);
11904c87aefeSPatrick Mooney 				} else if (gpa & 2 || todo == 2) {
11914c87aefeSPatrick Mooney 					bytes = 2;
119284659b24SMichael Zeller 					val = be16toh(parse_integer(data, 4));
11934c87aefeSPatrick Mooney 				} else {
11944c87aefeSPatrick Mooney 					bytes = 4;
119584659b24SMichael Zeller 					val = be32toh(parse_integer(data, 8));
11964c87aefeSPatrick Mooney 				}
11974c87aefeSPatrick Mooney 				error = write_mem(ctx, cur_vcpu, gpa, val,
11984c87aefeSPatrick Mooney 				    bytes);
11994c87aefeSPatrick Mooney 				if (error == 0) {
12004c87aefeSPatrick Mooney 					gpa += bytes;
12014c87aefeSPatrick Mooney 					gva += bytes;
12024c87aefeSPatrick Mooney 					resid -= bytes;
12034c87aefeSPatrick Mooney 					todo -= bytes;
12044c87aefeSPatrick Mooney 					data += 2 * bytes;
12054c87aefeSPatrick Mooney 					len -= 2 * bytes;
12064c87aefeSPatrick Mooney 				} else {
12074c87aefeSPatrick Mooney 					send_error(EFAULT);
12084c87aefeSPatrick Mooney 					return;
12094c87aefeSPatrick Mooney 				}
12104c87aefeSPatrick Mooney 			}
12114c87aefeSPatrick Mooney 		}
12124c87aefeSPatrick Mooney 		assert(resid == 0 || gpa % getpagesize() == 0);
12134c87aefeSPatrick Mooney 	}
12144c87aefeSPatrick Mooney 	assert(len == 0);
12154c87aefeSPatrick Mooney 	send_ok();
12164c87aefeSPatrick Mooney }
12174c87aefeSPatrick Mooney 
12184c87aefeSPatrick Mooney static bool
1219154972afSPatrick Mooney set_breakpoint_caps(bool enable)
1220154972afSPatrick Mooney {
1221154972afSPatrick Mooney 	cpuset_t mask;
1222154972afSPatrick Mooney 	int vcpu;
1223154972afSPatrick Mooney 
1224154972afSPatrick Mooney 	mask = vcpus_active;
1225154972afSPatrick Mooney 	while (!CPU_EMPTY(&mask)) {
1226154972afSPatrick Mooney 		vcpu = CPU_FFS(&mask) - 1;
1227154972afSPatrick Mooney 		CPU_CLR(vcpu, &mask);
1228154972afSPatrick Mooney 		if (vm_set_capability(ctx, vcpu, VM_CAP_BPT_EXIT,
1229154972afSPatrick Mooney 		    enable ? 1 : 0) < 0)
1230154972afSPatrick Mooney 			return (false);
1231154972afSPatrick Mooney 		debug("$vCPU %d %sabled breakpoint exits\n", vcpu,
1232154972afSPatrick Mooney 		    enable ? "en" : "dis");
1233154972afSPatrick Mooney 	}
1234154972afSPatrick Mooney 	return (true);
1235154972afSPatrick Mooney }
1236154972afSPatrick Mooney 
1237154972afSPatrick Mooney static void
1238154972afSPatrick Mooney remove_all_sw_breakpoints(void)
1239154972afSPatrick Mooney {
1240154972afSPatrick Mooney 	struct breakpoint *bp, *nbp;
1241154972afSPatrick Mooney 	uint8_t *cp;
1242154972afSPatrick Mooney 
1243154972afSPatrick Mooney 	if (TAILQ_EMPTY(&breakpoints))
1244154972afSPatrick Mooney 		return;
1245154972afSPatrick Mooney 
1246154972afSPatrick Mooney 	TAILQ_FOREACH_SAFE(bp, &breakpoints, link, nbp) {
1247154972afSPatrick Mooney 		debug("remove breakpoint at %#lx\n", bp->gpa);
1248154972afSPatrick Mooney 		cp = paddr_guest2host(ctx, bp->gpa, 1);
1249154972afSPatrick Mooney 		*cp = bp->shadow_inst;
1250154972afSPatrick Mooney 		TAILQ_REMOVE(&breakpoints, bp, link);
1251154972afSPatrick Mooney 		free(bp);
1252154972afSPatrick Mooney 	}
1253154972afSPatrick Mooney 	TAILQ_INIT(&breakpoints);
1254154972afSPatrick Mooney 	set_breakpoint_caps(false);
1255154972afSPatrick Mooney }
1256154972afSPatrick Mooney 
1257154972afSPatrick Mooney static void
1258154972afSPatrick Mooney update_sw_breakpoint(uint64_t gva, int kind, bool insert)
1259154972afSPatrick Mooney {
1260154972afSPatrick Mooney 	struct breakpoint *bp;
1261154972afSPatrick Mooney 	uint64_t gpa;
1262154972afSPatrick Mooney 	uint8_t *cp;
1263154972afSPatrick Mooney 	int error;
1264154972afSPatrick Mooney 
1265154972afSPatrick Mooney 	if (kind != 1) {
1266154972afSPatrick Mooney 		send_error(EINVAL);
1267154972afSPatrick Mooney 		return;
1268154972afSPatrick Mooney 	}
1269154972afSPatrick Mooney 
1270154972afSPatrick Mooney 	error = guest_vaddr2paddr(cur_vcpu, gva, &gpa);
1271154972afSPatrick Mooney 	if (error == -1) {
1272154972afSPatrick Mooney 		send_error(errno);
1273154972afSPatrick Mooney 		return;
1274154972afSPatrick Mooney 	}
1275154972afSPatrick Mooney 	if (error == 0) {
1276154972afSPatrick Mooney 		send_error(EFAULT);
1277154972afSPatrick Mooney 		return;
1278154972afSPatrick Mooney 	}
1279154972afSPatrick Mooney 
1280154972afSPatrick Mooney 	cp = paddr_guest2host(ctx, gpa, 1);
1281154972afSPatrick Mooney 
1282154972afSPatrick Mooney 	/* Only permit breakpoints in guest RAM. */
1283154972afSPatrick Mooney 	if (cp == NULL) {
1284154972afSPatrick Mooney 		send_error(EFAULT);
1285154972afSPatrick Mooney 		return;
1286154972afSPatrick Mooney 	}
1287154972afSPatrick Mooney 
1288154972afSPatrick Mooney 	/* Find any existing breakpoint. */
1289154972afSPatrick Mooney 	bp = find_breakpoint(gpa);
1290154972afSPatrick Mooney 
1291154972afSPatrick Mooney 	/*
1292154972afSPatrick Mooney 	 * Silently ignore duplicate commands since the protocol
1293154972afSPatrick Mooney 	 * requires these packets to be idempotent.
1294154972afSPatrick Mooney 	 */
1295154972afSPatrick Mooney 	if (insert) {
1296154972afSPatrick Mooney 		if (bp == NULL) {
1297154972afSPatrick Mooney 			if (TAILQ_EMPTY(&breakpoints) &&
1298154972afSPatrick Mooney 			    !set_breakpoint_caps(true)) {
1299154972afSPatrick Mooney 				send_empty_response();
1300154972afSPatrick Mooney 				return;
1301154972afSPatrick Mooney 			}
1302154972afSPatrick Mooney 			bp = malloc(sizeof(*bp));
1303154972afSPatrick Mooney 			bp->gpa = gpa;
1304154972afSPatrick Mooney 			bp->shadow_inst = *cp;
1305154972afSPatrick Mooney 			*cp = 0xcc;	/* INT 3 */
1306154972afSPatrick Mooney 			TAILQ_INSERT_TAIL(&breakpoints, bp, link);
1307154972afSPatrick Mooney 			debug("new breakpoint at %#lx\n", gpa);
1308154972afSPatrick Mooney 		}
1309154972afSPatrick Mooney 	} else {
1310154972afSPatrick Mooney 		if (bp != NULL) {
1311154972afSPatrick Mooney 			debug("remove breakpoint at %#lx\n", gpa);
1312154972afSPatrick Mooney 			*cp = bp->shadow_inst;
1313154972afSPatrick Mooney 			TAILQ_REMOVE(&breakpoints, bp, link);
1314154972afSPatrick Mooney 			free(bp);
1315154972afSPatrick Mooney 			if (TAILQ_EMPTY(&breakpoints))
1316154972afSPatrick Mooney 				set_breakpoint_caps(false);
1317154972afSPatrick Mooney 		}
1318154972afSPatrick Mooney 	}
1319154972afSPatrick Mooney 	send_ok();
1320154972afSPatrick Mooney }
1321154972afSPatrick Mooney 
1322154972afSPatrick Mooney static void
1323154972afSPatrick Mooney parse_breakpoint(const uint8_t *data, size_t len)
1324154972afSPatrick Mooney {
1325154972afSPatrick Mooney 	uint64_t gva;
1326154972afSPatrick Mooney 	uint8_t *cp;
1327154972afSPatrick Mooney 	bool insert;
1328154972afSPatrick Mooney 	int kind, type;
1329154972afSPatrick Mooney 
1330154972afSPatrick Mooney 	insert = data[0] == 'Z';
1331154972afSPatrick Mooney 
1332154972afSPatrick Mooney 	/* Skip 'Z/z' */
1333154972afSPatrick Mooney 	data += 1;
1334154972afSPatrick Mooney 	len -= 1;
1335154972afSPatrick Mooney 
1336154972afSPatrick Mooney 	/* Parse and consume type. */
1337154972afSPatrick Mooney 	cp = memchr(data, ',', len);
1338154972afSPatrick Mooney 	if (cp == NULL || cp == data) {
1339154972afSPatrick Mooney 		send_error(EINVAL);
1340154972afSPatrick Mooney 		return;
1341154972afSPatrick Mooney 	}
1342154972afSPatrick Mooney 	type = parse_integer(data, cp - data);
1343154972afSPatrick Mooney 	len -= (cp - data) + 1;
1344154972afSPatrick Mooney 	data += (cp - data) + 1;
1345154972afSPatrick Mooney 
1346154972afSPatrick Mooney 	/* Parse and consume address. */
1347154972afSPatrick Mooney 	cp = memchr(data, ',', len);
1348154972afSPatrick Mooney 	if (cp == NULL || cp == data) {
1349154972afSPatrick Mooney 		send_error(EINVAL);
1350154972afSPatrick Mooney 		return;
1351154972afSPatrick Mooney 	}
1352154972afSPatrick Mooney 	gva = parse_integer(data, cp - data);
1353154972afSPatrick Mooney 	len -= (cp - data) + 1;
1354154972afSPatrick Mooney 	data += (cp - data) + 1;
1355154972afSPatrick Mooney 
1356154972afSPatrick Mooney 	/* Parse and consume kind. */
1357154972afSPatrick Mooney 	cp = memchr(data, ';', len);
1358154972afSPatrick Mooney 	if (cp == data) {
1359154972afSPatrick Mooney 		send_error(EINVAL);
1360154972afSPatrick Mooney 		return;
1361154972afSPatrick Mooney 	}
1362154972afSPatrick Mooney 	if (cp != NULL) {
1363154972afSPatrick Mooney 		/*
1364154972afSPatrick Mooney 		 * We do not advertise support for either the
1365154972afSPatrick Mooney 		 * ConditionalBreakpoints or BreakpointCommands
1366154972afSPatrick Mooney 		 * features, so we should not be getting conditions or
1367154972afSPatrick Mooney 		 * commands from the remote end.
1368154972afSPatrick Mooney 		 */
1369154972afSPatrick Mooney 		send_empty_response();
1370154972afSPatrick Mooney 		return;
1371154972afSPatrick Mooney 	}
1372154972afSPatrick Mooney 	kind = parse_integer(data, len);
1373154972afSPatrick Mooney 	data += len;
1374154972afSPatrick Mooney 	len = 0;
1375154972afSPatrick Mooney 
1376154972afSPatrick Mooney 	switch (type) {
1377154972afSPatrick Mooney 	case 0:
1378154972afSPatrick Mooney 		update_sw_breakpoint(gva, kind, insert);
1379154972afSPatrick Mooney 		break;
1380154972afSPatrick Mooney 	default:
1381154972afSPatrick Mooney 		send_empty_response();
1382154972afSPatrick Mooney 		break;
1383154972afSPatrick Mooney 	}
1384154972afSPatrick Mooney }
1385154972afSPatrick Mooney 
1386154972afSPatrick Mooney static bool
13874c87aefeSPatrick Mooney command_equals(const uint8_t *data, size_t len, const char *cmd)
13884c87aefeSPatrick Mooney {
13894c87aefeSPatrick Mooney 
13904c87aefeSPatrick Mooney 	if (strlen(cmd) > len)
13914c87aefeSPatrick Mooney 		return (false);
13924c87aefeSPatrick Mooney 	return (memcmp(data, cmd, strlen(cmd)) == 0);
13934c87aefeSPatrick Mooney }
13944c87aefeSPatrick Mooney 
13954c87aefeSPatrick Mooney static void
13964c87aefeSPatrick Mooney check_features(const uint8_t *data, size_t len)
13974c87aefeSPatrick Mooney {
13984c87aefeSPatrick Mooney 	char *feature, *next_feature, *str, *value;
13994c87aefeSPatrick Mooney 	bool supported;
14004c87aefeSPatrick Mooney 
14014c87aefeSPatrick Mooney 	str = malloc(len + 1);
14024c87aefeSPatrick Mooney 	memcpy(str, data, len);
14034c87aefeSPatrick Mooney 	str[len] = '\0';
14044c87aefeSPatrick Mooney 	next_feature = str;
14054c87aefeSPatrick Mooney 
14064c87aefeSPatrick Mooney 	while ((feature = strsep(&next_feature, ";")) != NULL) {
14074c87aefeSPatrick Mooney 		/*
14084c87aefeSPatrick Mooney 		 * Null features shouldn't exist, but skip if they
14094c87aefeSPatrick Mooney 		 * do.
14104c87aefeSPatrick Mooney 		 */
14114c87aefeSPatrick Mooney 		if (strcmp(feature, "") == 0)
14124c87aefeSPatrick Mooney 			continue;
14134c87aefeSPatrick Mooney 
14144c87aefeSPatrick Mooney 		/*
14154c87aefeSPatrick Mooney 		 * Look for the value or supported / not supported
14164c87aefeSPatrick Mooney 		 * flag.
14174c87aefeSPatrick Mooney 		 */
14184c87aefeSPatrick Mooney 		value = strchr(feature, '=');
14194c87aefeSPatrick Mooney 		if (value != NULL) {
14204c87aefeSPatrick Mooney 			*value = '\0';
14214c87aefeSPatrick Mooney 			value++;
14224c87aefeSPatrick Mooney 			supported = true;
14234c87aefeSPatrick Mooney 		} else {
14244c87aefeSPatrick Mooney 			value = feature + strlen(feature) - 1;
14254c87aefeSPatrick Mooney 			switch (*value) {
14264c87aefeSPatrick Mooney 			case '+':
14274c87aefeSPatrick Mooney 				supported = true;
14284c87aefeSPatrick Mooney 				break;
14294c87aefeSPatrick Mooney 			case '-':
14304c87aefeSPatrick Mooney 				supported = false;
14314c87aefeSPatrick Mooney 				break;
14324c87aefeSPatrick Mooney 			default:
14334c87aefeSPatrick Mooney 				/*
14344c87aefeSPatrick Mooney 				 * This is really a protocol error,
14354c87aefeSPatrick Mooney 				 * but we just ignore malformed
14364c87aefeSPatrick Mooney 				 * features for ease of
14374c87aefeSPatrick Mooney 				 * implementation.
14384c87aefeSPatrick Mooney 				 */
14394c87aefeSPatrick Mooney 				continue;
14404c87aefeSPatrick Mooney 			}
14414c87aefeSPatrick Mooney 			value = NULL;
14424c87aefeSPatrick Mooney 		}
14434c87aefeSPatrick Mooney 
1444154972afSPatrick Mooney 		if (strcmp(feature, "swbreak") == 0)
1445154972afSPatrick Mooney 			swbreak_enabled = supported;
1446154972afSPatrick Mooney 
14474c87aefeSPatrick Mooney #ifndef __FreeBSD__
14484c87aefeSPatrick Mooney 		/*
14494c87aefeSPatrick Mooney 		 * The compiler dislikes 'supported' being set but never used.
14504c87aefeSPatrick Mooney 		 * Make it happy here.
14514c87aefeSPatrick Mooney 		 */
14524c87aefeSPatrick Mooney 		if (supported) {
14534c87aefeSPatrick Mooney 			debug("feature '%s' supported\n", feature);
14544c87aefeSPatrick Mooney 		}
14554c87aefeSPatrick Mooney #endif /* __FreeBSD__ */
14564c87aefeSPatrick Mooney 	}
14574c87aefeSPatrick Mooney 	free(str);
14584c87aefeSPatrick Mooney 
14594c87aefeSPatrick Mooney 	start_packet();
14604c87aefeSPatrick Mooney 
14614c87aefeSPatrick Mooney 	/* This is an arbitrary limit. */
14624c87aefeSPatrick Mooney 	append_string("PacketSize=4096");
1463154972afSPatrick Mooney 	append_string(";swbreak+");
14644c87aefeSPatrick Mooney 	finish_packet();
14654c87aefeSPatrick Mooney }
14664c87aefeSPatrick Mooney 
14674c87aefeSPatrick Mooney static void
14684c87aefeSPatrick Mooney gdb_query(const uint8_t *data, size_t len)
14694c87aefeSPatrick Mooney {
14704c87aefeSPatrick Mooney 
14714c87aefeSPatrick Mooney 	/*
14724c87aefeSPatrick Mooney 	 * TODO:
14734c87aefeSPatrick Mooney 	 * - qSearch
14744c87aefeSPatrick Mooney 	 */
14754c87aefeSPatrick Mooney 	if (command_equals(data, len, "qAttached")) {
14764c87aefeSPatrick Mooney 		start_packet();
14774c87aefeSPatrick Mooney 		append_char('1');
14784c87aefeSPatrick Mooney 		finish_packet();
14794c87aefeSPatrick Mooney 	} else if (command_equals(data, len, "qC")) {
14804c87aefeSPatrick Mooney 		start_packet();
14814c87aefeSPatrick Mooney 		append_string("QC");
14824c87aefeSPatrick Mooney 		append_integer(cur_vcpu + 1);
14834c87aefeSPatrick Mooney 		finish_packet();
14844c87aefeSPatrick Mooney 	} else if (command_equals(data, len, "qfThreadInfo")) {
14854c87aefeSPatrick Mooney 		cpuset_t mask;
14864c87aefeSPatrick Mooney 		bool first;
14874c87aefeSPatrick Mooney 		int vcpu;
14884c87aefeSPatrick Mooney 
14894c87aefeSPatrick Mooney 		if (CPU_EMPTY(&vcpus_active)) {
14904c87aefeSPatrick Mooney 			send_error(EINVAL);
14914c87aefeSPatrick Mooney 			return;
14924c87aefeSPatrick Mooney 		}
14934c87aefeSPatrick Mooney 		mask = vcpus_active;
14944c87aefeSPatrick Mooney 		start_packet();
14954c87aefeSPatrick Mooney 		append_char('m');
14964c87aefeSPatrick Mooney 		first = true;
14974c87aefeSPatrick Mooney 		while (!CPU_EMPTY(&mask)) {
14984c87aefeSPatrick Mooney 			vcpu = CPU_FFS(&mask) - 1;
14994c87aefeSPatrick Mooney 			CPU_CLR(vcpu, &mask);
15004c87aefeSPatrick Mooney 			if (first)
15014c87aefeSPatrick Mooney 				first = false;
15024c87aefeSPatrick Mooney 			else
15034c87aefeSPatrick Mooney 				append_char(',');
15044c87aefeSPatrick Mooney 			append_integer(vcpu + 1);
15054c87aefeSPatrick Mooney 		}
15064c87aefeSPatrick Mooney 		finish_packet();
15074c87aefeSPatrick Mooney 	} else if (command_equals(data, len, "qsThreadInfo")) {
15084c87aefeSPatrick Mooney 		start_packet();
15094c87aefeSPatrick Mooney 		append_char('l');
15104c87aefeSPatrick Mooney 		finish_packet();
15114c87aefeSPatrick Mooney 	} else if (command_equals(data, len, "qSupported")) {
15124c87aefeSPatrick Mooney 		data += strlen("qSupported");
15134c87aefeSPatrick Mooney 		len -= strlen("qSupported");
15144c87aefeSPatrick Mooney 		check_features(data, len);
15154c87aefeSPatrick Mooney 	} else if (command_equals(data, len, "qThreadExtraInfo")) {
15164c87aefeSPatrick Mooney 		char buf[16];
15174c87aefeSPatrick Mooney 		int tid;
15184c87aefeSPatrick Mooney 
15194c87aefeSPatrick Mooney 		data += strlen("qThreadExtraInfo");
15204c87aefeSPatrick Mooney 		len -= strlen("qThreadExtraInfo");
15214c87aefeSPatrick Mooney 		if (*data != ',') {
15224c87aefeSPatrick Mooney 			send_error(EINVAL);
15234c87aefeSPatrick Mooney 			return;
15244c87aefeSPatrick Mooney 		}
15254c87aefeSPatrick Mooney 		tid = parse_threadid(data + 1, len - 1);
15264c87aefeSPatrick Mooney 		if (tid <= 0 || !CPU_ISSET(tid - 1, &vcpus_active)) {
15274c87aefeSPatrick Mooney 			send_error(EINVAL);
15284c87aefeSPatrick Mooney 			return;
15294c87aefeSPatrick Mooney 		}
15304c87aefeSPatrick Mooney 
15314c87aefeSPatrick Mooney 		snprintf(buf, sizeof(buf), "vCPU %d", tid - 1);
15324c87aefeSPatrick Mooney 		start_packet();
15334c87aefeSPatrick Mooney 		append_asciihex(buf);
15344c87aefeSPatrick Mooney 		finish_packet();
15354c87aefeSPatrick Mooney 	} else
15364c87aefeSPatrick Mooney 		send_empty_response();
15374c87aefeSPatrick Mooney }
15384c87aefeSPatrick Mooney 
15394c87aefeSPatrick Mooney static void
15404c87aefeSPatrick Mooney handle_command(const uint8_t *data, size_t len)
15414c87aefeSPatrick Mooney {
15424c87aefeSPatrick Mooney 
15434c87aefeSPatrick Mooney 	/* Reject packets with a sequence-id. */
15444c87aefeSPatrick Mooney 	if (len >= 3 && data[0] >= '0' && data[0] <= '9' &&
15454c87aefeSPatrick Mooney 	    data[0] >= '0' && data[0] <= '9' && data[2] == ':') {
15464c87aefeSPatrick Mooney 		send_empty_response();
15474c87aefeSPatrick Mooney 		return;
15484c87aefeSPatrick Mooney 	}
15494c87aefeSPatrick Mooney 
15504c87aefeSPatrick Mooney 	switch (*data) {
15514c87aefeSPatrick Mooney 	case 'c':
15524c87aefeSPatrick Mooney 		if (len != 1) {
15534c87aefeSPatrick Mooney 			send_error(EINVAL);
15544c87aefeSPatrick Mooney 			break;
15554c87aefeSPatrick Mooney 		}
15564c87aefeSPatrick Mooney 
1557154972afSPatrick Mooney 		discard_stop();
15584c87aefeSPatrick Mooney 		gdb_resume_vcpus();
15594c87aefeSPatrick Mooney 		break;
15604c87aefeSPatrick Mooney 	case 'D':
15614c87aefeSPatrick Mooney 		send_ok();
15624c87aefeSPatrick Mooney 
15634c87aefeSPatrick Mooney 		/* TODO: Resume any stopped CPUs. */
15644c87aefeSPatrick Mooney 		break;
15654c87aefeSPatrick Mooney 	case 'g': {
15664c87aefeSPatrick Mooney 		gdb_read_regs();
15674c87aefeSPatrick Mooney 		break;
15684c87aefeSPatrick Mooney 	}
15694c87aefeSPatrick Mooney 	case 'H': {
15704c87aefeSPatrick Mooney 		int tid;
15714c87aefeSPatrick Mooney 
15724c87aefeSPatrick Mooney 		if (data[1] != 'g' && data[1] != 'c') {
15734c87aefeSPatrick Mooney 			send_error(EINVAL);
15744c87aefeSPatrick Mooney 			break;
15754c87aefeSPatrick Mooney 		}
15764c87aefeSPatrick Mooney 		tid = parse_threadid(data + 2, len - 2);
15774c87aefeSPatrick Mooney 		if (tid == -2) {
15784c87aefeSPatrick Mooney 			send_error(EINVAL);
15794c87aefeSPatrick Mooney 			break;
15804c87aefeSPatrick Mooney 		}
15814c87aefeSPatrick Mooney 
15824c87aefeSPatrick Mooney 		if (CPU_EMPTY(&vcpus_active)) {
15834c87aefeSPatrick Mooney 			send_error(EINVAL);
15844c87aefeSPatrick Mooney 			break;
15854c87aefeSPatrick Mooney 		}
15864c87aefeSPatrick Mooney 		if (tid == -1 || tid == 0)
15874c87aefeSPatrick Mooney 			cur_vcpu = CPU_FFS(&vcpus_active) - 1;
15884c87aefeSPatrick Mooney 		else if (CPU_ISSET(tid - 1, &vcpus_active))
15894c87aefeSPatrick Mooney 			cur_vcpu = tid - 1;
15904c87aefeSPatrick Mooney 		else {
15914c87aefeSPatrick Mooney 			send_error(EINVAL);
15924c87aefeSPatrick Mooney 			break;
15934c87aefeSPatrick Mooney 		}
15944c87aefeSPatrick Mooney 		send_ok();
15954c87aefeSPatrick Mooney 		break;
15964c87aefeSPatrick Mooney 	}
15974c87aefeSPatrick Mooney 	case 'm':
15984c87aefeSPatrick Mooney 		gdb_read_mem(data, len);
15994c87aefeSPatrick Mooney 		break;
16004c87aefeSPatrick Mooney 	case 'M':
16014c87aefeSPatrick Mooney 		gdb_write_mem(data, len);
16024c87aefeSPatrick Mooney 		break;
16034c87aefeSPatrick Mooney 	case 'T': {
16044c87aefeSPatrick Mooney 		int tid;
16054c87aefeSPatrick Mooney 
16064c87aefeSPatrick Mooney 		tid = parse_threadid(data + 1, len - 1);
16074c87aefeSPatrick Mooney 		if (tid <= 0 || !CPU_ISSET(tid - 1, &vcpus_active)) {
16084c87aefeSPatrick Mooney 			send_error(EINVAL);
16094c87aefeSPatrick Mooney 			return;
16104c87aefeSPatrick Mooney 		}
16114c87aefeSPatrick Mooney 		send_ok();
16124c87aefeSPatrick Mooney 		break;
16134c87aefeSPatrick Mooney 	}
16144c87aefeSPatrick Mooney 	case 'q':
16154c87aefeSPatrick Mooney 		gdb_query(data, len);
16164c87aefeSPatrick Mooney 		break;
16174c87aefeSPatrick Mooney 	case 's':
16184c87aefeSPatrick Mooney 		if (len != 1) {
16194c87aefeSPatrick Mooney 			send_error(EINVAL);
16204c87aefeSPatrick Mooney 			break;
16214c87aefeSPatrick Mooney 		}
16224c87aefeSPatrick Mooney 
16234c87aefeSPatrick Mooney 		/* Don't send a reply until a stop occurs. */
16244c87aefeSPatrick Mooney 		if (!gdb_step_vcpu(cur_vcpu)) {
16254c87aefeSPatrick Mooney 			send_error(EOPNOTSUPP);
16264c87aefeSPatrick Mooney 			break;
16274c87aefeSPatrick Mooney 		}
16284c87aefeSPatrick Mooney 		break;
1629154972afSPatrick Mooney 	case 'z':
1630154972afSPatrick Mooney 	case 'Z':
1631154972afSPatrick Mooney 		parse_breakpoint(data, len);
1632154972afSPatrick Mooney 		break;
16334c87aefeSPatrick Mooney 	case '?':
1634154972afSPatrick Mooney 		report_stop(false);
16354c87aefeSPatrick Mooney 		break;
16364c87aefeSPatrick Mooney 	case 'G': /* TODO */
16374c87aefeSPatrick Mooney 	case 'v':
16384c87aefeSPatrick Mooney 		/* Handle 'vCont' */
16394c87aefeSPatrick Mooney 		/* 'vCtrlC' */
16404c87aefeSPatrick Mooney 	case 'p': /* TODO */
16414c87aefeSPatrick Mooney 	case 'P': /* TODO */
16424c87aefeSPatrick Mooney 	case 'Q': /* TODO */
16434c87aefeSPatrick Mooney 	case 't': /* TODO */
16444c87aefeSPatrick Mooney 	case 'X': /* TODO */
16454c87aefeSPatrick Mooney 	default:
16464c87aefeSPatrick Mooney 		send_empty_response();
16474c87aefeSPatrick Mooney 	}
16484c87aefeSPatrick Mooney }
16494c87aefeSPatrick Mooney 
16504c87aefeSPatrick Mooney /* Check for a valid packet in the command buffer. */
16514c87aefeSPatrick Mooney static void
16524c87aefeSPatrick Mooney check_command(int fd)
16534c87aefeSPatrick Mooney {
16544c87aefeSPatrick Mooney 	uint8_t *head, *hash, *p, sum;
16554c87aefeSPatrick Mooney 	size_t avail, plen;
16564c87aefeSPatrick Mooney 
16574c87aefeSPatrick Mooney 	for (;;) {
16584c87aefeSPatrick Mooney 		avail = cur_comm.len;
16594c87aefeSPatrick Mooney 		if (avail == 0)
16604c87aefeSPatrick Mooney 			return;
16614c87aefeSPatrick Mooney 		head = io_buffer_head(&cur_comm);
16624c87aefeSPatrick Mooney 		switch (*head) {
16634c87aefeSPatrick Mooney 		case 0x03:
16644c87aefeSPatrick Mooney 			debug("<- Ctrl-C\n");
16654c87aefeSPatrick Mooney 			io_buffer_consume(&cur_comm, 1);
16664c87aefeSPatrick Mooney 
16674c87aefeSPatrick Mooney 			gdb_suspend_vcpus();
16684c87aefeSPatrick Mooney 			break;
16694c87aefeSPatrick Mooney 		case '+':
16704c87aefeSPatrick Mooney 			/* ACK of previous response. */
16714c87aefeSPatrick Mooney 			debug("<- +\n");
16724c87aefeSPatrick Mooney 			if (response_pending())
16734c87aefeSPatrick Mooney 				io_buffer_reset(&cur_resp);
16744c87aefeSPatrick Mooney 			io_buffer_consume(&cur_comm, 1);
1675154972afSPatrick Mooney 			if (stopped_vcpu != -1 && report_next_stop) {
1676154972afSPatrick Mooney 				report_stop(true);
16774c87aefeSPatrick Mooney 				send_pending_data(fd);
16784c87aefeSPatrick Mooney 			}
16794c87aefeSPatrick Mooney 			break;
16804c87aefeSPatrick Mooney 		case '-':
16814c87aefeSPatrick Mooney 			/* NACK of previous response. */
16824c87aefeSPatrick Mooney 			debug("<- -\n");
16834c87aefeSPatrick Mooney 			if (response_pending()) {
16844c87aefeSPatrick Mooney 				cur_resp.len += cur_resp.start;
16854c87aefeSPatrick Mooney 				cur_resp.start = 0;
16864c87aefeSPatrick Mooney 				if (cur_resp.data[0] == '+')
16874c87aefeSPatrick Mooney 					io_buffer_advance(&cur_resp, 1);
16884c87aefeSPatrick Mooney 				debug("-> %.*s\n", (int)cur_resp.len,
16894c87aefeSPatrick Mooney 				    io_buffer_head(&cur_resp));
16904c87aefeSPatrick Mooney 			}
16914c87aefeSPatrick Mooney 			io_buffer_consume(&cur_comm, 1);
16924c87aefeSPatrick Mooney 			send_pending_data(fd);
16934c87aefeSPatrick Mooney 			break;
16944c87aefeSPatrick Mooney 		case '$':
16954c87aefeSPatrick Mooney 			/* Packet. */
16964c87aefeSPatrick Mooney 
16974c87aefeSPatrick Mooney 			if (response_pending()) {
16984c87aefeSPatrick Mooney 				warnx("New GDB command while response in "
16994c87aefeSPatrick Mooney 				    "progress");
17004c87aefeSPatrick Mooney 				io_buffer_reset(&cur_resp);
17014c87aefeSPatrick Mooney 			}
17024c87aefeSPatrick Mooney 
17034c87aefeSPatrick Mooney 			/* Is packet complete? */
17044c87aefeSPatrick Mooney 			hash = memchr(head, '#', avail);
17054c87aefeSPatrick Mooney 			if (hash == NULL)
17064c87aefeSPatrick Mooney 				return;
17074c87aefeSPatrick Mooney 			plen = (hash - head + 1) + 2;
17084c87aefeSPatrick Mooney 			if (avail < plen)
17094c87aefeSPatrick Mooney 				return;
17104c87aefeSPatrick Mooney 			debug("<- %.*s\n", (int)plen, head);
17114c87aefeSPatrick Mooney 
17124c87aefeSPatrick Mooney 			/* Verify checksum. */
17134c87aefeSPatrick Mooney 			for (sum = 0, p = head + 1; p < hash; p++)
17144c87aefeSPatrick Mooney 				sum += *p;
17154c87aefeSPatrick Mooney 			if (sum != parse_byte(hash + 1)) {
17164c87aefeSPatrick Mooney 				io_buffer_consume(&cur_comm, plen);
17174c87aefeSPatrick Mooney 				debug("-> -\n");
17184c87aefeSPatrick Mooney 				send_char('-');
17194c87aefeSPatrick Mooney 				send_pending_data(fd);
17204c87aefeSPatrick Mooney 				break;
17214c87aefeSPatrick Mooney 			}
17224c87aefeSPatrick Mooney 			send_char('+');
17234c87aefeSPatrick Mooney 
17244c87aefeSPatrick Mooney 			handle_command(head + 1, hash - (head + 1));
17254c87aefeSPatrick Mooney 			io_buffer_consume(&cur_comm, plen);
17264c87aefeSPatrick Mooney 			if (!response_pending()) {
17274c87aefeSPatrick Mooney 				debug("-> +\n");
17284c87aefeSPatrick Mooney 			}
17294c87aefeSPatrick Mooney 			send_pending_data(fd);
17304c87aefeSPatrick Mooney 			break;
17314c87aefeSPatrick Mooney 		default:
17324c87aefeSPatrick Mooney 			/* XXX: Possibly drop connection instead. */
17334c87aefeSPatrick Mooney 			debug("-> %02x\n", *head);
17344c87aefeSPatrick Mooney 			io_buffer_consume(&cur_comm, 1);
17354c87aefeSPatrick Mooney 			break;
17364c87aefeSPatrick Mooney 		}
17374c87aefeSPatrick Mooney 	}
17384c87aefeSPatrick Mooney }
17394c87aefeSPatrick Mooney 
17404c87aefeSPatrick Mooney static void
17414c87aefeSPatrick Mooney gdb_readable(int fd, enum ev_type event, void *arg)
17424c87aefeSPatrick Mooney {
17434c87aefeSPatrick Mooney 	ssize_t nread;
17444c87aefeSPatrick Mooney 	int pending;
17454c87aefeSPatrick Mooney 
17464c87aefeSPatrick Mooney 	if (ioctl(fd, FIONREAD, &pending) == -1) {
17474c87aefeSPatrick Mooney 		warn("FIONREAD on GDB socket");
17484c87aefeSPatrick Mooney 		return;
17494c87aefeSPatrick Mooney 	}
17504c87aefeSPatrick Mooney 
17514c87aefeSPatrick Mooney 	/*
17524c87aefeSPatrick Mooney 	 * 'pending' might be zero due to EOF.  We need to call read
17534c87aefeSPatrick Mooney 	 * with a non-zero length to detect EOF.
17544c87aefeSPatrick Mooney 	 */
17554c87aefeSPatrick Mooney 	if (pending == 0)
17564c87aefeSPatrick Mooney 		pending = 1;
17574c87aefeSPatrick Mooney 
17584c87aefeSPatrick Mooney 	/* Ensure there is room in the command buffer. */
17594c87aefeSPatrick Mooney 	io_buffer_grow(&cur_comm, pending);
17604c87aefeSPatrick Mooney 	assert(io_buffer_avail(&cur_comm) >= pending);
17614c87aefeSPatrick Mooney 
17624c87aefeSPatrick Mooney 	nread = read(fd, io_buffer_tail(&cur_comm), io_buffer_avail(&cur_comm));
17634c87aefeSPatrick Mooney 	if (nread == 0) {
17644c87aefeSPatrick Mooney 		close_connection();
17654c87aefeSPatrick Mooney 	} else if (nread == -1) {
17664c87aefeSPatrick Mooney 		if (errno == EAGAIN)
17674c87aefeSPatrick Mooney 			return;
17684c87aefeSPatrick Mooney 
17694c87aefeSPatrick Mooney 		warn("Read from GDB socket");
17704c87aefeSPatrick Mooney 		close_connection();
17714c87aefeSPatrick Mooney 	} else {
17724c87aefeSPatrick Mooney 		cur_comm.len += nread;
17734c87aefeSPatrick Mooney 		pthread_mutex_lock(&gdb_lock);
17744c87aefeSPatrick Mooney 		check_command(fd);
17754c87aefeSPatrick Mooney 		pthread_mutex_unlock(&gdb_lock);
17764c87aefeSPatrick Mooney 	}
17774c87aefeSPatrick Mooney }
17784c87aefeSPatrick Mooney 
17794c87aefeSPatrick Mooney static void
17804c87aefeSPatrick Mooney gdb_writable(int fd, enum ev_type event, void *arg)
17814c87aefeSPatrick Mooney {
17824c87aefeSPatrick Mooney 
17834c87aefeSPatrick Mooney 	send_pending_data(fd);
17844c87aefeSPatrick Mooney }
17854c87aefeSPatrick Mooney 
17864c87aefeSPatrick Mooney static void
17874c87aefeSPatrick Mooney new_connection(int fd, enum ev_type event, void *arg)
17884c87aefeSPatrick Mooney {
17894c87aefeSPatrick Mooney 	int optval, s;
17904c87aefeSPatrick Mooney 
17914c87aefeSPatrick Mooney 	s = accept4(fd, NULL, NULL, SOCK_NONBLOCK);
17924c87aefeSPatrick Mooney 	if (s == -1) {
17934c87aefeSPatrick Mooney 		if (arg != NULL)
17944c87aefeSPatrick Mooney 			err(1, "Failed accepting initial GDB connection");
17954c87aefeSPatrick Mooney 
17964c87aefeSPatrick Mooney 		/* Silently ignore errors post-startup. */
17974c87aefeSPatrick Mooney 		return;
17984c87aefeSPatrick Mooney 	}
17994c87aefeSPatrick Mooney 
18004c87aefeSPatrick Mooney 	optval = 1;
18014c87aefeSPatrick Mooney 	if (setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) ==
18024c87aefeSPatrick Mooney 	    -1) {
18034c87aefeSPatrick Mooney 		warn("Failed to disable SIGPIPE for GDB connection");
18044c87aefeSPatrick Mooney 		close(s);
18054c87aefeSPatrick Mooney 		return;
18064c87aefeSPatrick Mooney 	}
18074c87aefeSPatrick Mooney 
18084c87aefeSPatrick Mooney 	pthread_mutex_lock(&gdb_lock);
18094c87aefeSPatrick Mooney 	if (cur_fd != -1) {
18104c87aefeSPatrick Mooney 		close(s);
18114c87aefeSPatrick Mooney 		warnx("Ignoring additional GDB connection.");
18124c87aefeSPatrick Mooney 	}
18134c87aefeSPatrick Mooney 
18144c87aefeSPatrick Mooney 	read_event = mevent_add(s, EVF_READ, gdb_readable, NULL);
18154c87aefeSPatrick Mooney 	if (read_event == NULL) {
18164c87aefeSPatrick Mooney 		if (arg != NULL)
18174c87aefeSPatrick Mooney 			err(1, "Failed to setup initial GDB connection");
18184c87aefeSPatrick Mooney 		pthread_mutex_unlock(&gdb_lock);
18194c87aefeSPatrick Mooney 		return;
18204c87aefeSPatrick Mooney 	}
18214c87aefeSPatrick Mooney 	write_event = mevent_add(s, EVF_WRITE, gdb_writable, NULL);
18224c87aefeSPatrick Mooney 	if (write_event == NULL) {
18234c87aefeSPatrick Mooney 		if (arg != NULL)
18244c87aefeSPatrick Mooney 			err(1, "Failed to setup initial GDB connection");
18254c87aefeSPatrick Mooney 		mevent_delete_close(read_event);
18264c87aefeSPatrick Mooney 		read_event = NULL;
18274c87aefeSPatrick Mooney 	}
18284c87aefeSPatrick Mooney 
18294c87aefeSPatrick Mooney 	cur_fd = s;
18304c87aefeSPatrick Mooney 	cur_vcpu = 0;
18314c87aefeSPatrick Mooney 	stopped_vcpu = -1;
18324c87aefeSPatrick Mooney 
18334c87aefeSPatrick Mooney 	/* Break on attach. */
18344c87aefeSPatrick Mooney 	first_stop = true;
1835154972afSPatrick Mooney 	report_next_stop = false;
18364c87aefeSPatrick Mooney 	gdb_suspend_vcpus();
18374c87aefeSPatrick Mooney 	pthread_mutex_unlock(&gdb_lock);
18384c87aefeSPatrick Mooney }
18394c87aefeSPatrick Mooney 
18404c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
1841*4f3f3e9aSAndy Fiddaman static void
18424c87aefeSPatrick Mooney limit_gdb_socket(int s)
18434c87aefeSPatrick Mooney {
18444c87aefeSPatrick Mooney 	cap_rights_t rights;
18454c87aefeSPatrick Mooney 	unsigned long ioctls[] = { FIONREAD };
18464c87aefeSPatrick Mooney 
18474c87aefeSPatrick Mooney 	cap_rights_init(&rights, CAP_ACCEPT, CAP_EVENT, CAP_READ, CAP_WRITE,
18484c87aefeSPatrick Mooney 	    CAP_SETSOCKOPT, CAP_IOCTL);
18494c87aefeSPatrick Mooney 	if (caph_rights_limit(s, &rights) == -1)
18504c87aefeSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
18514c87aefeSPatrick Mooney 	if (caph_ioctls_limit(s, ioctls, nitems(ioctls)) == -1)
18524c87aefeSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
18534c87aefeSPatrick Mooney }
18544c87aefeSPatrick Mooney #endif
18554c87aefeSPatrick Mooney 
1856c3d209caSPatrick Mooney 
1857c3d209caSPatrick Mooney #ifndef __FreeBSD__
1858c3d209caSPatrick Mooney /*
1859c3d209caSPatrick Mooney  * Equivalent to init_gdb() below, but without configuring the listening socket.
1860c3d209caSPatrick Mooney  * This will allow the bhyve process to tolerate mdb attaching/detaching from
1861c3d209caSPatrick Mooney  * the instance while it is running.
1862c3d209caSPatrick Mooney  */
1863c3d209caSPatrick Mooney void
1864b0de25cbSAndy Fiddaman init_mdb(struct vmctx *_ctx)
1865c3d209caSPatrick Mooney {
1866c3d209caSPatrick Mooney 	int error;
1867b0de25cbSAndy Fiddaman 	bool wait;
1868b0de25cbSAndy Fiddaman 
1869b0de25cbSAndy Fiddaman 	wait = get_config_bool_default("gdb.wait", false);
1870c3d209caSPatrick Mooney 
1871c3d209caSPatrick Mooney 	error = pthread_mutex_init(&gdb_lock, NULL);
1872c3d209caSPatrick Mooney 	if (error != 0)
1873c3d209caSPatrick Mooney 		errc(1, error, "gdb mutex init");
1874c3d209caSPatrick Mooney 	error = pthread_cond_init(&idle_vcpus, NULL);
1875c3d209caSPatrick Mooney 	if (error != 0)
1876c3d209caSPatrick Mooney 		errc(1, error, "gdb cv init");
1877c3d209caSPatrick Mooney 
1878c3d209caSPatrick Mooney 	ctx = _ctx;
1879c3d209caSPatrick Mooney 	stopped_vcpu = -1;
1880c3d209caSPatrick Mooney 	TAILQ_INIT(&breakpoints);
1881c3d209caSPatrick Mooney 	vcpu_state = calloc(guest_ncpus, sizeof(*vcpu_state));
1882c3d209caSPatrick Mooney 	if (wait) {
1883c3d209caSPatrick Mooney 		/*
1884c3d209caSPatrick Mooney 		 * Set vcpu 0 in vcpus_suspended.  This will trigger the
1885c3d209caSPatrick Mooney 		 * logic in gdb_cpu_add() to suspend the first vcpu before
1886c3d209caSPatrick Mooney 		 * it starts execution.  The vcpu will remain suspended
1887c3d209caSPatrick Mooney 		 * until a debugger connects.
1888c3d209caSPatrick Mooney 		 */
1889c3d209caSPatrick Mooney 		CPU_SET(0, &vcpus_suspended);
1890c3d209caSPatrick Mooney 		stopped_vcpu = 0;
1891c3d209caSPatrick Mooney 	}
1892c3d209caSPatrick Mooney }
1893c3d209caSPatrick Mooney #endif
1894c3d209caSPatrick Mooney 
18954c87aefeSPatrick Mooney void
1896b0de25cbSAndy Fiddaman init_gdb(struct vmctx *_ctx)
18974c87aefeSPatrick Mooney {
1898b0de25cbSAndy Fiddaman 	int error, flags, optval, s;
1899b0de25cbSAndy Fiddaman 	struct addrinfo hints;
1900b0de25cbSAndy Fiddaman 	struct addrinfo *gdbaddr;
1901b0de25cbSAndy Fiddaman 	const char *saddr, *value;
1902b0de25cbSAndy Fiddaman 	char *sport;
1903b0de25cbSAndy Fiddaman 	bool wait;
19044c87aefeSPatrick Mooney 
1905b0de25cbSAndy Fiddaman 	value = get_config_value("gdb.port");
1906b0de25cbSAndy Fiddaman 	if (value == NULL)
1907b0de25cbSAndy Fiddaman 		return;
1908b0de25cbSAndy Fiddaman 	sport = strdup(value);
1909b0de25cbSAndy Fiddaman 	if (sport == NULL)
1910b0de25cbSAndy Fiddaman 		errx(4, "Failed to allocate memory");
1911b0de25cbSAndy Fiddaman 
1912b0de25cbSAndy Fiddaman 	wait = get_config_bool_default("gdb.wait", false);
1913b0de25cbSAndy Fiddaman 
1914b0de25cbSAndy Fiddaman 	saddr = get_config_value("gdb.address");
1915b0de25cbSAndy Fiddaman 	if (saddr == NULL) {
1916b0de25cbSAndy Fiddaman 		saddr = "localhost";
1917b0de25cbSAndy Fiddaman 	}
1918b0de25cbSAndy Fiddaman 
1919b0de25cbSAndy Fiddaman 	debug("==> starting on %s:%s, %swaiting\n",
1920b0de25cbSAndy Fiddaman 	    saddr, sport, wait ? "" : "not ");
19214c87aefeSPatrick Mooney 
19224c87aefeSPatrick Mooney 	error = pthread_mutex_init(&gdb_lock, NULL);
19234c87aefeSPatrick Mooney 	if (error != 0)
19244c87aefeSPatrick Mooney 		errc(1, error, "gdb mutex init");
19254c87aefeSPatrick Mooney 	error = pthread_cond_init(&idle_vcpus, NULL);
19264c87aefeSPatrick Mooney 	if (error != 0)
19274c87aefeSPatrick Mooney 		errc(1, error, "gdb cv init");
19284c87aefeSPatrick Mooney 
1929b0de25cbSAndy Fiddaman 	memset(&hints, 0, sizeof(hints));
1930b0de25cbSAndy Fiddaman 	hints.ai_family = AF_UNSPEC;
1931b0de25cbSAndy Fiddaman 	hints.ai_socktype = SOCK_STREAM;
1932b0de25cbSAndy Fiddaman 	hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE;
1933b0de25cbSAndy Fiddaman 
1934d7b72f7bSAndy Fiddaman 	error = getaddrinfo(saddr, sport, &hints, &gdbaddr);
1935d7b72f7bSAndy Fiddaman 	if (error != 0)
1936d7b72f7bSAndy Fiddaman 		errx(1, "gdb address resolution: %s", gai_strerror(error));
1937b0de25cbSAndy Fiddaman 
19384c87aefeSPatrick Mooney 	ctx = _ctx;
1939b0de25cbSAndy Fiddaman 	s = socket(gdbaddr->ai_family, gdbaddr->ai_socktype, 0);
19404c87aefeSPatrick Mooney 	if (s < 0)
19414c87aefeSPatrick Mooney 		err(1, "gdb socket create");
19424c87aefeSPatrick Mooney 
1943b0de25cbSAndy Fiddaman 	optval = 1;
1944b0de25cbSAndy Fiddaman 	(void)setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
19454c87aefeSPatrick Mooney 
1946b0de25cbSAndy Fiddaman 	if (bind(s, gdbaddr->ai_addr, gdbaddr->ai_addrlen) < 0)
19474c87aefeSPatrick Mooney 		err(1, "gdb socket bind");
19484c87aefeSPatrick Mooney 
19494c87aefeSPatrick Mooney 	if (listen(s, 1) < 0)
19504c87aefeSPatrick Mooney 		err(1, "gdb socket listen");
19514c87aefeSPatrick Mooney 
1952154972afSPatrick Mooney 	stopped_vcpu = -1;
1953154972afSPatrick Mooney 	TAILQ_INIT(&breakpoints);
1954154972afSPatrick Mooney 	vcpu_state = calloc(guest_ncpus, sizeof(*vcpu_state));
19554c87aefeSPatrick Mooney 	if (wait) {
19564c87aefeSPatrick Mooney 		/*
19574c87aefeSPatrick Mooney 		 * Set vcpu 0 in vcpus_suspended.  This will trigger the
19584c87aefeSPatrick Mooney 		 * logic in gdb_cpu_add() to suspend the first vcpu before
19594c87aefeSPatrick Mooney 		 * it starts execution.  The vcpu will remain suspended
19604c87aefeSPatrick Mooney 		 * until a debugger connects.
19614c87aefeSPatrick Mooney 		 */
19624c87aefeSPatrick Mooney 		CPU_SET(0, &vcpus_suspended);
1963154972afSPatrick Mooney 		stopped_vcpu = 0;
19644c87aefeSPatrick Mooney 	}
19654c87aefeSPatrick Mooney 
19664c87aefeSPatrick Mooney 	flags = fcntl(s, F_GETFL);
19674c87aefeSPatrick Mooney 	if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
19684c87aefeSPatrick Mooney 		err(1, "Failed to mark gdb socket non-blocking");
19694c87aefeSPatrick Mooney 
19704c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
19714c87aefeSPatrick Mooney 	limit_gdb_socket(s);
19724c87aefeSPatrick Mooney #endif
19734c87aefeSPatrick Mooney 	mevent_add(s, EVF_READ, new_connection, NULL);
19742b948146SAndy Fiddaman 	gdb_active = true;
1975b0de25cbSAndy Fiddaman 	freeaddrinfo(gdbaddr);
1976b0de25cbSAndy Fiddaman 	free(sport);
19774c87aefeSPatrick Mooney }
1978