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