1cd377eb3SJohn Baldwin /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3cd377eb3SJohn Baldwin *
4cd377eb3SJohn Baldwin * Copyright (c) 2017-2018 John H. Baldwin <jhb@FreeBSD.org>
5cd377eb3SJohn Baldwin *
6cd377eb3SJohn Baldwin * Redistribution and use in source and binary forms, with or without
7cd377eb3SJohn Baldwin * modification, are permitted provided that the following conditions
8cd377eb3SJohn Baldwin * are met:
9cd377eb3SJohn Baldwin * 1. Redistributions of source code must retain the above copyright
10cd377eb3SJohn Baldwin * notice, this list of conditions and the following disclaimer.
11cd377eb3SJohn Baldwin * 2. Redistributions in binary form must reproduce the above copyright
12cd377eb3SJohn Baldwin * notice, this list of conditions and the following disclaimer in the
13cd377eb3SJohn Baldwin * documentation and/or other materials provided with the distribution.
14cd377eb3SJohn Baldwin *
15cd377eb3SJohn Baldwin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16cd377eb3SJohn Baldwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17cd377eb3SJohn Baldwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18cd377eb3SJohn Baldwin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19cd377eb3SJohn Baldwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20cd377eb3SJohn Baldwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21cd377eb3SJohn Baldwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22cd377eb3SJohn Baldwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23cd377eb3SJohn Baldwin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24cd377eb3SJohn Baldwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25cd377eb3SJohn Baldwin * SUCH DAMAGE.
26cd377eb3SJohn Baldwin */
27cd377eb3SJohn Baldwin
28cd377eb3SJohn Baldwin #include <sys/param.h>
29cd377eb3SJohn Baldwin #ifndef WITHOUT_CAPSICUM
30cd377eb3SJohn Baldwin #include <sys/capsicum.h>
31cd377eb3SJohn Baldwin #endif
324db23c74SJohn Baldwin #include <sys/endian.h>
33cd377eb3SJohn Baldwin #include <sys/ioctl.h>
34cd377eb3SJohn Baldwin #include <sys/mman.h>
35cbd03a9dSJohn Baldwin #include <sys/queue.h>
36cd377eb3SJohn Baldwin #include <sys/socket.h>
37f81cdf24SMark Johnston #include <sys/stat.h>
38f81cdf24SMark Johnston
39a0ca4af9SMark Johnston #ifdef __aarch64__
40a0ca4af9SMark Johnston #include <machine/armreg.h>
41a0ca4af9SMark Johnston #endif
42cd377eb3SJohn Baldwin #include <machine/atomic.h>
43a0ca4af9SMark Johnston #ifdef __amd64__
44cd377eb3SJohn Baldwin #include <machine/specialreg.h>
45a0ca4af9SMark Johnston #endif
46cd377eb3SJohn Baldwin #include <machine/vmm.h>
47a0ca4af9SMark Johnston
48cd377eb3SJohn Baldwin #include <netinet/in.h>
49a0ca4af9SMark Johnston
50cd377eb3SJohn Baldwin #include <assert.h>
51cd377eb3SJohn Baldwin #ifndef WITHOUT_CAPSICUM
52cd377eb3SJohn Baldwin #include <capsicum_helpers.h>
53cd377eb3SJohn Baldwin #endif
54cd377eb3SJohn Baldwin #include <err.h>
55cd377eb3SJohn Baldwin #include <errno.h>
56cd377eb3SJohn Baldwin #include <fcntl.h>
572cdff991SMariusz Zaborski #include <netdb.h>
58cd377eb3SJohn Baldwin #include <pthread.h>
59cd377eb3SJohn Baldwin #include <pthread_np.h>
60cd377eb3SJohn Baldwin #include <stdbool.h>
61cd377eb3SJohn Baldwin #include <stdio.h>
62cd377eb3SJohn Baldwin #include <stdlib.h>
63cd377eb3SJohn Baldwin #include <string.h>
64cd377eb3SJohn Baldwin #include <sysexits.h>
65cd377eb3SJohn Baldwin #include <unistd.h>
66cd377eb3SJohn Baldwin #include <vmmapi.h>
67cd377eb3SJohn Baldwin
68cd377eb3SJohn Baldwin #include "bhyverun.h"
692cdff991SMariusz Zaborski #include "config.h"
70b0936440SJohn Baldwin #include "debug.h"
71cbd03a9dSJohn Baldwin #include "gdb.h"
72cd377eb3SJohn Baldwin #include "mem.h"
73cd377eb3SJohn Baldwin #include "mevent.h"
74cd377eb3SJohn Baldwin
75f81cdf24SMark Johnston #define _PATH_GDB_XML "/usr/share/bhyve/gdb"
76f81cdf24SMark Johnston
77cd377eb3SJohn Baldwin /*
78cd377eb3SJohn Baldwin * GDB_SIGNAL_* numbers are part of the GDB remote protocol. Most stops
79cd377eb3SJohn Baldwin * use SIGTRAP.
80cd377eb3SJohn Baldwin */
81cd377eb3SJohn Baldwin #define GDB_SIGNAL_TRAP 5
82cd377eb3SJohn Baldwin
83a0ca4af9SMark Johnston #if defined(__amd64__)
845f086566SMark Johnston #define GDB_BP_SIZE 1
855f086566SMark Johnston #define GDB_BP_INSTR (uint8_t []){0xcc}
865f086566SMark Johnston #define GDB_PC_REGNAME VM_REG_GUEST_RIP
87a0ca4af9SMark Johnston #define GDB_BREAKPOINT_CAP VM_CAP_BPT_EXIT
88a0ca4af9SMark Johnston #elif defined(__aarch64__)
89a0ca4af9SMark Johnston #define GDB_BP_SIZE 4
90a0ca4af9SMark Johnston #define GDB_BP_INSTR (uint8_t []){0x00, 0x00, 0x20, 0xd4}
91a0ca4af9SMark Johnston #define GDB_PC_REGNAME VM_REG_GUEST_PC
92a0ca4af9SMark Johnston #define GDB_BREAKPOINT_CAP VM_CAP_BRK_EXIT
93a0ca4af9SMark Johnston #else
94a0ca4af9SMark Johnston #error "Unsupported architecture"
95a0ca4af9SMark Johnston #endif
965f086566SMark Johnston
975f086566SMark Johnston _Static_assert(sizeof(GDB_BP_INSTR) == GDB_BP_SIZE,
985f086566SMark Johnston "GDB_BP_INSTR has wrong size");
995f086566SMark Johnston
100cd377eb3SJohn Baldwin static void gdb_resume_vcpus(void);
101cd377eb3SJohn Baldwin static void check_command(int fd);
102cd377eb3SJohn Baldwin
103cd377eb3SJohn Baldwin static struct mevent *read_event, *write_event;
104cd377eb3SJohn Baldwin
105cd377eb3SJohn Baldwin static cpuset_t vcpus_active, vcpus_suspended, vcpus_waiting;
106cd377eb3SJohn Baldwin static pthread_mutex_t gdb_lock;
107cd377eb3SJohn Baldwin static pthread_cond_t idle_vcpus;
108cbd03a9dSJohn Baldwin static bool first_stop, report_next_stop, swbreak_enabled;
109f81cdf24SMark Johnston static int xml_dfd = -1;
110cd377eb3SJohn Baldwin
111cd377eb3SJohn Baldwin /*
112cd377eb3SJohn Baldwin * An I/O buffer contains 'capacity' bytes of room at 'data'. For a
113cd377eb3SJohn Baldwin * read buffer, 'start' is unused and 'len' contains the number of
114cd377eb3SJohn Baldwin * valid bytes in the buffer. For a write buffer, 'start' is set to
115cd377eb3SJohn Baldwin * the index of the next byte in 'data' to send, and 'len' contains
116cd377eb3SJohn Baldwin * the remaining number of valid bytes to send.
117cd377eb3SJohn Baldwin */
118cd377eb3SJohn Baldwin struct io_buffer {
119cd377eb3SJohn Baldwin uint8_t *data;
120cd377eb3SJohn Baldwin size_t capacity;
121cd377eb3SJohn Baldwin size_t start;
122cd377eb3SJohn Baldwin size_t len;
123cd377eb3SJohn Baldwin };
124cd377eb3SJohn Baldwin
125cbd03a9dSJohn Baldwin struct breakpoint {
126cbd03a9dSJohn Baldwin uint64_t gpa;
1275f086566SMark Johnston uint8_t shadow_inst[GDB_BP_SIZE];
128cbd03a9dSJohn Baldwin TAILQ_ENTRY(breakpoint) link;
129cbd03a9dSJohn Baldwin };
130cbd03a9dSJohn Baldwin
131cbd03a9dSJohn Baldwin /*
132cbd03a9dSJohn Baldwin * When a vCPU stops to due to an event that should be reported to the
133cbd03a9dSJohn Baldwin * debugger, information about the event is stored in this structure.
134cbd03a9dSJohn Baldwin * The vCPU thread then sets 'stopped_vcpu' if it is not already set
135cbd03a9dSJohn Baldwin * and stops other vCPUs so the event can be reported. The
136cbd03a9dSJohn Baldwin * report_stop() function reports the event for the 'stopped_vcpu'
137cbd03a9dSJohn Baldwin * vCPU. When the debugger resumes execution via continue or step,
138cbd03a9dSJohn Baldwin * the event for 'stopped_vcpu' is cleared. vCPUs will loop in their
139cbd03a9dSJohn Baldwin * event handlers until the associated event is reported or disabled.
140cbd03a9dSJohn Baldwin *
141cbd03a9dSJohn Baldwin * An idle vCPU will have all of the boolean fields set to false.
142cbd03a9dSJohn Baldwin *
143cbd03a9dSJohn Baldwin * When a vCPU is stepped, 'stepping' is set to true when the vCPU is
144cbd03a9dSJohn Baldwin * released to execute the stepped instruction. When the vCPU reports
145cbd03a9dSJohn Baldwin * the stepping trap, 'stepped' is set.
146cbd03a9dSJohn Baldwin *
147cbd03a9dSJohn Baldwin * When a vCPU hits a breakpoint set by the debug server,
148cbd03a9dSJohn Baldwin * 'hit_swbreak' is set to true.
149cbd03a9dSJohn Baldwin */
150cbd03a9dSJohn Baldwin struct vcpu_state {
151cbd03a9dSJohn Baldwin bool stepping;
152cbd03a9dSJohn Baldwin bool stepped;
153cbd03a9dSJohn Baldwin bool hit_swbreak;
154cbd03a9dSJohn Baldwin };
155cbd03a9dSJohn Baldwin
156cd377eb3SJohn Baldwin static struct io_buffer cur_comm, cur_resp;
157cd377eb3SJohn Baldwin static uint8_t cur_csum;
158cd377eb3SJohn Baldwin static struct vmctx *ctx;
159cd377eb3SJohn Baldwin static int cur_fd = -1;
160cbd03a9dSJohn Baldwin static TAILQ_HEAD(, breakpoint) breakpoints;
161cbd03a9dSJohn Baldwin static struct vcpu_state *vcpu_state;
1627d9ef309SJohn Baldwin static struct vcpu **vcpus;
163cbd03a9dSJohn Baldwin static int cur_vcpu, stopped_vcpu;
164621b5090SJohn Baldwin static bool gdb_active = false;
165cd377eb3SJohn Baldwin
166a0ca4af9SMark Johnston struct gdb_reg {
1675e728af4SMark Johnston enum vm_reg_name id;
1685e728af4SMark Johnston int size;
1699a4813e1SAndrew Turner };
170a0ca4af9SMark Johnston
171a0ca4af9SMark Johnston #ifdef __amd64__
1729a4813e1SAndrew Turner static const struct gdb_reg gdb_regset[] = {
1735e728af4SMark Johnston { .id = VM_REG_GUEST_RAX, .size = 8 },
1745e728af4SMark Johnston { .id = VM_REG_GUEST_RBX, .size = 8 },
1755e728af4SMark Johnston { .id = VM_REG_GUEST_RCX, .size = 8 },
1765e728af4SMark Johnston { .id = VM_REG_GUEST_RDX, .size = 8 },
1775e728af4SMark Johnston { .id = VM_REG_GUEST_RSI, .size = 8 },
1785e728af4SMark Johnston { .id = VM_REG_GUEST_RDI, .size = 8 },
1795e728af4SMark Johnston { .id = VM_REG_GUEST_RBP, .size = 8 },
1805e728af4SMark Johnston { .id = VM_REG_GUEST_RSP, .size = 8 },
1815e728af4SMark Johnston { .id = VM_REG_GUEST_R8, .size = 8 },
1825e728af4SMark Johnston { .id = VM_REG_GUEST_R9, .size = 8 },
1835e728af4SMark Johnston { .id = VM_REG_GUEST_R10, .size = 8 },
1845e728af4SMark Johnston { .id = VM_REG_GUEST_R11, .size = 8 },
1855e728af4SMark Johnston { .id = VM_REG_GUEST_R12, .size = 8 },
1865e728af4SMark Johnston { .id = VM_REG_GUEST_R13, .size = 8 },
1875e728af4SMark Johnston { .id = VM_REG_GUEST_R14, .size = 8 },
1885e728af4SMark Johnston { .id = VM_REG_GUEST_R15, .size = 8 },
1895e728af4SMark Johnston { .id = VM_REG_GUEST_RIP, .size = 8 },
1905e728af4SMark Johnston { .id = VM_REG_GUEST_RFLAGS, .size = 4 },
1915e728af4SMark Johnston { .id = VM_REG_GUEST_CS, .size = 4 },
1925e728af4SMark Johnston { .id = VM_REG_GUEST_SS, .size = 4 },
1935e728af4SMark Johnston { .id = VM_REG_GUEST_DS, .size = 4 },
1945e728af4SMark Johnston { .id = VM_REG_GUEST_ES, .size = 4 },
1955e728af4SMark Johnston { .id = VM_REG_GUEST_FS, .size = 4 },
1965e728af4SMark Johnston { .id = VM_REG_GUEST_GS, .size = 4 },
197f81cdf24SMark Johnston /*
198f81cdf24SMark Johnston * Registers past this point are not included in a reply to a 'g' query,
199f81cdf24SMark Johnston * to provide compatibility with debuggers that do not fetch a target
200f81cdf24SMark Johnston * description. The debugger can query them individually with 'p' if it
201f81cdf24SMark Johnston * knows about them.
202f81cdf24SMark Johnston */
203f81cdf24SMark Johnston #define GDB_REG_FIRST_EXT VM_REG_GUEST_FS_BASE
204f81cdf24SMark Johnston { .id = VM_REG_GUEST_FS_BASE, .size = 8 },
205f81cdf24SMark Johnston { .id = VM_REG_GUEST_GS_BASE, .size = 8 },
206f81cdf24SMark Johnston { .id = VM_REG_GUEST_KGS_BASE, .size = 8 },
207f81cdf24SMark Johnston { .id = VM_REG_GUEST_CR0, .size = 8 },
208f81cdf24SMark Johnston { .id = VM_REG_GUEST_CR2, .size = 8 },
209f81cdf24SMark Johnston { .id = VM_REG_GUEST_CR3, .size = 8 },
210f81cdf24SMark Johnston { .id = VM_REG_GUEST_CR4, .size = 8 },
211f81cdf24SMark Johnston { .id = VM_REG_GUEST_TPR, .size = 8 },
212f81cdf24SMark Johnston { .id = VM_REG_GUEST_EFER, .size = 8 },
213cd377eb3SJohn Baldwin };
214a0ca4af9SMark Johnston #else /* __aarch64__ */
2159a4813e1SAndrew Turner static const struct gdb_reg gdb_regset[] = {
216a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X0, .size = 8 },
217a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X1, .size = 8 },
218a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X2, .size = 8 },
219a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X3, .size = 8 },
220a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X4, .size = 8 },
221a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X5, .size = 8 },
222a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X6, .size = 8 },
223a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X7, .size = 8 },
224a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X8, .size = 8 },
225a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X9, .size = 8 },
226a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X10, .size = 8 },
227a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X11, .size = 8 },
228a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X12, .size = 8 },
229a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X13, .size = 8 },
230a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X14, .size = 8 },
231a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X15, .size = 8 },
232a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X16, .size = 8 },
233a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X17, .size = 8 },
234a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X18, .size = 8 },
235a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X19, .size = 8 },
236a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X20, .size = 8 },
237a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X21, .size = 8 },
238a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X22, .size = 8 },
239a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X23, .size = 8 },
240a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X24, .size = 8 },
241a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X25, .size = 8 },
242a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X26, .size = 8 },
243a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X27, .size = 8 },
244a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X28, .size = 8 },
245a0ca4af9SMark Johnston { .id = VM_REG_GUEST_X29, .size = 8 },
246a0ca4af9SMark Johnston { .id = VM_REG_GUEST_LR, .size = 8 },
247a0ca4af9SMark Johnston { .id = VM_REG_GUEST_SP, .size = 8 },
248a0ca4af9SMark Johnston { .id = VM_REG_GUEST_PC, .size = 8 },
249a0ca4af9SMark Johnston { .id = VM_REG_GUEST_CPSR, .size = 8 },
250a0ca4af9SMark Johnston };
251a0ca4af9SMark Johnston #endif
252cd377eb3SJohn Baldwin
253cd377eb3SJohn Baldwin #ifdef GDB_LOG
254cd377eb3SJohn Baldwin #include <stdarg.h>
255cd377eb3SJohn Baldwin #include <stdio.h>
256cd377eb3SJohn Baldwin
257cd377eb3SJohn Baldwin static void __printflike(1, 2)
debug(const char * fmt,...)258cd377eb3SJohn Baldwin debug(const char *fmt, ...)
259cd377eb3SJohn Baldwin {
260cd377eb3SJohn Baldwin static FILE *logfile;
261cd377eb3SJohn Baldwin va_list ap;
262cd377eb3SJohn Baldwin
263cd377eb3SJohn Baldwin if (logfile == NULL) {
264cd377eb3SJohn Baldwin logfile = fopen("/tmp/bhyve_gdb.log", "w");
265cd377eb3SJohn Baldwin if (logfile == NULL)
266cd377eb3SJohn Baldwin return;
267cd377eb3SJohn Baldwin #ifndef WITHOUT_CAPSICUM
268cd377eb3SJohn Baldwin if (caph_limit_stream(fileno(logfile), CAPH_WRITE) == -1) {
269cd377eb3SJohn Baldwin fclose(logfile);
270cd377eb3SJohn Baldwin logfile = NULL;
271cd377eb3SJohn Baldwin return;
272cd377eb3SJohn Baldwin }
273cd377eb3SJohn Baldwin #endif
274cd377eb3SJohn Baldwin setlinebuf(logfile);
275cd377eb3SJohn Baldwin }
276cd377eb3SJohn Baldwin va_start(ap, fmt);
277cd377eb3SJohn Baldwin vfprintf(logfile, fmt, ap);
278cd377eb3SJohn Baldwin va_end(ap);
279cd377eb3SJohn Baldwin }
280cd377eb3SJohn Baldwin #else
281cd377eb3SJohn Baldwin #define debug(...)
282cd377eb3SJohn Baldwin #endif
283cd377eb3SJohn Baldwin
284cbd03a9dSJohn Baldwin static void remove_all_sw_breakpoints(void);
285cbd03a9dSJohn Baldwin
286cd377eb3SJohn Baldwin static int
guest_paging_info(struct vcpu * vcpu,struct vm_guest_paging * paging)2877d9ef309SJohn Baldwin guest_paging_info(struct vcpu *vcpu, struct vm_guest_paging *paging)
288cd377eb3SJohn Baldwin {
289a0ca4af9SMark Johnston #ifdef __amd64__
290cd377eb3SJohn Baldwin uint64_t regs[4];
291cd377eb3SJohn Baldwin const int regset[4] = {
292cd377eb3SJohn Baldwin VM_REG_GUEST_CR0,
293cd377eb3SJohn Baldwin VM_REG_GUEST_CR3,
294cd377eb3SJohn Baldwin VM_REG_GUEST_CR4,
295cd377eb3SJohn Baldwin VM_REG_GUEST_EFER
296cd377eb3SJohn Baldwin };
297cd377eb3SJohn Baldwin
2987d9ef309SJohn Baldwin if (vm_get_register_set(vcpu, nitems(regset), regset, regs) == -1)
299cd377eb3SJohn Baldwin return (-1);
300cd377eb3SJohn Baldwin
301cd377eb3SJohn Baldwin /*
302cd377eb3SJohn Baldwin * For the debugger, always pretend to be the kernel (CPL 0),
303cd377eb3SJohn Baldwin * and if long-mode is enabled, always parse addresses as if
304cd377eb3SJohn Baldwin * in 64-bit mode.
305cd377eb3SJohn Baldwin */
306cd377eb3SJohn Baldwin paging->cr3 = regs[1];
307cd377eb3SJohn Baldwin paging->cpl = 0;
308cd377eb3SJohn Baldwin if (regs[3] & EFER_LMA)
309cd377eb3SJohn Baldwin paging->cpu_mode = CPU_MODE_64BIT;
310cd377eb3SJohn Baldwin else if (regs[0] & CR0_PE)
311cd377eb3SJohn Baldwin paging->cpu_mode = CPU_MODE_PROTECTED;
312cd377eb3SJohn Baldwin else
313cd377eb3SJohn Baldwin paging->cpu_mode = CPU_MODE_REAL;
314cd377eb3SJohn Baldwin if (!(regs[0] & CR0_PG))
315cd377eb3SJohn Baldwin paging->paging_mode = PAGING_MODE_FLAT;
316cd377eb3SJohn Baldwin else if (!(regs[2] & CR4_PAE))
317cd377eb3SJohn Baldwin paging->paging_mode = PAGING_MODE_32;
318cd377eb3SJohn Baldwin else if (regs[3] & EFER_LME)
319f3eb12e4SKonstantin Belousov paging->paging_mode = (regs[2] & CR4_LA57) ?
320f3eb12e4SKonstantin Belousov PAGING_MODE_64_LA57 : PAGING_MODE_64;
321cd377eb3SJohn Baldwin else
322cd377eb3SJohn Baldwin paging->paging_mode = PAGING_MODE_PAE;
323cd377eb3SJohn Baldwin return (0);
324a0ca4af9SMark Johnston #else /* __aarch64__ */
325a0ca4af9SMark Johnston uint64_t regs[6];
326a0ca4af9SMark Johnston const int regset[6] = {
327a0ca4af9SMark Johnston VM_REG_GUEST_TTBR0_EL1,
328a0ca4af9SMark Johnston VM_REG_GUEST_TTBR1_EL1,
329a0ca4af9SMark Johnston VM_REG_GUEST_TCR_EL1,
330a0ca4af9SMark Johnston VM_REG_GUEST_TCR2_EL1,
331a0ca4af9SMark Johnston VM_REG_GUEST_SCTLR_EL1,
332a0ca4af9SMark Johnston VM_REG_GUEST_CPSR,
333a0ca4af9SMark Johnston };
334a0ca4af9SMark Johnston
335a0ca4af9SMark Johnston if (vm_get_register_set(vcpu, nitems(regset), regset, regs) == -1)
336a0ca4af9SMark Johnston return (-1);
337a0ca4af9SMark Johnston
338a0ca4af9SMark Johnston memset(paging, 0, sizeof(*paging));
339a0ca4af9SMark Johnston paging->ttbr0_addr = regs[0] & ~(TTBR_ASID_MASK | TTBR_CnP);
340a0ca4af9SMark Johnston paging->ttbr1_addr = regs[1] & ~(TTBR_ASID_MASK | TTBR_CnP);
341a0ca4af9SMark Johnston paging->tcr_el1 = regs[2];
342a0ca4af9SMark Johnston paging->tcr2_el1 = regs[3];
343a0ca4af9SMark Johnston paging->flags = regs[5] & (PSR_M_MASK | PSR_M_32);
344a0ca4af9SMark Johnston if ((regs[4] & SCTLR_M) != 0)
345a0ca4af9SMark Johnston paging->flags |= VM_GP_MMU_ENABLED;
346a0ca4af9SMark Johnston
347a0ca4af9SMark Johnston return (0);
348a0ca4af9SMark Johnston #endif /* __aarch64__ */
349cd377eb3SJohn Baldwin }
350cd377eb3SJohn Baldwin
351cd377eb3SJohn Baldwin /*
352cd377eb3SJohn Baldwin * Map a guest virtual address to a physical address (for a given vcpu).
353cd377eb3SJohn Baldwin * If a guest virtual address is valid, return 1. If the address is
354cd377eb3SJohn Baldwin * not valid, return 0. If an error occurs obtaining the mapping,
355cd377eb3SJohn Baldwin * return -1.
356cd377eb3SJohn Baldwin */
357cd377eb3SJohn Baldwin static int
guest_vaddr2paddr(struct vcpu * vcpu,uint64_t vaddr,uint64_t * paddr)3587d9ef309SJohn Baldwin guest_vaddr2paddr(struct vcpu *vcpu, uint64_t vaddr, uint64_t *paddr)
359cd377eb3SJohn Baldwin {
360cd377eb3SJohn Baldwin struct vm_guest_paging paging;
361cd377eb3SJohn Baldwin int fault;
362cd377eb3SJohn Baldwin
363cd377eb3SJohn Baldwin if (guest_paging_info(vcpu, &paging) == -1)
364cd377eb3SJohn Baldwin return (-1);
365cd377eb3SJohn Baldwin
366cd377eb3SJohn Baldwin /*
367cd377eb3SJohn Baldwin * Always use PROT_READ. We really care if the VA is
368cd377eb3SJohn Baldwin * accessible, not if the current vCPU can write.
369cd377eb3SJohn Baldwin */
3707d9ef309SJohn Baldwin if (vm_gla2gpa_nofault(vcpu, &paging, vaddr, PROT_READ, paddr,
371cd377eb3SJohn Baldwin &fault) == -1)
372cd377eb3SJohn Baldwin return (-1);
373cd377eb3SJohn Baldwin if (fault)
374cd377eb3SJohn Baldwin return (0);
375cd377eb3SJohn Baldwin return (1);
376cd377eb3SJohn Baldwin }
377cd377eb3SJohn Baldwin
3785f086566SMark Johnston static uint64_t
guest_pc(struct vm_exit * vme)3795f086566SMark Johnston guest_pc(struct vm_exit *vme)
3805f086566SMark Johnston {
381a0ca4af9SMark Johnston #ifdef __amd64__
3825f086566SMark Johnston return (vme->rip);
383a0ca4af9SMark Johnston #else /* __aarch64__ */
384a0ca4af9SMark Johnston return (vme->pc);
385a0ca4af9SMark Johnston #endif
3865f086566SMark Johnston }
3875f086566SMark Johnston
388cd377eb3SJohn Baldwin static void
io_buffer_reset(struct io_buffer * io)389cd377eb3SJohn Baldwin io_buffer_reset(struct io_buffer *io)
390cd377eb3SJohn Baldwin {
391cd377eb3SJohn Baldwin
392cd377eb3SJohn Baldwin io->start = 0;
393cd377eb3SJohn Baldwin io->len = 0;
394cd377eb3SJohn Baldwin }
395cd377eb3SJohn Baldwin
396cd377eb3SJohn Baldwin /* Available room for adding data. */
397cd377eb3SJohn Baldwin static size_t
io_buffer_avail(struct io_buffer * io)398cd377eb3SJohn Baldwin io_buffer_avail(struct io_buffer *io)
399cd377eb3SJohn Baldwin {
400cd377eb3SJohn Baldwin
401cd377eb3SJohn Baldwin return (io->capacity - (io->start + io->len));
402cd377eb3SJohn Baldwin }
403cd377eb3SJohn Baldwin
404cd377eb3SJohn Baldwin static uint8_t *
io_buffer_head(struct io_buffer * io)405cd377eb3SJohn Baldwin io_buffer_head(struct io_buffer *io)
406cd377eb3SJohn Baldwin {
407cd377eb3SJohn Baldwin
408cd377eb3SJohn Baldwin return (io->data + io->start);
409cd377eb3SJohn Baldwin }
410cd377eb3SJohn Baldwin
411cd377eb3SJohn Baldwin static uint8_t *
io_buffer_tail(struct io_buffer * io)412cd377eb3SJohn Baldwin io_buffer_tail(struct io_buffer *io)
413cd377eb3SJohn Baldwin {
414cd377eb3SJohn Baldwin
415cd377eb3SJohn Baldwin return (io->data + io->start + io->len);
416cd377eb3SJohn Baldwin }
417cd377eb3SJohn Baldwin
418cd377eb3SJohn Baldwin static void
io_buffer_advance(struct io_buffer * io,size_t amount)419cd377eb3SJohn Baldwin io_buffer_advance(struct io_buffer *io, size_t amount)
420cd377eb3SJohn Baldwin {
421cd377eb3SJohn Baldwin
422cd377eb3SJohn Baldwin assert(amount <= io->len);
423cd377eb3SJohn Baldwin io->start += amount;
424cd377eb3SJohn Baldwin io->len -= amount;
425cd377eb3SJohn Baldwin }
426cd377eb3SJohn Baldwin
427cd377eb3SJohn Baldwin static void
io_buffer_consume(struct io_buffer * io,size_t amount)428cd377eb3SJohn Baldwin io_buffer_consume(struct io_buffer *io, size_t amount)
429cd377eb3SJohn Baldwin {
430cd377eb3SJohn Baldwin
431cd377eb3SJohn Baldwin io_buffer_advance(io, amount);
432cd377eb3SJohn Baldwin if (io->len == 0) {
433cd377eb3SJohn Baldwin io->start = 0;
434cd377eb3SJohn Baldwin return;
435cd377eb3SJohn Baldwin }
436cd377eb3SJohn Baldwin
437cd377eb3SJohn Baldwin /*
438cd377eb3SJohn Baldwin * XXX: Consider making this move optional and compacting on a
439cd377eb3SJohn Baldwin * future read() before realloc().
440cd377eb3SJohn Baldwin */
441cd377eb3SJohn Baldwin memmove(io->data, io_buffer_head(io), io->len);
442cd377eb3SJohn Baldwin io->start = 0;
443cd377eb3SJohn Baldwin }
444cd377eb3SJohn Baldwin
445cd377eb3SJohn Baldwin static void
io_buffer_grow(struct io_buffer * io,size_t newsize)446cd377eb3SJohn Baldwin io_buffer_grow(struct io_buffer *io, size_t newsize)
447cd377eb3SJohn Baldwin {
448cd377eb3SJohn Baldwin uint8_t *new_data;
449cd377eb3SJohn Baldwin size_t avail, new_cap;
450cd377eb3SJohn Baldwin
451cd377eb3SJohn Baldwin avail = io_buffer_avail(io);
452cd377eb3SJohn Baldwin if (newsize <= avail)
453cd377eb3SJohn Baldwin return;
454cd377eb3SJohn Baldwin
455cd377eb3SJohn Baldwin new_cap = io->capacity + (newsize - avail);
456cd377eb3SJohn Baldwin new_data = realloc(io->data, new_cap);
457cd377eb3SJohn Baldwin if (new_data == NULL)
458cd377eb3SJohn Baldwin err(1, "Failed to grow GDB I/O buffer");
459cd377eb3SJohn Baldwin io->data = new_data;
460cd377eb3SJohn Baldwin io->capacity = new_cap;
461cd377eb3SJohn Baldwin }
462cd377eb3SJohn Baldwin
463cd377eb3SJohn Baldwin static bool
response_pending(void)464cd377eb3SJohn Baldwin response_pending(void)
465cd377eb3SJohn Baldwin {
466cd377eb3SJohn Baldwin
467cd377eb3SJohn Baldwin if (cur_resp.start == 0 && cur_resp.len == 0)
468cd377eb3SJohn Baldwin return (false);
469cd377eb3SJohn Baldwin if (cur_resp.start + cur_resp.len == 1 && cur_resp.data[0] == '+')
470cd377eb3SJohn Baldwin return (false);
471cd377eb3SJohn Baldwin return (true);
472cd377eb3SJohn Baldwin }
473cd377eb3SJohn Baldwin
474cd377eb3SJohn Baldwin static void
close_connection(void)475cd377eb3SJohn Baldwin close_connection(void)
476cd377eb3SJohn Baldwin {
477cd377eb3SJohn Baldwin
478cd377eb3SJohn Baldwin /*
479cd377eb3SJohn Baldwin * XXX: This triggers a warning because mevent does the close
480cd377eb3SJohn Baldwin * before the EV_DELETE.
481cd377eb3SJohn Baldwin */
482cd377eb3SJohn Baldwin pthread_mutex_lock(&gdb_lock);
483cd377eb3SJohn Baldwin mevent_delete(write_event);
484cd377eb3SJohn Baldwin mevent_delete_close(read_event);
485cd377eb3SJohn Baldwin write_event = NULL;
486cd377eb3SJohn Baldwin read_event = NULL;
487cd377eb3SJohn Baldwin io_buffer_reset(&cur_comm);
488cd377eb3SJohn Baldwin io_buffer_reset(&cur_resp);
489cd377eb3SJohn Baldwin cur_fd = -1;
490cd377eb3SJohn Baldwin
491cbd03a9dSJohn Baldwin remove_all_sw_breakpoints();
492cbd03a9dSJohn Baldwin
493cbd03a9dSJohn Baldwin /* Clear any pending events. */
494cbd03a9dSJohn Baldwin memset(vcpu_state, 0, guest_ncpus * sizeof(*vcpu_state));
495cbd03a9dSJohn Baldwin
496cd377eb3SJohn Baldwin /* Resume any stopped vCPUs. */
497cd377eb3SJohn Baldwin gdb_resume_vcpus();
498cd377eb3SJohn Baldwin pthread_mutex_unlock(&gdb_lock);
499cd377eb3SJohn Baldwin }
500cd377eb3SJohn Baldwin
501cd377eb3SJohn Baldwin static uint8_t
hex_digit(uint8_t nibble)502cd377eb3SJohn Baldwin hex_digit(uint8_t nibble)
503cd377eb3SJohn Baldwin {
504cd377eb3SJohn Baldwin
505cd377eb3SJohn Baldwin if (nibble <= 9)
506cd377eb3SJohn Baldwin return (nibble + '0');
507cd377eb3SJohn Baldwin else
508cd377eb3SJohn Baldwin return (nibble + 'a' - 10);
509cd377eb3SJohn Baldwin }
510cd377eb3SJohn Baldwin
511cd377eb3SJohn Baldwin static uint8_t
parse_digit(uint8_t v)512cd377eb3SJohn Baldwin parse_digit(uint8_t v)
513cd377eb3SJohn Baldwin {
514cd377eb3SJohn Baldwin
515cd377eb3SJohn Baldwin if (v >= '0' && v <= '9')
516cd377eb3SJohn Baldwin return (v - '0');
517cd377eb3SJohn Baldwin if (v >= 'a' && v <= 'f')
518cd377eb3SJohn Baldwin return (v - 'a' + 10);
519cd377eb3SJohn Baldwin if (v >= 'A' && v <= 'F')
520cd377eb3SJohn Baldwin return (v - 'A' + 10);
521cd377eb3SJohn Baldwin return (0xF);
522cd377eb3SJohn Baldwin }
523cd377eb3SJohn Baldwin
524cd377eb3SJohn Baldwin /* Parses big-endian hexadecimal. */
525cd377eb3SJohn Baldwin static uintmax_t
parse_integer(const uint8_t * p,size_t len)526cd377eb3SJohn Baldwin parse_integer(const uint8_t *p, size_t len)
527cd377eb3SJohn Baldwin {
528cd377eb3SJohn Baldwin uintmax_t v;
529cd377eb3SJohn Baldwin
530cd377eb3SJohn Baldwin v = 0;
531cd377eb3SJohn Baldwin while (len > 0) {
532cd377eb3SJohn Baldwin v <<= 4;
533cd377eb3SJohn Baldwin v |= parse_digit(*p);
534cd377eb3SJohn Baldwin p++;
535cd377eb3SJohn Baldwin len--;
536cd377eb3SJohn Baldwin }
537cd377eb3SJohn Baldwin return (v);
538cd377eb3SJohn Baldwin }
539cd377eb3SJohn Baldwin
540cd377eb3SJohn Baldwin static uint8_t
parse_byte(const uint8_t * p)541cd377eb3SJohn Baldwin parse_byte(const uint8_t *p)
542cd377eb3SJohn Baldwin {
543cd377eb3SJohn Baldwin
544cd377eb3SJohn Baldwin return (parse_digit(p[0]) << 4 | parse_digit(p[1]));
545cd377eb3SJohn Baldwin }
546cd377eb3SJohn Baldwin
547cd377eb3SJohn Baldwin static void
send_pending_data(int fd)548cd377eb3SJohn Baldwin send_pending_data(int fd)
549cd377eb3SJohn Baldwin {
550cd377eb3SJohn Baldwin ssize_t nwritten;
551cd377eb3SJohn Baldwin
552cd377eb3SJohn Baldwin if (cur_resp.len == 0) {
553cd377eb3SJohn Baldwin mevent_disable(write_event);
554cd377eb3SJohn Baldwin return;
555cd377eb3SJohn Baldwin }
556cd377eb3SJohn Baldwin nwritten = write(fd, io_buffer_head(&cur_resp), cur_resp.len);
557cd377eb3SJohn Baldwin if (nwritten == -1) {
558cd377eb3SJohn Baldwin warn("Write to GDB socket failed");
559cd377eb3SJohn Baldwin close_connection();
560cd377eb3SJohn Baldwin } else {
561cd377eb3SJohn Baldwin io_buffer_advance(&cur_resp, nwritten);
562cd377eb3SJohn Baldwin if (cur_resp.len == 0)
563cd377eb3SJohn Baldwin mevent_disable(write_event);
564cd377eb3SJohn Baldwin else
565cd377eb3SJohn Baldwin mevent_enable(write_event);
566cd377eb3SJohn Baldwin }
567cd377eb3SJohn Baldwin }
568cd377eb3SJohn Baldwin
569cd377eb3SJohn Baldwin /* Append a single character to the output buffer. */
570cd377eb3SJohn Baldwin static void
send_char(uint8_t data)571cd377eb3SJohn Baldwin send_char(uint8_t data)
572cd377eb3SJohn Baldwin {
573cd377eb3SJohn Baldwin io_buffer_grow(&cur_resp, 1);
574cd377eb3SJohn Baldwin *io_buffer_tail(&cur_resp) = data;
575cd377eb3SJohn Baldwin cur_resp.len++;
576cd377eb3SJohn Baldwin }
577cd377eb3SJohn Baldwin
578cd377eb3SJohn Baldwin /* Append an array of bytes to the output buffer. */
579cd377eb3SJohn Baldwin static void
send_data(const uint8_t * data,size_t len)580cd377eb3SJohn Baldwin send_data(const uint8_t *data, size_t len)
581cd377eb3SJohn Baldwin {
582cd377eb3SJohn Baldwin
583cd377eb3SJohn Baldwin io_buffer_grow(&cur_resp, len);
584cd377eb3SJohn Baldwin memcpy(io_buffer_tail(&cur_resp), data, len);
585cd377eb3SJohn Baldwin cur_resp.len += len;
586cd377eb3SJohn Baldwin }
587cd377eb3SJohn Baldwin
588cd377eb3SJohn Baldwin static void
format_byte(uint8_t v,uint8_t * buf)589cd377eb3SJohn Baldwin format_byte(uint8_t v, uint8_t *buf)
590cd377eb3SJohn Baldwin {
591cd377eb3SJohn Baldwin
592cd377eb3SJohn Baldwin buf[0] = hex_digit(v >> 4);
593cd377eb3SJohn Baldwin buf[1] = hex_digit(v & 0xf);
594cd377eb3SJohn Baldwin }
595cd377eb3SJohn Baldwin
596cd377eb3SJohn Baldwin /*
597cd377eb3SJohn Baldwin * Append a single byte (formatted as two hex characters) to the
598cd377eb3SJohn Baldwin * output buffer.
599cd377eb3SJohn Baldwin */
600cd377eb3SJohn Baldwin static void
send_byte(uint8_t v)601cd377eb3SJohn Baldwin send_byte(uint8_t v)
602cd377eb3SJohn Baldwin {
603cd377eb3SJohn Baldwin uint8_t buf[2];
604cd377eb3SJohn Baldwin
605cd377eb3SJohn Baldwin format_byte(v, buf);
606cd377eb3SJohn Baldwin send_data(buf, sizeof(buf));
607cd377eb3SJohn Baldwin }
608cd377eb3SJohn Baldwin
609cd377eb3SJohn Baldwin static void
start_packet(void)610cd377eb3SJohn Baldwin start_packet(void)
611cd377eb3SJohn Baldwin {
612cd377eb3SJohn Baldwin
613cd377eb3SJohn Baldwin send_char('$');
614cd377eb3SJohn Baldwin cur_csum = 0;
615cd377eb3SJohn Baldwin }
616cd377eb3SJohn Baldwin
617cd377eb3SJohn Baldwin static void
finish_packet(void)618cd377eb3SJohn Baldwin finish_packet(void)
619cd377eb3SJohn Baldwin {
620cd377eb3SJohn Baldwin
621cd377eb3SJohn Baldwin send_char('#');
622cd377eb3SJohn Baldwin send_byte(cur_csum);
623cd377eb3SJohn Baldwin debug("-> %.*s\n", (int)cur_resp.len, io_buffer_head(&cur_resp));
624cd377eb3SJohn Baldwin }
625cd377eb3SJohn Baldwin
626cd377eb3SJohn Baldwin /*
627cd377eb3SJohn Baldwin * Append a single character (for the packet payload) and update the
628cd377eb3SJohn Baldwin * checksum.
629cd377eb3SJohn Baldwin */
630cd377eb3SJohn Baldwin static void
append_char(uint8_t v)631cd377eb3SJohn Baldwin append_char(uint8_t v)
632cd377eb3SJohn Baldwin {
633cd377eb3SJohn Baldwin
634cd377eb3SJohn Baldwin send_char(v);
635cd377eb3SJohn Baldwin cur_csum += v;
636cd377eb3SJohn Baldwin }
637cd377eb3SJohn Baldwin
638cd377eb3SJohn Baldwin /*
639cd377eb3SJohn Baldwin * Append an array of bytes (for the packet payload) and update the
640cd377eb3SJohn Baldwin * checksum.
641cd377eb3SJohn Baldwin */
642cd377eb3SJohn Baldwin static void
append_packet_data(const uint8_t * data,size_t len)643cd377eb3SJohn Baldwin append_packet_data(const uint8_t *data, size_t len)
644cd377eb3SJohn Baldwin {
645cd377eb3SJohn Baldwin
646cd377eb3SJohn Baldwin send_data(data, len);
647cd377eb3SJohn Baldwin while (len > 0) {
648cd377eb3SJohn Baldwin cur_csum += *data;
649cd377eb3SJohn Baldwin data++;
650cd377eb3SJohn Baldwin len--;
651cd377eb3SJohn Baldwin }
652cd377eb3SJohn Baldwin }
653cd377eb3SJohn Baldwin
654cd377eb3SJohn Baldwin static void
append_binary_data(const uint8_t * data,size_t len)655b4fb9479SMark Johnston append_binary_data(const uint8_t *data, size_t len)
656b4fb9479SMark Johnston {
657b4fb9479SMark Johnston uint8_t buf[2];
658b4fb9479SMark Johnston
659b4fb9479SMark Johnston for (; len > 0; data++, len--) {
660b4fb9479SMark Johnston switch (*data) {
661b4fb9479SMark Johnston case '}':
662b4fb9479SMark Johnston case '#':
663b4fb9479SMark Johnston case '$':
664b4fb9479SMark Johnston case '*':
665b4fb9479SMark Johnston buf[0] = 0x7d;
666b4fb9479SMark Johnston buf[1] = *data ^ 0x20;
667b4fb9479SMark Johnston append_packet_data(buf, 2);
668b4fb9479SMark Johnston break;
669b4fb9479SMark Johnston default:
670b4fb9479SMark Johnston append_packet_data(data, 1);
671b4fb9479SMark Johnston break;
672b4fb9479SMark Johnston }
673b4fb9479SMark Johnston }
674b4fb9479SMark Johnston }
675b4fb9479SMark Johnston
676b4fb9479SMark Johnston static void
append_string(const char * str)677cd377eb3SJohn Baldwin append_string(const char *str)
678cd377eb3SJohn Baldwin {
679cd377eb3SJohn Baldwin
680cd377eb3SJohn Baldwin append_packet_data(str, strlen(str));
681cd377eb3SJohn Baldwin }
682cd377eb3SJohn Baldwin
683cd377eb3SJohn Baldwin static void
append_byte(uint8_t v)684cd377eb3SJohn Baldwin append_byte(uint8_t v)
685cd377eb3SJohn Baldwin {
686cd377eb3SJohn Baldwin uint8_t buf[2];
687cd377eb3SJohn Baldwin
688cd377eb3SJohn Baldwin format_byte(v, buf);
689cd377eb3SJohn Baldwin append_packet_data(buf, sizeof(buf));
690cd377eb3SJohn Baldwin }
691cd377eb3SJohn Baldwin
692cd377eb3SJohn Baldwin static void
append_unsigned_native(uintmax_t value,size_t len)693cd377eb3SJohn Baldwin append_unsigned_native(uintmax_t value, size_t len)
694cd377eb3SJohn Baldwin {
695cd377eb3SJohn Baldwin size_t i;
696cd377eb3SJohn Baldwin
697cd377eb3SJohn Baldwin for (i = 0; i < len; i++) {
698cd377eb3SJohn Baldwin append_byte(value);
699cd377eb3SJohn Baldwin value >>= 8;
700cd377eb3SJohn Baldwin }
701cd377eb3SJohn Baldwin }
702cd377eb3SJohn Baldwin
703cd377eb3SJohn Baldwin static void
append_unsigned_be(uintmax_t value,size_t len)704cd377eb3SJohn Baldwin append_unsigned_be(uintmax_t value, size_t len)
705cd377eb3SJohn Baldwin {
706cd377eb3SJohn Baldwin char buf[len * 2];
707cd377eb3SJohn Baldwin size_t i;
708cd377eb3SJohn Baldwin
709cd377eb3SJohn Baldwin for (i = 0; i < len; i++) {
710cd377eb3SJohn Baldwin format_byte(value, buf + (len - i - 1) * 2);
711cd377eb3SJohn Baldwin value >>= 8;
712cd377eb3SJohn Baldwin }
713cd377eb3SJohn Baldwin append_packet_data(buf, sizeof(buf));
714cd377eb3SJohn Baldwin }
715cd377eb3SJohn Baldwin
716cd377eb3SJohn Baldwin static void
append_integer(unsigned int value)717cd377eb3SJohn Baldwin append_integer(unsigned int value)
718cd377eb3SJohn Baldwin {
719cd377eb3SJohn Baldwin
720cd377eb3SJohn Baldwin if (value == 0)
721cd377eb3SJohn Baldwin append_char('0');
722cd377eb3SJohn Baldwin else
723cbd03a9dSJohn Baldwin append_unsigned_be(value, (fls(value) + 7) / 8);
724cd377eb3SJohn Baldwin }
725cd377eb3SJohn Baldwin
726cd377eb3SJohn Baldwin static void
append_asciihex(const char * str)727cd377eb3SJohn Baldwin append_asciihex(const char *str)
728cd377eb3SJohn Baldwin {
729cd377eb3SJohn Baldwin
730cd377eb3SJohn Baldwin while (*str != '\0') {
731cd377eb3SJohn Baldwin append_byte(*str);
732cd377eb3SJohn Baldwin str++;
733cd377eb3SJohn Baldwin }
734cd377eb3SJohn Baldwin }
735cd377eb3SJohn Baldwin
736cd377eb3SJohn Baldwin static void
send_empty_response(void)737cd377eb3SJohn Baldwin send_empty_response(void)
738cd377eb3SJohn Baldwin {
739cd377eb3SJohn Baldwin
740cd377eb3SJohn Baldwin start_packet();
741cd377eb3SJohn Baldwin finish_packet();
742cd377eb3SJohn Baldwin }
743cd377eb3SJohn Baldwin
744cd377eb3SJohn Baldwin static void
send_error(int error)745cd377eb3SJohn Baldwin send_error(int error)
746cd377eb3SJohn Baldwin {
747cd377eb3SJohn Baldwin
748cd377eb3SJohn Baldwin start_packet();
749cd377eb3SJohn Baldwin append_char('E');
750cd377eb3SJohn Baldwin append_byte(error);
751cd377eb3SJohn Baldwin finish_packet();
752cd377eb3SJohn Baldwin }
753cd377eb3SJohn Baldwin
754cd377eb3SJohn Baldwin static void
send_ok(void)755cd377eb3SJohn Baldwin send_ok(void)
756cd377eb3SJohn Baldwin {
757cd377eb3SJohn Baldwin
758cd377eb3SJohn Baldwin start_packet();
759cd377eb3SJohn Baldwin append_string("OK");
760cd377eb3SJohn Baldwin finish_packet();
761cd377eb3SJohn Baldwin }
762cd377eb3SJohn Baldwin
763cd377eb3SJohn Baldwin static int
parse_threadid(const uint8_t * data,size_t len)764cd377eb3SJohn Baldwin parse_threadid(const uint8_t *data, size_t len)
765cd377eb3SJohn Baldwin {
766cd377eb3SJohn Baldwin
767cd377eb3SJohn Baldwin if (len == 1 && *data == '0')
768cd377eb3SJohn Baldwin return (0);
769cd377eb3SJohn Baldwin if (len == 2 && memcmp(data, "-1", 2) == 0)
770cd377eb3SJohn Baldwin return (-1);
771cd377eb3SJohn Baldwin if (len == 0)
772cd377eb3SJohn Baldwin return (-2);
773cd377eb3SJohn Baldwin return (parse_integer(data, len));
774cd377eb3SJohn Baldwin }
775cd377eb3SJohn Baldwin
776cbd03a9dSJohn Baldwin /*
777cbd03a9dSJohn Baldwin * Report the current stop event to the debugger. If the stop is due
778cbd03a9dSJohn Baldwin * to an event triggered on a specific vCPU such as a breakpoint or
779cbd03a9dSJohn Baldwin * stepping trap, stopped_vcpu will be set to the vCPU triggering the
780cbd03a9dSJohn Baldwin * stop. If 'set_cur_vcpu' is true, then cur_vcpu will be updated to
781cbd03a9dSJohn Baldwin * the reporting vCPU for vCPU events.
782cbd03a9dSJohn Baldwin */
783cd377eb3SJohn Baldwin static void
report_stop(bool set_cur_vcpu)784cbd03a9dSJohn Baldwin report_stop(bool set_cur_vcpu)
785cd377eb3SJohn Baldwin {
786cbd03a9dSJohn Baldwin struct vcpu_state *vs;
787cd377eb3SJohn Baldwin
788cd377eb3SJohn Baldwin start_packet();
789cbd03a9dSJohn Baldwin if (stopped_vcpu == -1) {
790cd377eb3SJohn Baldwin append_char('S');
791cbd03a9dSJohn Baldwin append_byte(GDB_SIGNAL_TRAP);
792cbd03a9dSJohn Baldwin } else {
793cbd03a9dSJohn Baldwin vs = &vcpu_state[stopped_vcpu];
794cbd03a9dSJohn Baldwin if (set_cur_vcpu)
795cbd03a9dSJohn Baldwin cur_vcpu = stopped_vcpu;
796cd377eb3SJohn Baldwin append_char('T');
797cd377eb3SJohn Baldwin append_byte(GDB_SIGNAL_TRAP);
798cd377eb3SJohn Baldwin append_string("thread:");
799cd377eb3SJohn Baldwin append_integer(stopped_vcpu + 1);
800cd377eb3SJohn Baldwin append_char(';');
801cbd03a9dSJohn Baldwin if (vs->hit_swbreak) {
802cbd03a9dSJohn Baldwin debug("$vCPU %d reporting swbreak\n", stopped_vcpu);
803cbd03a9dSJohn Baldwin if (swbreak_enabled)
804cbd03a9dSJohn Baldwin append_string("swbreak:;");
805cbd03a9dSJohn Baldwin } else if (vs->stepped)
806cbd03a9dSJohn Baldwin debug("$vCPU %d reporting step\n", stopped_vcpu);
807cbd03a9dSJohn Baldwin else
808cbd03a9dSJohn Baldwin debug("$vCPU %d reporting ???\n", stopped_vcpu);
809cd377eb3SJohn Baldwin }
810cd377eb3SJohn Baldwin finish_packet();
811cbd03a9dSJohn Baldwin report_next_stop = false;
812cbd03a9dSJohn Baldwin }
813cbd03a9dSJohn Baldwin
814cbd03a9dSJohn Baldwin /*
815cbd03a9dSJohn Baldwin * If this stop is due to a vCPU event, clear that event to mark it as
816cbd03a9dSJohn Baldwin * acknowledged.
817cbd03a9dSJohn Baldwin */
818cbd03a9dSJohn Baldwin static void
discard_stop(void)819cbd03a9dSJohn Baldwin discard_stop(void)
820cbd03a9dSJohn Baldwin {
821cbd03a9dSJohn Baldwin struct vcpu_state *vs;
822cbd03a9dSJohn Baldwin
823cbd03a9dSJohn Baldwin if (stopped_vcpu != -1) {
824cbd03a9dSJohn Baldwin vs = &vcpu_state[stopped_vcpu];
825cbd03a9dSJohn Baldwin vs->hit_swbreak = false;
826cbd03a9dSJohn Baldwin vs->stepped = false;
827cbd03a9dSJohn Baldwin stopped_vcpu = -1;
828cbd03a9dSJohn Baldwin }
829cbd03a9dSJohn Baldwin report_next_stop = true;
830cd377eb3SJohn Baldwin }
831cd377eb3SJohn Baldwin
832cd377eb3SJohn Baldwin static void
gdb_finish_suspend_vcpus(void)833cd377eb3SJohn Baldwin gdb_finish_suspend_vcpus(void)
834cd377eb3SJohn Baldwin {
835cd377eb3SJohn Baldwin
836cd377eb3SJohn Baldwin if (first_stop) {
837cd377eb3SJohn Baldwin first_stop = false;
838cd377eb3SJohn Baldwin stopped_vcpu = -1;
839cbd03a9dSJohn Baldwin } else if (report_next_stop) {
840cbd03a9dSJohn Baldwin assert(!response_pending());
841cbd03a9dSJohn Baldwin report_stop(true);
842cd377eb3SJohn Baldwin send_pending_data(cur_fd);
843cd377eb3SJohn Baldwin }
844cd377eb3SJohn Baldwin }
845cd377eb3SJohn Baldwin
846cbd03a9dSJohn Baldwin /*
847cbd03a9dSJohn Baldwin * vCPU threads invoke this function whenever the vCPU enters the
848cbd03a9dSJohn Baldwin * debug server to pause or report an event. vCPU threads wait here
849cbd03a9dSJohn Baldwin * as long as the debug server keeps them suspended.
850cbd03a9dSJohn Baldwin */
851cd377eb3SJohn Baldwin static void
_gdb_cpu_suspend(struct vcpu * vcpu,bool report_stop)8527d9ef309SJohn Baldwin _gdb_cpu_suspend(struct vcpu *vcpu, bool report_stop)
853cd377eb3SJohn Baldwin {
8547d9ef309SJohn Baldwin int vcpuid = vcpu_id(vcpu);
855cd377eb3SJohn Baldwin
8567d9ef309SJohn Baldwin debug("$vCPU %d suspending\n", vcpuid);
8577d9ef309SJohn Baldwin CPU_SET(vcpuid, &vcpus_waiting);
858cd377eb3SJohn Baldwin if (report_stop && CPU_CMP(&vcpus_waiting, &vcpus_suspended) == 0)
859cd377eb3SJohn Baldwin gdb_finish_suspend_vcpus();
8607d9ef309SJohn Baldwin while (CPU_ISSET(vcpuid, &vcpus_suspended))
861cd377eb3SJohn Baldwin pthread_cond_wait(&idle_vcpus, &gdb_lock);
8627d9ef309SJohn Baldwin CPU_CLR(vcpuid, &vcpus_waiting);
8637d9ef309SJohn Baldwin debug("$vCPU %d resuming\n", vcpuid);
864cd377eb3SJohn Baldwin }
865cd377eb3SJohn Baldwin
866cbd03a9dSJohn Baldwin /*
867ca96a942SBojan Novković * Requests vCPU single-stepping using a
868ca96a942SBojan Novković * VMEXIT suitable for the host platform.
869ca96a942SBojan Novković */
870ca96a942SBojan Novković static int
_gdb_set_step(struct vcpu * vcpu,int val)871ca96a942SBojan Novković _gdb_set_step(struct vcpu *vcpu, int val)
872ca96a942SBojan Novković {
873ca96a942SBojan Novković int error;
874ca96a942SBojan Novković
875a0ca4af9SMark Johnston #ifdef __amd64__
876ca96a942SBojan Novković /*
877ca96a942SBojan Novković * If the MTRAP cap fails, we are running on an AMD host.
878ca96a942SBojan Novković * In that case, we request DB exits caused by RFLAGS.TF.
879ca96a942SBojan Novković */
880ca96a942SBojan Novković error = vm_set_capability(vcpu, VM_CAP_MTRAP_EXIT, val);
881ca96a942SBojan Novković if (error != 0)
882ca96a942SBojan Novković error = vm_set_capability(vcpu, VM_CAP_RFLAGS_TF, val);
883ca96a942SBojan Novković if (error == 0)
884ca96a942SBojan Novković (void)vm_set_capability(vcpu, VM_CAP_MASK_HWINTR, val);
885a0ca4af9SMark Johnston #else /* __aarch64__ */
886a0ca4af9SMark Johnston error = vm_set_capability(vcpu, VM_CAP_SS_EXIT, val);
887a0ca4af9SMark Johnston if (error == 0)
888a0ca4af9SMark Johnston error = vm_set_capability(vcpu, VM_CAP_MASK_HWINTR, val);
889a0ca4af9SMark Johnston #endif
890ca96a942SBojan Novković return (error);
891ca96a942SBojan Novković }
892ca96a942SBojan Novković
893ca96a942SBojan Novković /*
894a0ca4af9SMark Johnston * Checks whether single-stepping is supported for a given vCPU.
895ca96a942SBojan Novković */
896ca96a942SBojan Novković static int
_gdb_check_step(struct vcpu * vcpu)897ca96a942SBojan Novković _gdb_check_step(struct vcpu *vcpu)
898ca96a942SBojan Novković {
899a0ca4af9SMark Johnston #ifdef __amd64__
900ca96a942SBojan Novković int val;
901ca96a942SBojan Novković
902ca96a942SBojan Novković if (vm_get_capability(vcpu, VM_CAP_MTRAP_EXIT, &val) != 0) {
903ca96a942SBojan Novković if (vm_get_capability(vcpu, VM_CAP_RFLAGS_TF, &val) != 0)
904a0ca4af9SMark Johnston return (-1);
905ca96a942SBojan Novković }
906a0ca4af9SMark Johnston #else /* __aarch64__ */
907a0ca4af9SMark Johnston (void)vcpu;
908a0ca4af9SMark Johnston #endif
909a0ca4af9SMark Johnston return (0);
910ca96a942SBojan Novković }
911ca96a942SBojan Novković
912ca96a942SBojan Novković /*
913cbd03a9dSJohn Baldwin * Invoked at the start of a vCPU thread's execution to inform the
914cbd03a9dSJohn Baldwin * debug server about the new thread.
915cbd03a9dSJohn Baldwin */
916cd377eb3SJohn Baldwin void
gdb_cpu_add(struct vcpu * vcpu)9177d9ef309SJohn Baldwin gdb_cpu_add(struct vcpu *vcpu)
918cd377eb3SJohn Baldwin {
9197d9ef309SJohn Baldwin int vcpuid;
920cd377eb3SJohn Baldwin
921621b5090SJohn Baldwin if (!gdb_active)
922621b5090SJohn Baldwin return;
9237d9ef309SJohn Baldwin vcpuid = vcpu_id(vcpu);
9247d9ef309SJohn Baldwin debug("$vCPU %d starting\n", vcpuid);
925cd377eb3SJohn Baldwin pthread_mutex_lock(&gdb_lock);
9267d9ef309SJohn Baldwin assert(vcpuid < guest_ncpus);
9277d9ef309SJohn Baldwin assert(vcpus[vcpuid] == NULL);
9287d9ef309SJohn Baldwin vcpus[vcpuid] = vcpu;
9297d9ef309SJohn Baldwin CPU_SET(vcpuid, &vcpus_active);
930cbd03a9dSJohn Baldwin if (!TAILQ_EMPTY(&breakpoints)) {
931a0ca4af9SMark Johnston vm_set_capability(vcpu, GDB_BREAKPOINT_CAP, 1);
9324e288572SMark Johnston debug("$vCPU %d enabled breakpoint exits\n", vcpuid);
933cbd03a9dSJohn Baldwin }
934cd377eb3SJohn Baldwin
935cd377eb3SJohn Baldwin /*
936cd377eb3SJohn Baldwin * If a vcpu is added while vcpus are stopped, suspend the new
937cd377eb3SJohn Baldwin * vcpu so that it will pop back out with a debug exit before
938cd377eb3SJohn Baldwin * executing the first instruction.
939cd377eb3SJohn Baldwin */
940cd377eb3SJohn Baldwin if (!CPU_EMPTY(&vcpus_suspended)) {
941*a9e4753bSMark Johnston cpuset_t suspended;
942*a9e4753bSMark Johnston int error;
943*a9e4753bSMark Johnston
944*a9e4753bSMark Johnston error = vm_debug_cpus(ctx, &suspended);
945*a9e4753bSMark Johnston assert(error == 0);
946*a9e4753bSMark Johnston
9477d9ef309SJohn Baldwin CPU_SET(vcpuid, &vcpus_suspended);
948cd377eb3SJohn Baldwin _gdb_cpu_suspend(vcpu, false);
949*a9e4753bSMark Johnston
950*a9e4753bSMark Johnston /*
951*a9e4753bSMark Johnston * In general, APs are started in a suspended mode such that
952*a9e4753bSMark Johnston * they exit with VM_EXITCODE_DEBUG until the BSP starts them.
953*a9e4753bSMark Johnston * In particular, this refers to the kernel's view of the vCPU
954*a9e4753bSMark Johnston * state rather than our own. If the debugger resumes guest
955*a9e4753bSMark Johnston * execution, vCPUs will be unsuspended from the kernel's point
956*a9e4753bSMark Johnston * of view, so we should restore the previous state before
957*a9e4753bSMark Johnston * continuing.
958*a9e4753bSMark Johnston */
959*a9e4753bSMark Johnston if (CPU_ISSET(vcpuid, &suspended)) {
960*a9e4753bSMark Johnston error = vm_suspend_cpu(vcpu);
961*a9e4753bSMark Johnston assert(error == 0);
962*a9e4753bSMark Johnston }
963cd377eb3SJohn Baldwin }
964cd377eb3SJohn Baldwin pthread_mutex_unlock(&gdb_lock);
965cd377eb3SJohn Baldwin }
966cd377eb3SJohn Baldwin
967cbd03a9dSJohn Baldwin /*
968cbd03a9dSJohn Baldwin * Invoked by vCPU before resuming execution. This enables stepping
969cbd03a9dSJohn Baldwin * if the vCPU is marked as stepping.
970cbd03a9dSJohn Baldwin */
971cbd03a9dSJohn Baldwin static void
gdb_cpu_resume(struct vcpu * vcpu)9727d9ef309SJohn Baldwin gdb_cpu_resume(struct vcpu *vcpu)
973cbd03a9dSJohn Baldwin {
974cbd03a9dSJohn Baldwin struct vcpu_state *vs;
975cbd03a9dSJohn Baldwin int error;
976cbd03a9dSJohn Baldwin
9777d9ef309SJohn Baldwin vs = &vcpu_state[vcpu_id(vcpu)];
978cbd03a9dSJohn Baldwin
979cbd03a9dSJohn Baldwin /*
980cbd03a9dSJohn Baldwin * Any pending event should already be reported before
981cbd03a9dSJohn Baldwin * resuming.
982cbd03a9dSJohn Baldwin */
983cbd03a9dSJohn Baldwin assert(vs->hit_swbreak == false);
984cbd03a9dSJohn Baldwin assert(vs->stepped == false);
985cbd03a9dSJohn Baldwin if (vs->stepping) {
986ca96a942SBojan Novković error = _gdb_set_step(vcpu, 1);
987fefac543SBojan Novković assert(error == 0);
988cbd03a9dSJohn Baldwin }
989cbd03a9dSJohn Baldwin }
990cbd03a9dSJohn Baldwin
991cbd03a9dSJohn Baldwin /*
992cbd03a9dSJohn Baldwin * Handler for VM_EXITCODE_DEBUG used to suspend a vCPU when the guest
993cbd03a9dSJohn Baldwin * has been suspended due to an event on different vCPU or in response
994cbd03a9dSJohn Baldwin * to a guest-wide suspend such as Ctrl-C or the stop on attach.
995cbd03a9dSJohn Baldwin */
996cd377eb3SJohn Baldwin void
gdb_cpu_suspend(struct vcpu * vcpu)9977d9ef309SJohn Baldwin gdb_cpu_suspend(struct vcpu *vcpu)
998cd377eb3SJohn Baldwin {
999cd377eb3SJohn Baldwin
1000eacc27afSJohn Baldwin if (!gdb_active)
1001eacc27afSJohn Baldwin return;
1002cd377eb3SJohn Baldwin pthread_mutex_lock(&gdb_lock);
1003cd377eb3SJohn Baldwin _gdb_cpu_suspend(vcpu, true);
1004cbd03a9dSJohn Baldwin gdb_cpu_resume(vcpu);
1005cd377eb3SJohn Baldwin pthread_mutex_unlock(&gdb_lock);
1006cd377eb3SJohn Baldwin }
1007cd377eb3SJohn Baldwin
1008cd377eb3SJohn Baldwin static void
gdb_suspend_vcpus(void)1009cd377eb3SJohn Baldwin gdb_suspend_vcpus(void)
1010cd377eb3SJohn Baldwin {
1011cd377eb3SJohn Baldwin
1012cd377eb3SJohn Baldwin assert(pthread_mutex_isowned_np(&gdb_lock));
1013cd377eb3SJohn Baldwin debug("suspending all CPUs\n");
1014cd377eb3SJohn Baldwin vcpus_suspended = vcpus_active;
10157d9ef309SJohn Baldwin vm_suspend_all_cpus(ctx);
1016cd377eb3SJohn Baldwin if (CPU_CMP(&vcpus_waiting, &vcpus_suspended) == 0)
1017cd377eb3SJohn Baldwin gdb_finish_suspend_vcpus();
1018cd377eb3SJohn Baldwin }
1019cd377eb3SJohn Baldwin
1020cbd03a9dSJohn Baldwin /*
1021ca96a942SBojan Novković * Invoked each time a vmexit handler needs to step a vCPU.
1022ca96a942SBojan Novković * Handles MTRAP and RFLAGS.TF vmexits.
1023cbd03a9dSJohn Baldwin */
1024ca96a942SBojan Novković static void
gdb_cpu_step(struct vcpu * vcpu)1025ca96a942SBojan Novković gdb_cpu_step(struct vcpu *vcpu)
1026cbd03a9dSJohn Baldwin {
1027cbd03a9dSJohn Baldwin struct vcpu_state *vs;
1028ca96a942SBojan Novković int vcpuid = vcpu_id(vcpu);
1029ca96a942SBojan Novković int error;
1030cbd03a9dSJohn Baldwin
1031ca96a942SBojan Novković debug("$vCPU %d stepped\n", vcpuid);
1032cbd03a9dSJohn Baldwin pthread_mutex_lock(&gdb_lock);
10337d9ef309SJohn Baldwin vs = &vcpu_state[vcpuid];
1034cbd03a9dSJohn Baldwin if (vs->stepping) {
1035cbd03a9dSJohn Baldwin vs->stepping = false;
1036cbd03a9dSJohn Baldwin vs->stepped = true;
1037ca96a942SBojan Novković error = _gdb_set_step(vcpu, 0);
1038ca96a942SBojan Novković assert(error == 0);
1039fefac543SBojan Novković
1040cbd03a9dSJohn Baldwin while (vs->stepped) {
1041cbd03a9dSJohn Baldwin if (stopped_vcpu == -1) {
10427d9ef309SJohn Baldwin debug("$vCPU %d reporting step\n", vcpuid);
10437d9ef309SJohn Baldwin stopped_vcpu = vcpuid;
1044cbd03a9dSJohn Baldwin gdb_suspend_vcpus();
1045cbd03a9dSJohn Baldwin }
1046cbd03a9dSJohn Baldwin _gdb_cpu_suspend(vcpu, true);
1047cbd03a9dSJohn Baldwin }
1048cbd03a9dSJohn Baldwin gdb_cpu_resume(vcpu);
1049cbd03a9dSJohn Baldwin }
1050cbd03a9dSJohn Baldwin pthread_mutex_unlock(&gdb_lock);
1051cbd03a9dSJohn Baldwin }
1052cbd03a9dSJohn Baldwin
1053ca96a942SBojan Novković /*
1054a0ca4af9SMark Johnston * A general handler for single-step exceptions.
1055ca96a942SBojan Novković * Handles RFLAGS.TF exits on AMD SVM.
1056ca96a942SBojan Novković */
1057ca96a942SBojan Novković void
gdb_cpu_debug(struct vcpu * vcpu,struct vm_exit * vmexit)1058ca96a942SBojan Novković gdb_cpu_debug(struct vcpu *vcpu, struct vm_exit *vmexit)
1059ca96a942SBojan Novković {
1060ca96a942SBojan Novković if (!gdb_active)
1061ca96a942SBojan Novković return;
1062ca96a942SBojan Novković
1063a0ca4af9SMark Johnston #ifdef __amd64__
1064ca96a942SBojan Novković /* RFLAGS.TF exit? */
1065ca96a942SBojan Novković if (vmexit->u.dbg.trace_trap) {
1066ca96a942SBojan Novković gdb_cpu_step(vcpu);
1067ca96a942SBojan Novković }
1068a0ca4af9SMark Johnston #else /* __aarch64__ */
1069a0ca4af9SMark Johnston (void)vmexit;
1070a0ca4af9SMark Johnston gdb_cpu_step(vcpu);
1071a0ca4af9SMark Johnston #endif
1072ca96a942SBojan Novković }
1073ca96a942SBojan Novković
1074ca96a942SBojan Novković /*
1075ca96a942SBojan Novković * Handler for VM_EXITCODE_MTRAP reported when a vCPU single-steps via
1076ca96a942SBojan Novković * the VT-x-specific MTRAP exit.
1077ca96a942SBojan Novković */
1078ca96a942SBojan Novković void
gdb_cpu_mtrap(struct vcpu * vcpu)1079ca96a942SBojan Novković gdb_cpu_mtrap(struct vcpu *vcpu)
1080ca96a942SBojan Novković {
1081ca96a942SBojan Novković if (!gdb_active)
1082ca96a942SBojan Novković return;
1083ca96a942SBojan Novković gdb_cpu_step(vcpu);
1084ca96a942SBojan Novković }
1085ca96a942SBojan Novković
1086cbd03a9dSJohn Baldwin static struct breakpoint *
find_breakpoint(uint64_t gpa)1087cbd03a9dSJohn Baldwin find_breakpoint(uint64_t gpa)
1088cbd03a9dSJohn Baldwin {
1089cbd03a9dSJohn Baldwin struct breakpoint *bp;
1090cbd03a9dSJohn Baldwin
1091cbd03a9dSJohn Baldwin TAILQ_FOREACH(bp, &breakpoints, link) {
1092cbd03a9dSJohn Baldwin if (bp->gpa == gpa)
1093cbd03a9dSJohn Baldwin return (bp);
1094cbd03a9dSJohn Baldwin }
1095cbd03a9dSJohn Baldwin return (NULL);
1096cbd03a9dSJohn Baldwin }
1097cbd03a9dSJohn Baldwin
1098cbd03a9dSJohn Baldwin void
gdb_cpu_breakpoint(struct vcpu * vcpu,struct vm_exit * vmexit)10997d9ef309SJohn Baldwin gdb_cpu_breakpoint(struct vcpu *vcpu, struct vm_exit *vmexit)
1100cbd03a9dSJohn Baldwin {
1101cbd03a9dSJohn Baldwin struct breakpoint *bp;
1102cbd03a9dSJohn Baldwin struct vcpu_state *vs;
1103cbd03a9dSJohn Baldwin uint64_t gpa;
11047d9ef309SJohn Baldwin int error, vcpuid;
1105cbd03a9dSJohn Baldwin
1106621b5090SJohn Baldwin if (!gdb_active) {
1107b0936440SJohn Baldwin EPRINTLN("vm_loop: unexpected VMEXIT_DEBUG");
1108621b5090SJohn Baldwin exit(4);
1109621b5090SJohn Baldwin }
11107d9ef309SJohn Baldwin vcpuid = vcpu_id(vcpu);
1111cbd03a9dSJohn Baldwin pthread_mutex_lock(&gdb_lock);
11125f086566SMark Johnston error = guest_vaddr2paddr(vcpu, guest_pc(vmexit), &gpa);
1113cbd03a9dSJohn Baldwin assert(error == 1);
1114cbd03a9dSJohn Baldwin bp = find_breakpoint(gpa);
1115cbd03a9dSJohn Baldwin if (bp != NULL) {
11167d9ef309SJohn Baldwin vs = &vcpu_state[vcpuid];
1117cbd03a9dSJohn Baldwin assert(vs->stepping == false);
1118cbd03a9dSJohn Baldwin assert(vs->stepped == false);
1119cbd03a9dSJohn Baldwin assert(vs->hit_swbreak == false);
1120cbd03a9dSJohn Baldwin vs->hit_swbreak = true;
11215f086566SMark Johnston vm_set_register(vcpu, GDB_PC_REGNAME, guest_pc(vmexit));
1122cbd03a9dSJohn Baldwin for (;;) {
1123cbd03a9dSJohn Baldwin if (stopped_vcpu == -1) {
11247d9ef309SJohn Baldwin debug("$vCPU %d reporting breakpoint at rip %#lx\n",
11255f086566SMark Johnston vcpuid, guest_pc(vmexit));
11267d9ef309SJohn Baldwin stopped_vcpu = vcpuid;
1127cbd03a9dSJohn Baldwin gdb_suspend_vcpus();
1128cbd03a9dSJohn Baldwin }
1129cbd03a9dSJohn Baldwin _gdb_cpu_suspend(vcpu, true);
1130cbd03a9dSJohn Baldwin if (!vs->hit_swbreak) {
1131cbd03a9dSJohn Baldwin /* Breakpoint reported. */
1132cbd03a9dSJohn Baldwin break;
1133cbd03a9dSJohn Baldwin }
1134cbd03a9dSJohn Baldwin bp = find_breakpoint(gpa);
1135cbd03a9dSJohn Baldwin if (bp == NULL) {
1136cbd03a9dSJohn Baldwin /* Breakpoint was removed. */
1137cbd03a9dSJohn Baldwin vs->hit_swbreak = false;
1138cbd03a9dSJohn Baldwin break;
1139cbd03a9dSJohn Baldwin }
1140cbd03a9dSJohn Baldwin }
1141cbd03a9dSJohn Baldwin gdb_cpu_resume(vcpu);
1142cbd03a9dSJohn Baldwin } else {
11437d9ef309SJohn Baldwin debug("$vCPU %d injecting breakpoint at rip %#lx\n", vcpuid,
11445f086566SMark Johnston guest_pc(vmexit));
1145a0ca4af9SMark Johnston #ifdef __amd64__
11467d9ef309SJohn Baldwin error = vm_set_register(vcpu, VM_REG_GUEST_ENTRY_INST_LENGTH,
11477d9ef309SJohn Baldwin vmexit->u.bpt.inst_length);
1148cbd03a9dSJohn Baldwin assert(error == 0);
11497d9ef309SJohn Baldwin error = vm_inject_exception(vcpu, IDT_BP, 0, 0, 0);
1150cbd03a9dSJohn Baldwin assert(error == 0);
1151a0ca4af9SMark Johnston #else /* __aarch64__ */
1152a0ca4af9SMark Johnston uint64_t esr;
1153a0ca4af9SMark Johnston
1154a0ca4af9SMark Johnston esr = (EXCP_BRK << ESR_ELx_EC_SHIFT) | vmexit->u.hyp.esr_el2;
1155a0ca4af9SMark Johnston error = vm_inject_exception(vcpu, esr, 0);
1156a0ca4af9SMark Johnston assert(error == 0);
1157a0ca4af9SMark Johnston #endif
1158cbd03a9dSJohn Baldwin }
1159cbd03a9dSJohn Baldwin pthread_mutex_unlock(&gdb_lock);
1160cbd03a9dSJohn Baldwin }
1161cbd03a9dSJohn Baldwin
1162cd377eb3SJohn Baldwin static bool
gdb_step_vcpu(struct vcpu * vcpu)11637d9ef309SJohn Baldwin gdb_step_vcpu(struct vcpu *vcpu)
1164cd377eb3SJohn Baldwin {
1165ca96a942SBojan Novković int error, vcpuid;
1166cd377eb3SJohn Baldwin
11677d9ef309SJohn Baldwin vcpuid = vcpu_id(vcpu);
11687d9ef309SJohn Baldwin debug("$vCPU %d step\n", vcpuid);
1169ca96a942SBojan Novković error = _gdb_check_step(vcpu);
1170cd377eb3SJohn Baldwin if (error < 0)
1171cd377eb3SJohn Baldwin return (false);
1172cbd03a9dSJohn Baldwin
1173cbd03a9dSJohn Baldwin discard_stop();
11747d9ef309SJohn Baldwin vcpu_state[vcpuid].stepping = true;
11757d9ef309SJohn Baldwin vm_resume_cpu(vcpu);
11767d9ef309SJohn Baldwin CPU_CLR(vcpuid, &vcpus_suspended);
1177cd377eb3SJohn Baldwin pthread_cond_broadcast(&idle_vcpus);
1178cd377eb3SJohn Baldwin return (true);
1179cd377eb3SJohn Baldwin }
1180cd377eb3SJohn Baldwin
1181cd377eb3SJohn Baldwin static void
gdb_resume_vcpus(void)1182cd377eb3SJohn Baldwin gdb_resume_vcpus(void)
1183cd377eb3SJohn Baldwin {
1184cd377eb3SJohn Baldwin
1185cd377eb3SJohn Baldwin assert(pthread_mutex_isowned_np(&gdb_lock));
11867d9ef309SJohn Baldwin vm_resume_all_cpus(ctx);
1187cd377eb3SJohn Baldwin debug("resuming all CPUs\n");
1188cd377eb3SJohn Baldwin CPU_ZERO(&vcpus_suspended);
1189cd377eb3SJohn Baldwin pthread_cond_broadcast(&idle_vcpus);
1190cd377eb3SJohn Baldwin }
1191cd377eb3SJohn Baldwin
1192cd377eb3SJohn Baldwin static void
gdb_read_regs(void)1193cd377eb3SJohn Baldwin gdb_read_regs(void)
1194cd377eb3SJohn Baldwin {
1195cd377eb3SJohn Baldwin uint64_t regvals[nitems(gdb_regset)];
11965e728af4SMark Johnston int regnums[nitems(gdb_regset)];
1197cd377eb3SJohn Baldwin
11985e728af4SMark Johnston for (size_t i = 0; i < nitems(gdb_regset); i++)
11995e728af4SMark Johnston regnums[i] = gdb_regset[i].id;
12007d9ef309SJohn Baldwin if (vm_get_register_set(vcpus[cur_vcpu], nitems(gdb_regset),
12015e728af4SMark Johnston regnums, regvals) == -1) {
1202cd377eb3SJohn Baldwin send_error(errno);
1203cd377eb3SJohn Baldwin return;
1204cd377eb3SJohn Baldwin }
1205f81cdf24SMark Johnston
1206cd377eb3SJohn Baldwin start_packet();
1207f81cdf24SMark Johnston for (size_t i = 0; i < nitems(gdb_regset); i++) {
1208a0ca4af9SMark Johnston #ifdef GDB_REG_FIRST_EXT
1209f81cdf24SMark Johnston if (gdb_regset[i].id == GDB_REG_FIRST_EXT)
1210f81cdf24SMark Johnston break;
1211a0ca4af9SMark Johnston #endif
12125e728af4SMark Johnston append_unsigned_native(regvals[i], gdb_regset[i].size);
1213f81cdf24SMark Johnston }
1214cd377eb3SJohn Baldwin finish_packet();
1215cd377eb3SJohn Baldwin }
1216cd377eb3SJohn Baldwin
1217cd377eb3SJohn Baldwin static void
gdb_read_one_reg(const uint8_t * data,size_t len)1218e6516294SMark Johnston gdb_read_one_reg(const uint8_t *data, size_t len)
1219e6516294SMark Johnston {
1220e6516294SMark Johnston uint64_t regval;
1221e6516294SMark Johnston uintmax_t reg;
1222e6516294SMark Johnston
1223e6516294SMark Johnston reg = parse_integer(data, len);
1224e6516294SMark Johnston if (reg >= nitems(gdb_regset)) {
1225e6516294SMark Johnston send_error(EINVAL);
1226e6516294SMark Johnston return;
1227e6516294SMark Johnston }
1228e6516294SMark Johnston
1229e6516294SMark Johnston if (vm_get_register(vcpus[cur_vcpu], gdb_regset[reg].id, ®val) ==
1230e6516294SMark Johnston -1) {
1231e6516294SMark Johnston send_error(errno);
1232e6516294SMark Johnston return;
1233e6516294SMark Johnston }
1234e6516294SMark Johnston
1235e6516294SMark Johnston start_packet();
1236e6516294SMark Johnston append_unsigned_native(regval, gdb_regset[reg].size);
1237e6516294SMark Johnston finish_packet();
1238e6516294SMark Johnston }
1239e6516294SMark Johnston
1240e6516294SMark Johnston static void
gdb_read_mem(const uint8_t * data,size_t len)1241cd377eb3SJohn Baldwin gdb_read_mem(const uint8_t *data, size_t len)
1242cd377eb3SJohn Baldwin {
1243cd377eb3SJohn Baldwin uint64_t gpa, gva, val;
1244cd377eb3SJohn Baldwin uint8_t *cp;
1245cd377eb3SJohn Baldwin size_t resid, todo, bytes;
1246cd377eb3SJohn Baldwin bool started;
1247cd377eb3SJohn Baldwin int error;
1248cd377eb3SJohn Baldwin
1249cfa2c78aSMark Johnston assert(len >= 1);
1250cfa2c78aSMark Johnston
12511b52cd45SJohn Baldwin /* Skip 'm' */
12521b52cd45SJohn Baldwin data += 1;
12531b52cd45SJohn Baldwin len -= 1;
12541b52cd45SJohn Baldwin
12551b52cd45SJohn Baldwin /* Parse and consume address. */
1256cd377eb3SJohn Baldwin cp = memchr(data, ',', len);
12571b52cd45SJohn Baldwin if (cp == NULL || cp == data) {
1258cd377eb3SJohn Baldwin send_error(EINVAL);
1259cd377eb3SJohn Baldwin return;
1260cd377eb3SJohn Baldwin }
12611b52cd45SJohn Baldwin gva = parse_integer(data, cp - data);
12621b52cd45SJohn Baldwin len -= (cp - data) + 1;
12631b52cd45SJohn Baldwin data += (cp - data) + 1;
1264cd377eb3SJohn Baldwin
12651b52cd45SJohn Baldwin /* Parse length. */
12661b52cd45SJohn Baldwin resid = parse_integer(data, len);
12671b52cd45SJohn Baldwin
12681b52cd45SJohn Baldwin started = false;
1269cd377eb3SJohn Baldwin while (resid > 0) {
12707d9ef309SJohn Baldwin error = guest_vaddr2paddr(vcpus[cur_vcpu], gva, &gpa);
1271cd377eb3SJohn Baldwin if (error == -1) {
1272cd377eb3SJohn Baldwin if (started)
1273cd377eb3SJohn Baldwin finish_packet();
1274cd377eb3SJohn Baldwin else
1275cd377eb3SJohn Baldwin send_error(errno);
1276cd377eb3SJohn Baldwin return;
1277cd377eb3SJohn Baldwin }
1278cd377eb3SJohn Baldwin if (error == 0) {
1279cd377eb3SJohn Baldwin if (started)
1280cd377eb3SJohn Baldwin finish_packet();
1281cd377eb3SJohn Baldwin else
1282cd377eb3SJohn Baldwin send_error(EFAULT);
1283cd377eb3SJohn Baldwin return;
1284cd377eb3SJohn Baldwin }
1285cd377eb3SJohn Baldwin
1286cd377eb3SJohn Baldwin /* Read bytes from current page. */
1287cd377eb3SJohn Baldwin todo = getpagesize() - gpa % getpagesize();
1288cd377eb3SJohn Baldwin if (todo > resid)
1289cd377eb3SJohn Baldwin todo = resid;
1290cd377eb3SJohn Baldwin
1291cd377eb3SJohn Baldwin cp = paddr_guest2host(ctx, gpa, todo);
1292cd377eb3SJohn Baldwin if (cp != NULL) {
1293cd377eb3SJohn Baldwin /*
1294cd377eb3SJohn Baldwin * If this page is guest RAM, read it a byte
1295cd377eb3SJohn Baldwin * at a time.
1296cd377eb3SJohn Baldwin */
1297cd377eb3SJohn Baldwin if (!started) {
1298cd377eb3SJohn Baldwin start_packet();
1299cd377eb3SJohn Baldwin started = true;
1300cd377eb3SJohn Baldwin }
1301cd377eb3SJohn Baldwin while (todo > 0) {
1302cd377eb3SJohn Baldwin append_byte(*cp);
1303cd377eb3SJohn Baldwin cp++;
1304cd377eb3SJohn Baldwin gpa++;
1305cd377eb3SJohn Baldwin gva++;
1306cd377eb3SJohn Baldwin resid--;
1307cd377eb3SJohn Baldwin todo--;
1308cd377eb3SJohn Baldwin }
1309cd377eb3SJohn Baldwin } else {
1310cd377eb3SJohn Baldwin /*
1311cd377eb3SJohn Baldwin * If this page isn't guest RAM, try to handle
1312cd377eb3SJohn Baldwin * it via MMIO. For MMIO requests, use
1313cd377eb3SJohn Baldwin * aligned reads of words when possible.
1314cd377eb3SJohn Baldwin */
1315cd377eb3SJohn Baldwin while (todo > 0) {
1316cd377eb3SJohn Baldwin if (gpa & 1 || todo == 1)
1317cd377eb3SJohn Baldwin bytes = 1;
1318cd377eb3SJohn Baldwin else if (gpa & 2 || todo == 2)
1319cd377eb3SJohn Baldwin bytes = 2;
1320cd377eb3SJohn Baldwin else
1321cd377eb3SJohn Baldwin bytes = 4;
13227d9ef309SJohn Baldwin error = read_mem(vcpus[cur_vcpu], gpa, &val,
1323cd377eb3SJohn Baldwin bytes);
1324cd377eb3SJohn Baldwin if (error == 0) {
1325cd377eb3SJohn Baldwin if (!started) {
1326cd377eb3SJohn Baldwin start_packet();
1327cd377eb3SJohn Baldwin started = true;
1328cd377eb3SJohn Baldwin }
1329cd377eb3SJohn Baldwin gpa += bytes;
1330cd377eb3SJohn Baldwin gva += bytes;
1331cd377eb3SJohn Baldwin resid -= bytes;
1332cd377eb3SJohn Baldwin todo -= bytes;
1333cd377eb3SJohn Baldwin while (bytes > 0) {
1334cd377eb3SJohn Baldwin append_byte(val);
1335cd377eb3SJohn Baldwin val >>= 8;
1336cd377eb3SJohn Baldwin bytes--;
1337cd377eb3SJohn Baldwin }
1338cd377eb3SJohn Baldwin } else {
1339cd377eb3SJohn Baldwin if (started)
1340cd377eb3SJohn Baldwin finish_packet();
1341cd377eb3SJohn Baldwin else
1342cd377eb3SJohn Baldwin send_error(EFAULT);
1343cd377eb3SJohn Baldwin return;
1344cd377eb3SJohn Baldwin }
1345cd377eb3SJohn Baldwin }
1346cd377eb3SJohn Baldwin }
1347cd377eb3SJohn Baldwin assert(resid == 0 || gpa % getpagesize() == 0);
1348cd377eb3SJohn Baldwin }
1349cd377eb3SJohn Baldwin if (!started)
1350cd377eb3SJohn Baldwin start_packet();
1351cd377eb3SJohn Baldwin finish_packet();
1352cd377eb3SJohn Baldwin }
1353cd377eb3SJohn Baldwin
13541b52cd45SJohn Baldwin static void
gdb_write_mem(const uint8_t * data,size_t len)13551b52cd45SJohn Baldwin gdb_write_mem(const uint8_t *data, size_t len)
13561b52cd45SJohn Baldwin {
13571b52cd45SJohn Baldwin uint64_t gpa, gva, val;
13581b52cd45SJohn Baldwin uint8_t *cp;
13591b52cd45SJohn Baldwin size_t resid, todo, bytes;
13601b52cd45SJohn Baldwin int error;
13611b52cd45SJohn Baldwin
1362cfa2c78aSMark Johnston assert(len >= 1);
1363cfa2c78aSMark Johnston
13641b52cd45SJohn Baldwin /* Skip 'M' */
13651b52cd45SJohn Baldwin data += 1;
13661b52cd45SJohn Baldwin len -= 1;
13671b52cd45SJohn Baldwin
13681b52cd45SJohn Baldwin /* Parse and consume address. */
13691b52cd45SJohn Baldwin cp = memchr(data, ',', len);
13701b52cd45SJohn Baldwin if (cp == NULL || cp == data) {
13711b52cd45SJohn Baldwin send_error(EINVAL);
13721b52cd45SJohn Baldwin return;
13731b52cd45SJohn Baldwin }
13741b52cd45SJohn Baldwin gva = parse_integer(data, cp - data);
13751b52cd45SJohn Baldwin len -= (cp - data) + 1;
13761b52cd45SJohn Baldwin data += (cp - data) + 1;
13771b52cd45SJohn Baldwin
13781b52cd45SJohn Baldwin /* Parse and consume length. */
13791b52cd45SJohn Baldwin cp = memchr(data, ':', len);
13801b52cd45SJohn Baldwin if (cp == NULL || cp == data) {
13811b52cd45SJohn Baldwin send_error(EINVAL);
13821b52cd45SJohn Baldwin return;
13831b52cd45SJohn Baldwin }
13841b52cd45SJohn Baldwin resid = parse_integer(data, cp - data);
13851b52cd45SJohn Baldwin len -= (cp - data) + 1;
13861b52cd45SJohn Baldwin data += (cp - data) + 1;
13871b52cd45SJohn Baldwin
13881b52cd45SJohn Baldwin /* Verify the available bytes match the length. */
13891b52cd45SJohn Baldwin if (len != resid * 2) {
13901b52cd45SJohn Baldwin send_error(EINVAL);
13911b52cd45SJohn Baldwin return;
13921b52cd45SJohn Baldwin }
13931b52cd45SJohn Baldwin
13941b52cd45SJohn Baldwin while (resid > 0) {
13957d9ef309SJohn Baldwin error = guest_vaddr2paddr(vcpus[cur_vcpu], gva, &gpa);
13961b52cd45SJohn Baldwin if (error == -1) {
13971b52cd45SJohn Baldwin send_error(errno);
13981b52cd45SJohn Baldwin return;
13991b52cd45SJohn Baldwin }
14001b52cd45SJohn Baldwin if (error == 0) {
14011b52cd45SJohn Baldwin send_error(EFAULT);
14021b52cd45SJohn Baldwin return;
14031b52cd45SJohn Baldwin }
14041b52cd45SJohn Baldwin
14051b52cd45SJohn Baldwin /* Write bytes to current page. */
14061b52cd45SJohn Baldwin todo = getpagesize() - gpa % getpagesize();
14071b52cd45SJohn Baldwin if (todo > resid)
14081b52cd45SJohn Baldwin todo = resid;
14091b52cd45SJohn Baldwin
14101b52cd45SJohn Baldwin cp = paddr_guest2host(ctx, gpa, todo);
14111b52cd45SJohn Baldwin if (cp != NULL) {
14121b52cd45SJohn Baldwin /*
14131b52cd45SJohn Baldwin * If this page is guest RAM, write it a byte
14141b52cd45SJohn Baldwin * at a time.
14151b52cd45SJohn Baldwin */
14161b52cd45SJohn Baldwin while (todo > 0) {
14171b52cd45SJohn Baldwin assert(len >= 2);
14181b52cd45SJohn Baldwin *cp = parse_byte(data);
14191b52cd45SJohn Baldwin data += 2;
14201b52cd45SJohn Baldwin len -= 2;
14211b52cd45SJohn Baldwin cp++;
14221b52cd45SJohn Baldwin gpa++;
14231b52cd45SJohn Baldwin gva++;
14241b52cd45SJohn Baldwin resid--;
14251b52cd45SJohn Baldwin todo--;
14261b52cd45SJohn Baldwin }
14271b52cd45SJohn Baldwin } else {
14281b52cd45SJohn Baldwin /*
14291b52cd45SJohn Baldwin * If this page isn't guest RAM, try to handle
14301b52cd45SJohn Baldwin * it via MMIO. For MMIO requests, use
14311b52cd45SJohn Baldwin * aligned writes of words when possible.
14321b52cd45SJohn Baldwin */
14331b52cd45SJohn Baldwin while (todo > 0) {
14341b52cd45SJohn Baldwin if (gpa & 1 || todo == 1) {
14351b52cd45SJohn Baldwin bytes = 1;
14361b52cd45SJohn Baldwin val = parse_byte(data);
14371b52cd45SJohn Baldwin } else if (gpa & 2 || todo == 2) {
14381b52cd45SJohn Baldwin bytes = 2;
14394db23c74SJohn Baldwin val = be16toh(parse_integer(data, 4));
14401b52cd45SJohn Baldwin } else {
14411b52cd45SJohn Baldwin bytes = 4;
14424db23c74SJohn Baldwin val = be32toh(parse_integer(data, 8));
14431b52cd45SJohn Baldwin }
14447d9ef309SJohn Baldwin error = write_mem(vcpus[cur_vcpu], gpa, val,
14451b52cd45SJohn Baldwin bytes);
14461b52cd45SJohn Baldwin if (error == 0) {
14471b52cd45SJohn Baldwin gpa += bytes;
14481b52cd45SJohn Baldwin gva += bytes;
14491b52cd45SJohn Baldwin resid -= bytes;
14501b52cd45SJohn Baldwin todo -= bytes;
14511b52cd45SJohn Baldwin data += 2 * bytes;
14521b52cd45SJohn Baldwin len -= 2 * bytes;
14531b52cd45SJohn Baldwin } else {
14541b52cd45SJohn Baldwin send_error(EFAULT);
14551b52cd45SJohn Baldwin return;
14561b52cd45SJohn Baldwin }
14571b52cd45SJohn Baldwin }
14581b52cd45SJohn Baldwin }
14591b52cd45SJohn Baldwin assert(resid == 0 || gpa % getpagesize() == 0);
14601b52cd45SJohn Baldwin }
14611b52cd45SJohn Baldwin assert(len == 0);
14621b52cd45SJohn Baldwin send_ok();
14631b52cd45SJohn Baldwin }
14641b52cd45SJohn Baldwin
1465cd377eb3SJohn Baldwin static bool
set_breakpoint_caps(bool enable)1466cbd03a9dSJohn Baldwin set_breakpoint_caps(bool enable)
1467cbd03a9dSJohn Baldwin {
1468cbd03a9dSJohn Baldwin cpuset_t mask;
1469cbd03a9dSJohn Baldwin int vcpu;
1470cbd03a9dSJohn Baldwin
1471cbd03a9dSJohn Baldwin mask = vcpus_active;
1472cbd03a9dSJohn Baldwin while (!CPU_EMPTY(&mask)) {
1473cbd03a9dSJohn Baldwin vcpu = CPU_FFS(&mask) - 1;
1474cbd03a9dSJohn Baldwin CPU_CLR(vcpu, &mask);
1475a0ca4af9SMark Johnston if (vm_set_capability(vcpus[vcpu], GDB_BREAKPOINT_CAP,
1476cbd03a9dSJohn Baldwin enable ? 1 : 0) < 0)
1477cbd03a9dSJohn Baldwin return (false);
1478cbd03a9dSJohn Baldwin debug("$vCPU %d %sabled breakpoint exits\n", vcpu,
1479cbd03a9dSJohn Baldwin enable ? "en" : "dis");
1480cbd03a9dSJohn Baldwin }
1481cbd03a9dSJohn Baldwin return (true);
1482cbd03a9dSJohn Baldwin }
1483cbd03a9dSJohn Baldwin
1484cbd03a9dSJohn Baldwin static void
write_instr(uint8_t * dest,uint8_t * instr,size_t len)1485a0ca4af9SMark Johnston write_instr(uint8_t *dest, uint8_t *instr, size_t len)
1486a0ca4af9SMark Johnston {
1487a0ca4af9SMark Johnston memcpy(dest, instr, len);
1488a0ca4af9SMark Johnston #ifdef __arm64__
1489a0ca4af9SMark Johnston __asm __volatile(
1490a0ca4af9SMark Johnston "dc cvau, %0\n"
1491a0ca4af9SMark Johnston "dsb ish\n"
1492a0ca4af9SMark Johnston "ic ialluis\n"
1493a0ca4af9SMark Johnston "dsb ish\n"
1494a0ca4af9SMark Johnston : : "r" (dest) : "memory");
1495a0ca4af9SMark Johnston #endif
1496a0ca4af9SMark Johnston }
1497a0ca4af9SMark Johnston
1498a0ca4af9SMark Johnston static void
remove_all_sw_breakpoints(void)1499cbd03a9dSJohn Baldwin remove_all_sw_breakpoints(void)
1500cbd03a9dSJohn Baldwin {
1501cbd03a9dSJohn Baldwin struct breakpoint *bp, *nbp;
1502cbd03a9dSJohn Baldwin uint8_t *cp;
1503cbd03a9dSJohn Baldwin
1504cbd03a9dSJohn Baldwin if (TAILQ_EMPTY(&breakpoints))
1505cbd03a9dSJohn Baldwin return;
1506cbd03a9dSJohn Baldwin
1507cbd03a9dSJohn Baldwin TAILQ_FOREACH_SAFE(bp, &breakpoints, link, nbp) {
1508cbd03a9dSJohn Baldwin debug("remove breakpoint at %#lx\n", bp->gpa);
15095f086566SMark Johnston cp = paddr_guest2host(ctx, bp->gpa, sizeof(bp->shadow_inst));
1510a0ca4af9SMark Johnston write_instr(cp, bp->shadow_inst, sizeof(bp->shadow_inst));
1511cbd03a9dSJohn Baldwin TAILQ_REMOVE(&breakpoints, bp, link);
1512cbd03a9dSJohn Baldwin free(bp);
1513cbd03a9dSJohn Baldwin }
1514cbd03a9dSJohn Baldwin TAILQ_INIT(&breakpoints);
1515cbd03a9dSJohn Baldwin set_breakpoint_caps(false);
1516cbd03a9dSJohn Baldwin }
1517cbd03a9dSJohn Baldwin
1518cbd03a9dSJohn Baldwin static void
update_sw_breakpoint(uint64_t gva,int kind,bool insert)1519cbd03a9dSJohn Baldwin update_sw_breakpoint(uint64_t gva, int kind, bool insert)
1520cbd03a9dSJohn Baldwin {
1521cbd03a9dSJohn Baldwin struct breakpoint *bp;
1522cbd03a9dSJohn Baldwin uint64_t gpa;
1523cbd03a9dSJohn Baldwin uint8_t *cp;
1524cbd03a9dSJohn Baldwin int error;
1525cbd03a9dSJohn Baldwin
15265f086566SMark Johnston if (kind != GDB_BP_SIZE) {
1527cbd03a9dSJohn Baldwin send_error(EINVAL);
1528cbd03a9dSJohn Baldwin return;
1529cbd03a9dSJohn Baldwin }
1530cbd03a9dSJohn Baldwin
15317d9ef309SJohn Baldwin error = guest_vaddr2paddr(vcpus[cur_vcpu], gva, &gpa);
1532cbd03a9dSJohn Baldwin if (error == -1) {
1533cbd03a9dSJohn Baldwin send_error(errno);
1534cbd03a9dSJohn Baldwin return;
1535cbd03a9dSJohn Baldwin }
1536cbd03a9dSJohn Baldwin if (error == 0) {
1537cbd03a9dSJohn Baldwin send_error(EFAULT);
1538cbd03a9dSJohn Baldwin return;
1539cbd03a9dSJohn Baldwin }
1540cbd03a9dSJohn Baldwin
15415f086566SMark Johnston cp = paddr_guest2host(ctx, gpa, sizeof(bp->shadow_inst));
1542cbd03a9dSJohn Baldwin
1543cbd03a9dSJohn Baldwin /* Only permit breakpoints in guest RAM. */
1544cbd03a9dSJohn Baldwin if (cp == NULL) {
1545cbd03a9dSJohn Baldwin send_error(EFAULT);
1546cbd03a9dSJohn Baldwin return;
1547cbd03a9dSJohn Baldwin }
1548cbd03a9dSJohn Baldwin
1549cbd03a9dSJohn Baldwin /* Find any existing breakpoint. */
1550cbd03a9dSJohn Baldwin bp = find_breakpoint(gpa);
1551cbd03a9dSJohn Baldwin
1552cbd03a9dSJohn Baldwin /*
1553cbd03a9dSJohn Baldwin * Silently ignore duplicate commands since the protocol
1554cbd03a9dSJohn Baldwin * requires these packets to be idempotent.
1555cbd03a9dSJohn Baldwin */
1556cbd03a9dSJohn Baldwin if (insert) {
1557cbd03a9dSJohn Baldwin if (bp == NULL) {
1558cbd03a9dSJohn Baldwin if (TAILQ_EMPTY(&breakpoints) &&
1559cbd03a9dSJohn Baldwin !set_breakpoint_caps(true)) {
1560cbd03a9dSJohn Baldwin send_empty_response();
1561cbd03a9dSJohn Baldwin return;
1562cbd03a9dSJohn Baldwin }
1563cbd03a9dSJohn Baldwin bp = malloc(sizeof(*bp));
1564cbd03a9dSJohn Baldwin bp->gpa = gpa;
15655f086566SMark Johnston memcpy(bp->shadow_inst, cp, sizeof(bp->shadow_inst));
1566a0ca4af9SMark Johnston write_instr(cp, GDB_BP_INSTR, sizeof(bp->shadow_inst));
1567cbd03a9dSJohn Baldwin TAILQ_INSERT_TAIL(&breakpoints, bp, link);
1568cbd03a9dSJohn Baldwin debug("new breakpoint at %#lx\n", gpa);
1569cbd03a9dSJohn Baldwin }
1570cbd03a9dSJohn Baldwin } else {
1571cbd03a9dSJohn Baldwin if (bp != NULL) {
1572cbd03a9dSJohn Baldwin debug("remove breakpoint at %#lx\n", gpa);
1573a0ca4af9SMark Johnston write_instr(cp, bp->shadow_inst,
1574a0ca4af9SMark Johnston sizeof(bp->shadow_inst));
1575cbd03a9dSJohn Baldwin TAILQ_REMOVE(&breakpoints, bp, link);
1576cbd03a9dSJohn Baldwin free(bp);
1577cbd03a9dSJohn Baldwin if (TAILQ_EMPTY(&breakpoints))
1578cbd03a9dSJohn Baldwin set_breakpoint_caps(false);
1579cbd03a9dSJohn Baldwin }
1580cbd03a9dSJohn Baldwin }
1581cbd03a9dSJohn Baldwin send_ok();
1582cbd03a9dSJohn Baldwin }
1583cbd03a9dSJohn Baldwin
1584cbd03a9dSJohn Baldwin static void
parse_breakpoint(const uint8_t * data,size_t len)1585cbd03a9dSJohn Baldwin parse_breakpoint(const uint8_t *data, size_t len)
1586cbd03a9dSJohn Baldwin {
1587cbd03a9dSJohn Baldwin uint64_t gva;
1588cbd03a9dSJohn Baldwin uint8_t *cp;
1589cbd03a9dSJohn Baldwin bool insert;
1590cbd03a9dSJohn Baldwin int kind, type;
1591cbd03a9dSJohn Baldwin
1592cbd03a9dSJohn Baldwin insert = data[0] == 'Z';
1593cbd03a9dSJohn Baldwin
1594cbd03a9dSJohn Baldwin /* Skip 'Z/z' */
1595cbd03a9dSJohn Baldwin data += 1;
1596cbd03a9dSJohn Baldwin len -= 1;
1597cbd03a9dSJohn Baldwin
1598cbd03a9dSJohn Baldwin /* Parse and consume type. */
1599cbd03a9dSJohn Baldwin cp = memchr(data, ',', len);
1600cbd03a9dSJohn Baldwin if (cp == NULL || cp == data) {
1601cbd03a9dSJohn Baldwin send_error(EINVAL);
1602cbd03a9dSJohn Baldwin return;
1603cbd03a9dSJohn Baldwin }
1604cbd03a9dSJohn Baldwin type = parse_integer(data, cp - data);
1605cbd03a9dSJohn Baldwin len -= (cp - data) + 1;
1606cbd03a9dSJohn Baldwin data += (cp - data) + 1;
1607cbd03a9dSJohn Baldwin
1608cbd03a9dSJohn Baldwin /* Parse and consume address. */
1609cbd03a9dSJohn Baldwin cp = memchr(data, ',', len);
1610cbd03a9dSJohn Baldwin if (cp == NULL || cp == data) {
1611cbd03a9dSJohn Baldwin send_error(EINVAL);
1612cbd03a9dSJohn Baldwin return;
1613cbd03a9dSJohn Baldwin }
1614cbd03a9dSJohn Baldwin gva = parse_integer(data, cp - data);
1615cbd03a9dSJohn Baldwin len -= (cp - data) + 1;
1616cbd03a9dSJohn Baldwin data += (cp - data) + 1;
1617cbd03a9dSJohn Baldwin
1618cbd03a9dSJohn Baldwin /* Parse and consume kind. */
1619cbd03a9dSJohn Baldwin cp = memchr(data, ';', len);
1620cbd03a9dSJohn Baldwin if (cp == data) {
1621cbd03a9dSJohn Baldwin send_error(EINVAL);
1622cbd03a9dSJohn Baldwin return;
1623cbd03a9dSJohn Baldwin }
1624cbd03a9dSJohn Baldwin if (cp != NULL) {
1625cbd03a9dSJohn Baldwin /*
1626cbd03a9dSJohn Baldwin * We do not advertise support for either the
1627cbd03a9dSJohn Baldwin * ConditionalBreakpoints or BreakpointCommands
1628cbd03a9dSJohn Baldwin * features, so we should not be getting conditions or
1629cbd03a9dSJohn Baldwin * commands from the remote end.
1630cbd03a9dSJohn Baldwin */
1631cbd03a9dSJohn Baldwin send_empty_response();
1632cbd03a9dSJohn Baldwin return;
1633cbd03a9dSJohn Baldwin }
1634cbd03a9dSJohn Baldwin kind = parse_integer(data, len);
1635cbd03a9dSJohn Baldwin data += len;
1636cbd03a9dSJohn Baldwin len = 0;
1637cbd03a9dSJohn Baldwin
1638cbd03a9dSJohn Baldwin switch (type) {
1639cbd03a9dSJohn Baldwin case 0:
1640cbd03a9dSJohn Baldwin update_sw_breakpoint(gva, kind, insert);
1641cbd03a9dSJohn Baldwin break;
1642cbd03a9dSJohn Baldwin default:
1643cbd03a9dSJohn Baldwin send_empty_response();
1644cbd03a9dSJohn Baldwin break;
1645cbd03a9dSJohn Baldwin }
1646cbd03a9dSJohn Baldwin }
1647cbd03a9dSJohn Baldwin
1648cbd03a9dSJohn Baldwin static bool
command_equals(const uint8_t * data,size_t len,const char * cmd)1649cd377eb3SJohn Baldwin command_equals(const uint8_t *data, size_t len, const char *cmd)
1650cd377eb3SJohn Baldwin {
1651cd377eb3SJohn Baldwin
1652cd377eb3SJohn Baldwin if (strlen(cmd) > len)
1653cd377eb3SJohn Baldwin return (false);
1654cd377eb3SJohn Baldwin return (memcmp(data, cmd, strlen(cmd)) == 0);
1655cd377eb3SJohn Baldwin }
1656cd377eb3SJohn Baldwin
1657cd377eb3SJohn Baldwin static void
check_features(const uint8_t * data,size_t len)165807e007e1SJohn Baldwin check_features(const uint8_t *data, size_t len)
165907e007e1SJohn Baldwin {
166007e007e1SJohn Baldwin char *feature, *next_feature, *str, *value;
166107e007e1SJohn Baldwin bool supported;
166207e007e1SJohn Baldwin
166307e007e1SJohn Baldwin str = malloc(len + 1);
166407e007e1SJohn Baldwin memcpy(str, data, len);
166507e007e1SJohn Baldwin str[len] = '\0';
166607e007e1SJohn Baldwin next_feature = str;
166707e007e1SJohn Baldwin
166807e007e1SJohn Baldwin while ((feature = strsep(&next_feature, ";")) != NULL) {
166907e007e1SJohn Baldwin /*
167007e007e1SJohn Baldwin * Null features shouldn't exist, but skip if they
167107e007e1SJohn Baldwin * do.
167207e007e1SJohn Baldwin */
167307e007e1SJohn Baldwin if (strcmp(feature, "") == 0)
167407e007e1SJohn Baldwin continue;
167507e007e1SJohn Baldwin
167607e007e1SJohn Baldwin /*
167707e007e1SJohn Baldwin * Look for the value or supported / not supported
167807e007e1SJohn Baldwin * flag.
167907e007e1SJohn Baldwin */
168007e007e1SJohn Baldwin value = strchr(feature, '=');
168107e007e1SJohn Baldwin if (value != NULL) {
168207e007e1SJohn Baldwin *value = '\0';
168307e007e1SJohn Baldwin value++;
168407e007e1SJohn Baldwin supported = true;
168507e007e1SJohn Baldwin } else {
168607e007e1SJohn Baldwin value = feature + strlen(feature) - 1;
168707e007e1SJohn Baldwin switch (*value) {
168807e007e1SJohn Baldwin case '+':
168907e007e1SJohn Baldwin supported = true;
169007e007e1SJohn Baldwin break;
169107e007e1SJohn Baldwin case '-':
169207e007e1SJohn Baldwin supported = false;
169307e007e1SJohn Baldwin break;
169407e007e1SJohn Baldwin default:
169507e007e1SJohn Baldwin /*
169607e007e1SJohn Baldwin * This is really a protocol error,
169707e007e1SJohn Baldwin * but we just ignore malformed
169807e007e1SJohn Baldwin * features for ease of
169907e007e1SJohn Baldwin * implementation.
170007e007e1SJohn Baldwin */
170107e007e1SJohn Baldwin continue;
170207e007e1SJohn Baldwin }
170307e007e1SJohn Baldwin value = NULL;
170407e007e1SJohn Baldwin }
170507e007e1SJohn Baldwin
1706cbd03a9dSJohn Baldwin if (strcmp(feature, "swbreak") == 0)
1707cbd03a9dSJohn Baldwin swbreak_enabled = supported;
170807e007e1SJohn Baldwin }
170907e007e1SJohn Baldwin free(str);
171007e007e1SJohn Baldwin
171107e007e1SJohn Baldwin start_packet();
171207e007e1SJohn Baldwin
171307e007e1SJohn Baldwin /* This is an arbitrary limit. */
171407e007e1SJohn Baldwin append_string("PacketSize=4096");
1715cbd03a9dSJohn Baldwin append_string(";swbreak+");
1716f81cdf24SMark Johnston append_string(";qXfer:features:read+");
171707e007e1SJohn Baldwin finish_packet();
171807e007e1SJohn Baldwin }
171907e007e1SJohn Baldwin
172007e007e1SJohn Baldwin static void
gdb_query(const uint8_t * data,size_t len)1721cd377eb3SJohn Baldwin gdb_query(const uint8_t *data, size_t len)
1722cd377eb3SJohn Baldwin {
1723cd377eb3SJohn Baldwin
1724cd377eb3SJohn Baldwin /*
1725cd377eb3SJohn Baldwin * TODO:
1726cd377eb3SJohn Baldwin * - qSearch
1727cd377eb3SJohn Baldwin */
1728cd377eb3SJohn Baldwin if (command_equals(data, len, "qAttached")) {
1729cd377eb3SJohn Baldwin start_packet();
1730cd377eb3SJohn Baldwin append_char('1');
1731cd377eb3SJohn Baldwin finish_packet();
1732cd377eb3SJohn Baldwin } else if (command_equals(data, len, "qC")) {
1733cd377eb3SJohn Baldwin start_packet();
1734cd377eb3SJohn Baldwin append_string("QC");
1735cd377eb3SJohn Baldwin append_integer(cur_vcpu + 1);
1736cd377eb3SJohn Baldwin finish_packet();
1737cd377eb3SJohn Baldwin } else if (command_equals(data, len, "qfThreadInfo")) {
1738cd377eb3SJohn Baldwin cpuset_t mask;
1739cd377eb3SJohn Baldwin bool first;
1740cd377eb3SJohn Baldwin int vcpu;
1741cd377eb3SJohn Baldwin
1742cd377eb3SJohn Baldwin if (CPU_EMPTY(&vcpus_active)) {
1743cd377eb3SJohn Baldwin send_error(EINVAL);
1744cd377eb3SJohn Baldwin return;
1745cd377eb3SJohn Baldwin }
1746cd377eb3SJohn Baldwin mask = vcpus_active;
1747cd377eb3SJohn Baldwin start_packet();
1748cd377eb3SJohn Baldwin append_char('m');
1749cd377eb3SJohn Baldwin first = true;
1750cd377eb3SJohn Baldwin while (!CPU_EMPTY(&mask)) {
1751cd377eb3SJohn Baldwin vcpu = CPU_FFS(&mask) - 1;
1752cd377eb3SJohn Baldwin CPU_CLR(vcpu, &mask);
1753cd377eb3SJohn Baldwin if (first)
1754cd377eb3SJohn Baldwin first = false;
1755cd377eb3SJohn Baldwin else
1756cd377eb3SJohn Baldwin append_char(',');
1757cd377eb3SJohn Baldwin append_integer(vcpu + 1);
1758cd377eb3SJohn Baldwin }
1759cd377eb3SJohn Baldwin finish_packet();
1760cd377eb3SJohn Baldwin } else if (command_equals(data, len, "qsThreadInfo")) {
1761cd377eb3SJohn Baldwin start_packet();
1762cd377eb3SJohn Baldwin append_char('l');
1763cd377eb3SJohn Baldwin finish_packet();
176407e007e1SJohn Baldwin } else if (command_equals(data, len, "qSupported")) {
176507e007e1SJohn Baldwin data += strlen("qSupported");
176607e007e1SJohn Baldwin len -= strlen("qSupported");
176707e007e1SJohn Baldwin check_features(data, len);
1768cd377eb3SJohn Baldwin } else if (command_equals(data, len, "qThreadExtraInfo")) {
1769cd377eb3SJohn Baldwin char buf[16];
1770cd377eb3SJohn Baldwin int tid;
1771cd377eb3SJohn Baldwin
1772cd377eb3SJohn Baldwin data += strlen("qThreadExtraInfo");
1773cd377eb3SJohn Baldwin len -= strlen("qThreadExtraInfo");
1774cfa2c78aSMark Johnston if (len == 0 || *data != ',') {
1775cd377eb3SJohn Baldwin send_error(EINVAL);
1776cd377eb3SJohn Baldwin return;
1777cd377eb3SJohn Baldwin }
1778cd377eb3SJohn Baldwin tid = parse_threadid(data + 1, len - 1);
1779cd377eb3SJohn Baldwin if (tid <= 0 || !CPU_ISSET(tid - 1, &vcpus_active)) {
1780cd377eb3SJohn Baldwin send_error(EINVAL);
1781cd377eb3SJohn Baldwin return;
1782cd377eb3SJohn Baldwin }
1783cd377eb3SJohn Baldwin
1784cd377eb3SJohn Baldwin snprintf(buf, sizeof(buf), "vCPU %d", tid - 1);
1785cd377eb3SJohn Baldwin start_packet();
1786cd377eb3SJohn Baldwin append_asciihex(buf);
1787cd377eb3SJohn Baldwin finish_packet();
1788f81cdf24SMark Johnston } else if (command_equals(data, len, "qXfer:features:read:")) {
1789f81cdf24SMark Johnston struct stat sb;
1790f81cdf24SMark Johnston const char *xml;
1791f81cdf24SMark Johnston const uint8_t *pathend;
1792f81cdf24SMark Johnston char buf[64], path[PATH_MAX];
1793f81cdf24SMark Johnston size_t xmllen;
1794f81cdf24SMark Johnston unsigned int doff, dlen;
1795f81cdf24SMark Johnston int fd;
1796f81cdf24SMark Johnston
1797f81cdf24SMark Johnston data += strlen("qXfer:features:read:");
1798f81cdf24SMark Johnston len -= strlen("qXfer:features:read:");
1799f81cdf24SMark Johnston
1800f81cdf24SMark Johnston pathend = memchr(data, ':', len);
1801f81cdf24SMark Johnston if (pathend == NULL ||
1802f81cdf24SMark Johnston (size_t)(pathend - data) >= sizeof(path) - 1) {
1803f81cdf24SMark Johnston send_error(EINVAL);
1804f81cdf24SMark Johnston return;
1805f81cdf24SMark Johnston }
1806f81cdf24SMark Johnston memcpy(path, data, pathend - data);
1807f81cdf24SMark Johnston path[pathend - data] = '\0';
1808f81cdf24SMark Johnston data += (pathend - data) + 1;
1809f81cdf24SMark Johnston len -= (pathend - data) + 1;
1810f81cdf24SMark Johnston
1811f81cdf24SMark Johnston if (len > sizeof(buf) - 1) {
1812f81cdf24SMark Johnston send_error(EINVAL);
1813f81cdf24SMark Johnston return;
1814f81cdf24SMark Johnston }
1815f81cdf24SMark Johnston memcpy(buf, data, len);
1816f81cdf24SMark Johnston buf[len] = '\0';
1817f81cdf24SMark Johnston if (sscanf(buf, "%x,%x", &doff, &dlen) != 2) {
1818f81cdf24SMark Johnston send_error(EINVAL);
1819f81cdf24SMark Johnston return;
1820f81cdf24SMark Johnston }
1821f81cdf24SMark Johnston
1822f81cdf24SMark Johnston fd = openat(xml_dfd, path, O_RDONLY | O_RESOLVE_BENEATH);
1823f81cdf24SMark Johnston if (fd < 0) {
1824f81cdf24SMark Johnston send_error(errno);
1825f81cdf24SMark Johnston return;
1826f81cdf24SMark Johnston }
1827f81cdf24SMark Johnston if (fstat(fd, &sb) < 0) {
1828f81cdf24SMark Johnston send_error(errno);
1829f81cdf24SMark Johnston close(fd);
1830f81cdf24SMark Johnston return;
1831f81cdf24SMark Johnston }
1832f81cdf24SMark Johnston xml = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
1833f81cdf24SMark Johnston if (xml == MAP_FAILED) {
1834f81cdf24SMark Johnston send_error(errno);
1835f81cdf24SMark Johnston close(fd);
1836f81cdf24SMark Johnston return;
1837f81cdf24SMark Johnston }
1838f81cdf24SMark Johnston close(fd);
1839f81cdf24SMark Johnston xmllen = sb.st_size;
1840f81cdf24SMark Johnston
1841f81cdf24SMark Johnston start_packet();
1842f81cdf24SMark Johnston if (doff >= xmllen) {
1843f81cdf24SMark Johnston append_char('l');
1844f81cdf24SMark Johnston } else if (doff + dlen >= xmllen) {
1845f81cdf24SMark Johnston append_char('l');
1846b4fb9479SMark Johnston append_binary_data(xml + doff, xmllen - doff);
1847f81cdf24SMark Johnston } else {
1848f81cdf24SMark Johnston append_char('m');
1849b4fb9479SMark Johnston append_binary_data(xml + doff, dlen);
1850f81cdf24SMark Johnston }
1851f81cdf24SMark Johnston finish_packet();
1852f81cdf24SMark Johnston (void)munmap(__DECONST(void *, xml), xmllen);
1853cd377eb3SJohn Baldwin } else
1854cd377eb3SJohn Baldwin send_empty_response();
1855cd377eb3SJohn Baldwin }
1856cd377eb3SJohn Baldwin
1857cd377eb3SJohn Baldwin static void
handle_command(const uint8_t * data,size_t len)1858cd377eb3SJohn Baldwin handle_command(const uint8_t *data, size_t len)
1859cd377eb3SJohn Baldwin {
1860cd377eb3SJohn Baldwin
1861cd377eb3SJohn Baldwin /* Reject packets with a sequence-id. */
1862cd377eb3SJohn Baldwin if (len >= 3 && data[0] >= '0' && data[0] <= '9' &&
1863cd377eb3SJohn Baldwin data[0] >= '0' && data[0] <= '9' && data[2] == ':') {
1864cd377eb3SJohn Baldwin send_empty_response();
1865cd377eb3SJohn Baldwin return;
1866cd377eb3SJohn Baldwin }
1867cd377eb3SJohn Baldwin
1868cd377eb3SJohn Baldwin switch (*data) {
1869cd377eb3SJohn Baldwin case 'c':
1870cd377eb3SJohn Baldwin if (len != 1) {
1871cd377eb3SJohn Baldwin send_error(EINVAL);
1872cd377eb3SJohn Baldwin break;
1873cd377eb3SJohn Baldwin }
1874cd377eb3SJohn Baldwin
1875cbd03a9dSJohn Baldwin discard_stop();
1876cd377eb3SJohn Baldwin gdb_resume_vcpus();
1877cd377eb3SJohn Baldwin break;
1878cd377eb3SJohn Baldwin case 'D':
1879cd377eb3SJohn Baldwin send_ok();
1880cd377eb3SJohn Baldwin
1881cd377eb3SJohn Baldwin /* TODO: Resume any stopped CPUs. */
1882cd377eb3SJohn Baldwin break;
1883e6516294SMark Johnston case 'g':
1884cd377eb3SJohn Baldwin gdb_read_regs();
1885cd377eb3SJohn Baldwin break;
1886e6516294SMark Johnston case 'p':
1887e6516294SMark Johnston gdb_read_one_reg(data + 1, len - 1);
1888e6516294SMark Johnston break;
1889cd377eb3SJohn Baldwin case 'H': {
1890cd377eb3SJohn Baldwin int tid;
1891cd377eb3SJohn Baldwin
1892cfa2c78aSMark Johnston if (len < 2 || (data[1] != 'g' && data[1] != 'c')) {
1893cd377eb3SJohn Baldwin send_error(EINVAL);
1894cd377eb3SJohn Baldwin break;
1895cd377eb3SJohn Baldwin }
1896cd377eb3SJohn Baldwin tid = parse_threadid(data + 2, len - 2);
1897cd377eb3SJohn Baldwin if (tid == -2) {
1898cd377eb3SJohn Baldwin send_error(EINVAL);
1899cd377eb3SJohn Baldwin break;
1900cd377eb3SJohn Baldwin }
1901cd377eb3SJohn Baldwin
1902cd377eb3SJohn Baldwin if (CPU_EMPTY(&vcpus_active)) {
1903cd377eb3SJohn Baldwin send_error(EINVAL);
1904cd377eb3SJohn Baldwin break;
1905cd377eb3SJohn Baldwin }
1906cd377eb3SJohn Baldwin if (tid == -1 || tid == 0)
1907cd377eb3SJohn Baldwin cur_vcpu = CPU_FFS(&vcpus_active) - 1;
1908cd377eb3SJohn Baldwin else if (CPU_ISSET(tid - 1, &vcpus_active))
1909cd377eb3SJohn Baldwin cur_vcpu = tid - 1;
1910cd377eb3SJohn Baldwin else {
1911cd377eb3SJohn Baldwin send_error(EINVAL);
1912cd377eb3SJohn Baldwin break;
1913cd377eb3SJohn Baldwin }
1914cd377eb3SJohn Baldwin send_ok();
1915cd377eb3SJohn Baldwin break;
1916cd377eb3SJohn Baldwin }
1917cd377eb3SJohn Baldwin case 'm':
1918cd377eb3SJohn Baldwin gdb_read_mem(data, len);
1919cd377eb3SJohn Baldwin break;
19201b52cd45SJohn Baldwin case 'M':
19211b52cd45SJohn Baldwin gdb_write_mem(data, len);
19221b52cd45SJohn Baldwin break;
1923cd377eb3SJohn Baldwin case 'T': {
1924cd377eb3SJohn Baldwin int tid;
1925cd377eb3SJohn Baldwin
1926cd377eb3SJohn Baldwin tid = parse_threadid(data + 1, len - 1);
1927cd377eb3SJohn Baldwin if (tid <= 0 || !CPU_ISSET(tid - 1, &vcpus_active)) {
1928cd377eb3SJohn Baldwin send_error(EINVAL);
1929cd377eb3SJohn Baldwin return;
1930cd377eb3SJohn Baldwin }
1931cd377eb3SJohn Baldwin send_ok();
1932cd377eb3SJohn Baldwin break;
1933cd377eb3SJohn Baldwin }
1934cd377eb3SJohn Baldwin case 'q':
1935cd377eb3SJohn Baldwin gdb_query(data, len);
1936cd377eb3SJohn Baldwin break;
1937cd377eb3SJohn Baldwin case 's':
1938cd377eb3SJohn Baldwin if (len != 1) {
1939cd377eb3SJohn Baldwin send_error(EINVAL);
1940cd377eb3SJohn Baldwin break;
1941cd377eb3SJohn Baldwin }
1942cd377eb3SJohn Baldwin
1943cd377eb3SJohn Baldwin /* Don't send a reply until a stop occurs. */
19447d9ef309SJohn Baldwin if (!gdb_step_vcpu(vcpus[cur_vcpu])) {
1945cd377eb3SJohn Baldwin send_error(EOPNOTSUPP);
1946cd377eb3SJohn Baldwin break;
1947cd377eb3SJohn Baldwin }
1948cd377eb3SJohn Baldwin break;
1949cbd03a9dSJohn Baldwin case 'z':
1950cbd03a9dSJohn Baldwin case 'Z':
1951cbd03a9dSJohn Baldwin parse_breakpoint(data, len);
1952cbd03a9dSJohn Baldwin break;
1953cd377eb3SJohn Baldwin case '?':
1954cbd03a9dSJohn Baldwin report_stop(false);
1955cd377eb3SJohn Baldwin break;
1956cd377eb3SJohn Baldwin case 'G': /* TODO */
1957cd377eb3SJohn Baldwin case 'v':
1958cd377eb3SJohn Baldwin /* Handle 'vCont' */
1959cd377eb3SJohn Baldwin /* 'vCtrlC' */
1960cd377eb3SJohn Baldwin case 'P': /* TODO */
1961cd377eb3SJohn Baldwin case 'Q': /* TODO */
1962cd377eb3SJohn Baldwin case 't': /* TODO */
1963cd377eb3SJohn Baldwin case 'X': /* TODO */
1964cd377eb3SJohn Baldwin default:
1965cd377eb3SJohn Baldwin send_empty_response();
1966cd377eb3SJohn Baldwin }
1967cd377eb3SJohn Baldwin }
1968cd377eb3SJohn Baldwin
1969cd377eb3SJohn Baldwin /* Check for a valid packet in the command buffer. */
1970cd377eb3SJohn Baldwin static void
check_command(int fd)1971cd377eb3SJohn Baldwin check_command(int fd)
1972cd377eb3SJohn Baldwin {
1973cd377eb3SJohn Baldwin uint8_t *head, *hash, *p, sum;
1974cd377eb3SJohn Baldwin size_t avail, plen;
1975cd377eb3SJohn Baldwin
1976cd377eb3SJohn Baldwin for (;;) {
1977cd377eb3SJohn Baldwin avail = cur_comm.len;
1978cd377eb3SJohn Baldwin if (avail == 0)
1979cd377eb3SJohn Baldwin return;
1980cd377eb3SJohn Baldwin head = io_buffer_head(&cur_comm);
1981cd377eb3SJohn Baldwin switch (*head) {
1982cd377eb3SJohn Baldwin case 0x03:
1983cd377eb3SJohn Baldwin debug("<- Ctrl-C\n");
1984cd377eb3SJohn Baldwin io_buffer_consume(&cur_comm, 1);
1985cd377eb3SJohn Baldwin
1986cd377eb3SJohn Baldwin gdb_suspend_vcpus();
1987cd377eb3SJohn Baldwin break;
1988cd377eb3SJohn Baldwin case '+':
1989cd377eb3SJohn Baldwin /* ACK of previous response. */
1990cd377eb3SJohn Baldwin debug("<- +\n");
1991cd377eb3SJohn Baldwin if (response_pending())
1992cd377eb3SJohn Baldwin io_buffer_reset(&cur_resp);
1993cd377eb3SJohn Baldwin io_buffer_consume(&cur_comm, 1);
1994cbd03a9dSJohn Baldwin if (stopped_vcpu != -1 && report_next_stop) {
1995cbd03a9dSJohn Baldwin report_stop(true);
1996cd377eb3SJohn Baldwin send_pending_data(fd);
1997cd377eb3SJohn Baldwin }
1998cd377eb3SJohn Baldwin break;
1999cd377eb3SJohn Baldwin case '-':
2000cd377eb3SJohn Baldwin /* NACK of previous response. */
2001cd377eb3SJohn Baldwin debug("<- -\n");
2002cd377eb3SJohn Baldwin if (response_pending()) {
2003cd377eb3SJohn Baldwin cur_resp.len += cur_resp.start;
2004cd377eb3SJohn Baldwin cur_resp.start = 0;
2005cd377eb3SJohn Baldwin if (cur_resp.data[0] == '+')
2006cd377eb3SJohn Baldwin io_buffer_advance(&cur_resp, 1);
2007cd377eb3SJohn Baldwin debug("-> %.*s\n", (int)cur_resp.len,
2008cd377eb3SJohn Baldwin io_buffer_head(&cur_resp));
2009cd377eb3SJohn Baldwin }
2010cd377eb3SJohn Baldwin io_buffer_consume(&cur_comm, 1);
2011cd377eb3SJohn Baldwin send_pending_data(fd);
2012cd377eb3SJohn Baldwin break;
2013cd377eb3SJohn Baldwin case '$':
2014cd377eb3SJohn Baldwin /* Packet. */
2015cd377eb3SJohn Baldwin
2016cd377eb3SJohn Baldwin if (response_pending()) {
2017cd377eb3SJohn Baldwin warnx("New GDB command while response in "
2018cd377eb3SJohn Baldwin "progress");
2019cd377eb3SJohn Baldwin io_buffer_reset(&cur_resp);
2020cd377eb3SJohn Baldwin }
2021cd377eb3SJohn Baldwin
2022cd377eb3SJohn Baldwin /* Is packet complete? */
2023cd377eb3SJohn Baldwin hash = memchr(head, '#', avail);
2024cd377eb3SJohn Baldwin if (hash == NULL)
2025cd377eb3SJohn Baldwin return;
2026cd377eb3SJohn Baldwin plen = (hash - head + 1) + 2;
2027cd377eb3SJohn Baldwin if (avail < plen)
2028cd377eb3SJohn Baldwin return;
2029cd377eb3SJohn Baldwin debug("<- %.*s\n", (int)plen, head);
2030cd377eb3SJohn Baldwin
2031cd377eb3SJohn Baldwin /* Verify checksum. */
2032cd377eb3SJohn Baldwin for (sum = 0, p = head + 1; p < hash; p++)
2033cd377eb3SJohn Baldwin sum += *p;
2034cd377eb3SJohn Baldwin if (sum != parse_byte(hash + 1)) {
2035cd377eb3SJohn Baldwin io_buffer_consume(&cur_comm, plen);
2036cd377eb3SJohn Baldwin debug("-> -\n");
2037cd377eb3SJohn Baldwin send_char('-');
2038cd377eb3SJohn Baldwin send_pending_data(fd);
2039cd377eb3SJohn Baldwin break;
2040cd377eb3SJohn Baldwin }
2041cd377eb3SJohn Baldwin send_char('+');
2042cd377eb3SJohn Baldwin
2043cd377eb3SJohn Baldwin handle_command(head + 1, hash - (head + 1));
2044cd377eb3SJohn Baldwin io_buffer_consume(&cur_comm, plen);
2045cd377eb3SJohn Baldwin if (!response_pending())
2046cd377eb3SJohn Baldwin debug("-> +\n");
2047cd377eb3SJohn Baldwin send_pending_data(fd);
2048cd377eb3SJohn Baldwin break;
2049cd377eb3SJohn Baldwin default:
2050cd377eb3SJohn Baldwin /* XXX: Possibly drop connection instead. */
2051cd377eb3SJohn Baldwin debug("-> %02x\n", *head);
2052cd377eb3SJohn Baldwin io_buffer_consume(&cur_comm, 1);
2053cd377eb3SJohn Baldwin break;
2054cd377eb3SJohn Baldwin }
2055cd377eb3SJohn Baldwin }
2056cd377eb3SJohn Baldwin }
2057cd377eb3SJohn Baldwin
2058cd377eb3SJohn Baldwin static void
gdb_readable(int fd,enum ev_type event __unused,void * arg __unused)205998d920d9SMark Johnston gdb_readable(int fd, enum ev_type event __unused, void *arg __unused)
2060cd377eb3SJohn Baldwin {
2061ed721684SMark Johnston size_t pending;
2062cd377eb3SJohn Baldwin ssize_t nread;
2063ed721684SMark Johnston int n;
2064cd377eb3SJohn Baldwin
2065ed721684SMark Johnston if (ioctl(fd, FIONREAD, &n) == -1) {
2066cd377eb3SJohn Baldwin warn("FIONREAD on GDB socket");
2067cd377eb3SJohn Baldwin return;
2068cd377eb3SJohn Baldwin }
2069ed721684SMark Johnston assert(n >= 0);
2070ed721684SMark Johnston pending = n;
2071cd377eb3SJohn Baldwin
2072cd377eb3SJohn Baldwin /*
2073cd377eb3SJohn Baldwin * 'pending' might be zero due to EOF. We need to call read
2074cd377eb3SJohn Baldwin * with a non-zero length to detect EOF.
2075cd377eb3SJohn Baldwin */
2076cd377eb3SJohn Baldwin if (pending == 0)
2077cd377eb3SJohn Baldwin pending = 1;
2078cd377eb3SJohn Baldwin
2079cd377eb3SJohn Baldwin /* Ensure there is room in the command buffer. */
2080cd377eb3SJohn Baldwin io_buffer_grow(&cur_comm, pending);
2081cd377eb3SJohn Baldwin assert(io_buffer_avail(&cur_comm) >= pending);
2082cd377eb3SJohn Baldwin
2083cd377eb3SJohn Baldwin nread = read(fd, io_buffer_tail(&cur_comm), io_buffer_avail(&cur_comm));
2084cd377eb3SJohn Baldwin if (nread == 0) {
2085cd377eb3SJohn Baldwin close_connection();
2086cd377eb3SJohn Baldwin } else if (nread == -1) {
2087cd377eb3SJohn Baldwin if (errno == EAGAIN)
2088cd377eb3SJohn Baldwin return;
2089cd377eb3SJohn Baldwin
2090cd377eb3SJohn Baldwin warn("Read from GDB socket");
2091cd377eb3SJohn Baldwin close_connection();
2092cd377eb3SJohn Baldwin } else {
2093cd377eb3SJohn Baldwin cur_comm.len += nread;
2094cd377eb3SJohn Baldwin pthread_mutex_lock(&gdb_lock);
2095cd377eb3SJohn Baldwin check_command(fd);
2096cd377eb3SJohn Baldwin pthread_mutex_unlock(&gdb_lock);
2097cd377eb3SJohn Baldwin }
2098cd377eb3SJohn Baldwin }
2099cd377eb3SJohn Baldwin
2100cd377eb3SJohn Baldwin static void
gdb_writable(int fd,enum ev_type event __unused,void * arg __unused)210198d920d9SMark Johnston gdb_writable(int fd, enum ev_type event __unused, void *arg __unused)
2102cd377eb3SJohn Baldwin {
2103cd377eb3SJohn Baldwin
2104cd377eb3SJohn Baldwin send_pending_data(fd);
2105cd377eb3SJohn Baldwin }
2106cd377eb3SJohn Baldwin
2107cd377eb3SJohn Baldwin static void
new_connection(int fd,enum ev_type event __unused,void * arg)210898d920d9SMark Johnston new_connection(int fd, enum ev_type event __unused, void *arg)
2109cd377eb3SJohn Baldwin {
2110cd377eb3SJohn Baldwin int optval, s;
2111cd377eb3SJohn Baldwin
2112cd377eb3SJohn Baldwin s = accept4(fd, NULL, NULL, SOCK_NONBLOCK);
2113cd377eb3SJohn Baldwin if (s == -1) {
2114cd377eb3SJohn Baldwin if (arg != NULL)
2115cd377eb3SJohn Baldwin err(1, "Failed accepting initial GDB connection");
2116cd377eb3SJohn Baldwin
2117cd377eb3SJohn Baldwin /* Silently ignore errors post-startup. */
2118cd377eb3SJohn Baldwin return;
2119cd377eb3SJohn Baldwin }
2120cd377eb3SJohn Baldwin
2121cd377eb3SJohn Baldwin optval = 1;
2122cd377eb3SJohn Baldwin if (setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) ==
2123cd377eb3SJohn Baldwin -1) {
2124cd377eb3SJohn Baldwin warn("Failed to disable SIGPIPE for GDB connection");
2125cd377eb3SJohn Baldwin close(s);
2126cd377eb3SJohn Baldwin return;
2127cd377eb3SJohn Baldwin }
2128cd377eb3SJohn Baldwin
2129cd377eb3SJohn Baldwin pthread_mutex_lock(&gdb_lock);
2130cd377eb3SJohn Baldwin if (cur_fd != -1) {
2131cd377eb3SJohn Baldwin close(s);
2132cd377eb3SJohn Baldwin warnx("Ignoring additional GDB connection.");
2133cd377eb3SJohn Baldwin }
2134cd377eb3SJohn Baldwin
2135cd377eb3SJohn Baldwin read_event = mevent_add(s, EVF_READ, gdb_readable, NULL);
2136cd377eb3SJohn Baldwin if (read_event == NULL) {
2137cd377eb3SJohn Baldwin if (arg != NULL)
2138cd377eb3SJohn Baldwin err(1, "Failed to setup initial GDB connection");
2139cd377eb3SJohn Baldwin pthread_mutex_unlock(&gdb_lock);
2140cd377eb3SJohn Baldwin return;
2141cd377eb3SJohn Baldwin }
2142cd377eb3SJohn Baldwin write_event = mevent_add(s, EVF_WRITE, gdb_writable, NULL);
2143cd377eb3SJohn Baldwin if (write_event == NULL) {
2144cd377eb3SJohn Baldwin if (arg != NULL)
2145cd377eb3SJohn Baldwin err(1, "Failed to setup initial GDB connection");
2146cd377eb3SJohn Baldwin mevent_delete_close(read_event);
2147cd377eb3SJohn Baldwin read_event = NULL;
2148cd377eb3SJohn Baldwin }
2149cd377eb3SJohn Baldwin
2150cd377eb3SJohn Baldwin cur_fd = s;
2151cd377eb3SJohn Baldwin cur_vcpu = 0;
2152cd377eb3SJohn Baldwin stopped_vcpu = -1;
2153cd377eb3SJohn Baldwin
2154cd377eb3SJohn Baldwin /* Break on attach. */
2155cd377eb3SJohn Baldwin first_stop = true;
2156cbd03a9dSJohn Baldwin report_next_stop = false;
2157cd377eb3SJohn Baldwin gdb_suspend_vcpus();
2158cd377eb3SJohn Baldwin pthread_mutex_unlock(&gdb_lock);
2159cd377eb3SJohn Baldwin }
2160cd377eb3SJohn Baldwin
2161cd377eb3SJohn Baldwin #ifndef WITHOUT_CAPSICUM
216237045dfaSMark Johnston static void
limit_gdb_socket(int s)2163cd377eb3SJohn Baldwin limit_gdb_socket(int s)
2164cd377eb3SJohn Baldwin {
2165cd377eb3SJohn Baldwin cap_rights_t rights;
2166cd377eb3SJohn Baldwin unsigned long ioctls[] = { FIONREAD };
2167cd377eb3SJohn Baldwin
2168cd377eb3SJohn Baldwin cap_rights_init(&rights, CAP_ACCEPT, CAP_EVENT, CAP_READ, CAP_WRITE,
2169cd377eb3SJohn Baldwin CAP_SETSOCKOPT, CAP_IOCTL);
2170abfa3c39SMarcelo Araujo if (caph_rights_limit(s, &rights) == -1)
2171cd377eb3SJohn Baldwin errx(EX_OSERR, "Unable to apply rights for sandbox");
2172abfa3c39SMarcelo Araujo if (caph_ioctls_limit(s, ioctls, nitems(ioctls)) == -1)
2173cd377eb3SJohn Baldwin errx(EX_OSERR, "Unable to apply rights for sandbox");
2174cd377eb3SJohn Baldwin }
2175cd377eb3SJohn Baldwin #endif
2176cd377eb3SJohn Baldwin
2177cd377eb3SJohn Baldwin void
init_gdb(struct vmctx * _ctx)21782cdff991SMariusz Zaborski init_gdb(struct vmctx *_ctx)
2179cd377eb3SJohn Baldwin {
2180f81cdf24SMark Johnston #ifndef WITHOUT_CAPSICUM
2181f81cdf24SMark Johnston cap_rights_t rights;
2182f81cdf24SMark Johnston #endif
218302e7a651SMark Johnston int error, flags, optval, s;
21842cdff991SMariusz Zaborski struct addrinfo hints;
21852cdff991SMariusz Zaborski struct addrinfo *gdbaddr;
21862cdff991SMariusz Zaborski const char *saddr, *value;
21872cdff991SMariusz Zaborski char *sport;
21882cdff991SMariusz Zaborski bool wait;
2189cd377eb3SJohn Baldwin
21902cdff991SMariusz Zaborski value = get_config_value("gdb.port");
21912cdff991SMariusz Zaborski if (value == NULL)
21922cdff991SMariusz Zaborski return;
21932cdff991SMariusz Zaborski sport = strdup(value);
21942cdff991SMariusz Zaborski if (sport == NULL)
21952cdff991SMariusz Zaborski errx(4, "Failed to allocate memory");
21962cdff991SMariusz Zaborski
21972cdff991SMariusz Zaborski wait = get_config_bool_default("gdb.wait", false);
21982cdff991SMariusz Zaborski
21992cdff991SMariusz Zaborski saddr = get_config_value("gdb.address");
22002cdff991SMariusz Zaborski if (saddr == NULL) {
22013a92927bSMariusz Zaborski saddr = "localhost";
22022cdff991SMariusz Zaborski }
22032cdff991SMariusz Zaborski
22042cdff991SMariusz Zaborski debug("==> starting on %s:%s, %swaiting\n",
22052cdff991SMariusz Zaborski saddr, sport, wait ? "" : "not ");
2206cd377eb3SJohn Baldwin
2207cd377eb3SJohn Baldwin error = pthread_mutex_init(&gdb_lock, NULL);
2208cd377eb3SJohn Baldwin if (error != 0)
2209cd377eb3SJohn Baldwin errc(1, error, "gdb mutex init");
2210cd377eb3SJohn Baldwin error = pthread_cond_init(&idle_vcpus, NULL);
2211cd377eb3SJohn Baldwin if (error != 0)
2212cd377eb3SJohn Baldwin errc(1, error, "gdb cv init");
2213cd377eb3SJohn Baldwin
22142cdff991SMariusz Zaborski memset(&hints, 0, sizeof(hints));
22152cdff991SMariusz Zaborski hints.ai_family = AF_UNSPEC;
22162cdff991SMariusz Zaborski hints.ai_socktype = SOCK_STREAM;
22173a92927bSMariusz Zaborski hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE;
22182cdff991SMariusz Zaborski
2219927aa5feSMark Johnston error = getaddrinfo(saddr, sport, &hints, &gdbaddr);
2220927aa5feSMark Johnston if (error != 0)
2221927aa5feSMark Johnston errx(1, "gdb address resolution: %s", gai_strerror(error));
22222cdff991SMariusz Zaborski
2223cd377eb3SJohn Baldwin ctx = _ctx;
22242cdff991SMariusz Zaborski s = socket(gdbaddr->ai_family, gdbaddr->ai_socktype, 0);
2225cd377eb3SJohn Baldwin if (s < 0)
2226cd377eb3SJohn Baldwin err(1, "gdb socket create");
2227cd377eb3SJohn Baldwin
222802e7a651SMark Johnston optval = 1;
222902e7a651SMark Johnston (void)setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
223002e7a651SMark Johnston
22312cdff991SMariusz Zaborski if (bind(s, gdbaddr->ai_addr, gdbaddr->ai_addrlen) < 0)
2232cd377eb3SJohn Baldwin err(1, "gdb socket bind");
2233cd377eb3SJohn Baldwin
2234cd377eb3SJohn Baldwin if (listen(s, 1) < 0)
2235cd377eb3SJohn Baldwin err(1, "gdb socket listen");
2236cd377eb3SJohn Baldwin
2237cbd03a9dSJohn Baldwin stopped_vcpu = -1;
2238cbd03a9dSJohn Baldwin TAILQ_INIT(&breakpoints);
22397d9ef309SJohn Baldwin vcpus = calloc(guest_ncpus, sizeof(*vcpus));
2240cbd03a9dSJohn Baldwin vcpu_state = calloc(guest_ncpus, sizeof(*vcpu_state));
2241cd377eb3SJohn Baldwin if (wait) {
2242cd377eb3SJohn Baldwin /*
2243cd377eb3SJohn Baldwin * Set vcpu 0 in vcpus_suspended. This will trigger the
2244cd377eb3SJohn Baldwin * logic in gdb_cpu_add() to suspend the first vcpu before
2245cd377eb3SJohn Baldwin * it starts execution. The vcpu will remain suspended
2246cd377eb3SJohn Baldwin * until a debugger connects.
2247cd377eb3SJohn Baldwin */
2248cd377eb3SJohn Baldwin CPU_SET(0, &vcpus_suspended);
2249cbd03a9dSJohn Baldwin stopped_vcpu = 0;
2250cd377eb3SJohn Baldwin }
2251cd377eb3SJohn Baldwin
2252cd377eb3SJohn Baldwin flags = fcntl(s, F_GETFL);
2253cd377eb3SJohn Baldwin if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
2254cd377eb3SJohn Baldwin err(1, "Failed to mark gdb socket non-blocking");
2255cd377eb3SJohn Baldwin
2256cd377eb3SJohn Baldwin #ifndef WITHOUT_CAPSICUM
2257cd377eb3SJohn Baldwin limit_gdb_socket(s);
2258cd377eb3SJohn Baldwin #endif
2259cd377eb3SJohn Baldwin mevent_add(s, EVF_READ, new_connection, NULL);
2260621b5090SJohn Baldwin gdb_active = true;
22612cdff991SMariusz Zaborski freeaddrinfo(gdbaddr);
22622cdff991SMariusz Zaborski free(sport);
2263f81cdf24SMark Johnston
2264f81cdf24SMark Johnston xml_dfd = open(_PATH_GDB_XML, O_DIRECTORY);
2265f81cdf24SMark Johnston if (xml_dfd == -1)
2266f81cdf24SMark Johnston err(1, "Failed to open gdb xml directory");
2267f81cdf24SMark Johnston #ifndef WITHOUT_CAPSICUM
2268f81cdf24SMark Johnston cap_rights_init(&rights, CAP_FSTAT, CAP_LOOKUP, CAP_MMAP_R, CAP_PREAD);
2269f81cdf24SMark Johnston if (caph_rights_limit(xml_dfd, &rights) == -1)
2270f81cdf24SMark Johnston err(1, "cap_rights_init");
2271f81cdf24SMark Johnston #endif
2272cd377eb3SJohn Baldwin }
2273