Lines Matching +full:suspend +full:- +full:to +full:- +full:ram
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2017-2018 John H. Baldwin <jhb@FreeBSD.org>
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
109 static int xml_dfd = -1;
114 * valid bytes in the buffer. For a write buffer, 'start' is set to
115 * the index of the next byte in 'data' to send, and 'len' contains
116 * the remaining number of valid bytes to send.
132 * When a vCPU stops to due to an event that should be reported to the
141 * An idle vCPU will have all of the boolean fields set to false.
143 * When a vCPU is stepped, 'stepping' is set to true when the vCPU is
144 * released to execute the stepped instruction. When the vCPU reports
148 * 'hit_swbreak' is set to true.
159 static int cur_fd = -1;
198 * Registers past this point are not included in a reply to a 'g' query,
199 * to provide compatibility with debuggers that do not fetch a target
268 if (caph_limit_stream(fileno(logfile), CAPH_WRITE) == -1) { in debug()
298 if (vm_get_register_set(vcpu, nitems(regset), regset, regs) == -1) in guest_paging_info()
299 return (-1); in guest_paging_info()
302 * For the debugger, always pretend to be the kernel (CPL 0), in guest_paging_info()
303 * and if long-mode is enabled, always parse addresses as if in guest_paging_info()
304 * in 64-bit mode. in guest_paging_info()
306 paging->cr3 = regs[1]; in guest_paging_info()
307 paging->cpl = 0; in guest_paging_info()
309 paging->cpu_mode = CPU_MODE_64BIT; in guest_paging_info()
311 paging->cpu_mode = CPU_MODE_PROTECTED; in guest_paging_info()
313 paging->cpu_mode = CPU_MODE_REAL; in guest_paging_info()
315 paging->paging_mode = PAGING_MODE_FLAT; in guest_paging_info()
317 paging->paging_mode = PAGING_MODE_32; in guest_paging_info()
319 paging->paging_mode = (regs[2] & CR4_LA57) ? in guest_paging_info()
322 paging->paging_mode = PAGING_MODE_PAE; in guest_paging_info()
335 if (vm_get_register_set(vcpu, nitems(regset), regset, regs) == -1) in guest_paging_info()
336 return (-1); in guest_paging_info()
339 paging->ttbr0_addr = regs[0] & ~(TTBR_ASID_MASK | TTBR_CnP); in guest_paging_info()
340 paging->ttbr1_addr = regs[1] & ~(TTBR_ASID_MASK | TTBR_CnP); in guest_paging_info()
341 paging->tcr_el1 = regs[2]; in guest_paging_info()
342 paging->tcr2_el1 = regs[3]; in guest_paging_info()
343 paging->flags = regs[5] & (PSR_M_MASK | PSR_M_32); in guest_paging_info()
345 paging->flags |= VM_GP_MMU_ENABLED; in guest_paging_info()
352 * Map a guest virtual address to a physical address (for a given vcpu).
355 * return -1.
363 if (guest_paging_info(vcpu, &paging) == -1) in guest_vaddr2paddr()
364 return (-1); in guest_vaddr2paddr()
371 &fault) == -1) in guest_vaddr2paddr()
372 return (-1); in guest_vaddr2paddr()
382 return (vme->rip); in guest_pc()
384 return (vme->pc); in guest_pc()
392 io->start = 0; in io_buffer_reset()
393 io->len = 0; in io_buffer_reset()
401 return (io->capacity - (io->start + io->len)); in io_buffer_avail()
408 return (io->data + io->start); in io_buffer_head()
415 return (io->data + io->start + io->len); in io_buffer_tail()
422 assert(amount <= io->len); in io_buffer_advance()
423 io->start += amount; in io_buffer_advance()
424 io->len -= amount; in io_buffer_advance()
432 if (io->len == 0) { in io_buffer_consume()
433 io->start = 0; in io_buffer_consume()
441 memmove(io->data, io_buffer_head(io), io->len); in io_buffer_consume()
442 io->start = 0; in io_buffer_consume()
455 new_cap = io->capacity + (newsize - avail); in io_buffer_grow()
456 new_data = realloc(io->data, new_cap); in io_buffer_grow()
458 err(1, "Failed to grow GDB I/O buffer"); in io_buffer_grow()
459 io->data = new_data; in io_buffer_grow()
460 io->capacity = new_cap; in io_buffer_grow()
489 cur_fd = -1; in close_connection()
508 return (nibble + 'a' - 10); in hex_digit()
516 return (v - '0'); in parse_digit()
518 return (v - 'a' + 10); in parse_digit()
520 return (v - 'A' + 10); in parse_digit()
524 /* Parses big-endian hexadecimal. */
535 len--; in parse_integer()
557 if (nwritten == -1) { in send_pending_data()
558 warn("Write to GDB socket failed"); in send_pending_data()
569 /* Append a single character to the output buffer. */
578 /* Append an array of bytes to the output buffer. */
597 * Append a single byte (formatted as two hex characters) to the
623 debug("-> %.*s\n", (int)cur_resp.len, io_buffer_head(&cur_resp)); in finish_packet()
650 len--; in append_packet_data()
659 for (; len > 0; data++, len--) { in append_binary_data()
710 format_byte(value, buf + (len - i - 1) * 2); in append_unsigned_be()
769 if (len == 2 && memcmp(data, "-1", 2) == 0) in parse_threadid()
770 return (-1); in parse_threadid()
772 return (-2); in parse_threadid()
777 * Report the current stop event to the debugger. If the stop is due
778 * to an event triggered on a specific vCPU such as a breakpoint or
779 * stepping trap, stopped_vcpu will be set to the vCPU triggering the
780 * stop. If 'set_cur_vcpu' is true, then cur_vcpu will be updated to
789 if (stopped_vcpu == -1) { in report_stop()
801 if (vs->hit_swbreak) { in report_stop()
805 } else if (vs->stepped) in report_stop()
815 * If this stop is due to a vCPU event, clear that event to mark it as
823 if (stopped_vcpu != -1) { in discard_stop()
825 vs->hit_swbreak = false; in discard_stop()
826 vs->stepped = false; in discard_stop()
827 stopped_vcpu = -1; in discard_stop()
838 stopped_vcpu = -1; in gdb_finish_suspend_vcpus()
848 * debug server to pause or report an event. vCPU threads wait here
867 * Requests vCPU single-stepping using a
894 * Checks whether single-stepping is supported for a given vCPU.
904 return (-1); in _gdb_check_step()
913 * Invoked at the start of a vCPU thread's execution to inform the
936 * If a vcpu is added while vcpus are stopped, suspend the new in gdb_cpu_add()
953 * In particular, this refers to the kernel's view of the vCPU in gdb_cpu_add()
983 assert(vs->hit_swbreak == false); in gdb_cpu_resume()
984 assert(vs->stepped == false); in gdb_cpu_resume()
985 if (vs->stepping) { in gdb_cpu_resume()
992 * Handler for VM_EXITCODE_DEBUG used to suspend a vCPU when the guest
993 * has been suspended due to an event on different vCPU or in response
994 * to a guest-wide suspend such as Ctrl-C or the stop on attach.
1021 * Invoked each time a vmexit handler needs to step a vCPU.
1034 if (vs->stepping) { in gdb_cpu_step()
1035 vs->stepping = false; in gdb_cpu_step()
1036 vs->stepped = true; in gdb_cpu_step()
1040 while (vs->stepped) { in gdb_cpu_step()
1041 if (stopped_vcpu == -1) { in gdb_cpu_step()
1054 * A general handler for single-step exceptions.
1065 if (vmexit->u.dbg.trace_trap) { in gdb_cpu_debug()
1075 * Handler for VM_EXITCODE_MTRAP reported when a vCPU single-steps via
1076 * the VT-x-specific MTRAP exit.
1092 if (bp->gpa == gpa) in find_breakpoint()
1117 assert(vs->stepping == false); in gdb_cpu_breakpoint()
1118 assert(vs->stepped == false); in gdb_cpu_breakpoint()
1119 assert(vs->hit_swbreak == false); in gdb_cpu_breakpoint()
1120 vs->hit_swbreak = true; in gdb_cpu_breakpoint()
1123 if (stopped_vcpu == -1) { in gdb_cpu_breakpoint()
1130 if (!vs->hit_swbreak) { in gdb_cpu_breakpoint()
1137 vs->hit_swbreak = false; in gdb_cpu_breakpoint()
1147 vmexit->u.bpt.inst_length); in gdb_cpu_breakpoint()
1154 esr = (EXCP_BRK << ESR_ELx_EC_SHIFT) | vmexit->u.hyp.esr_el2; in gdb_cpu_breakpoint()
1201 regnums, regvals) == -1) { in gdb_read_regs()
1230 -1) { in gdb_read_one_reg()
1253 len -= 1; in gdb_read_mem()
1261 gva = parse_integer(data, cp - data); in gdb_read_mem()
1262 len -= (cp - data) + 1; in gdb_read_mem()
1263 data += (cp - data) + 1; in gdb_read_mem()
1271 if (error == -1) { in gdb_read_mem()
1287 todo = getpagesize() - gpa % getpagesize(); in gdb_read_mem()
1294 * If this page is guest RAM, read it a byte in gdb_read_mem()
1306 resid--; in gdb_read_mem()
1307 todo--; in gdb_read_mem()
1311 * If this page isn't guest RAM, try to handle in gdb_read_mem()
1331 resid -= bytes; in gdb_read_mem()
1332 todo -= bytes; in gdb_read_mem()
1336 bytes--; in gdb_read_mem()
1366 len -= 1; in gdb_write_mem()
1374 gva = parse_integer(data, cp - data); in gdb_write_mem()
1375 len -= (cp - data) + 1; in gdb_write_mem()
1376 data += (cp - data) + 1; in gdb_write_mem()
1384 resid = parse_integer(data, cp - data); in gdb_write_mem()
1385 len -= (cp - data) + 1; in gdb_write_mem()
1386 data += (cp - data) + 1; in gdb_write_mem()
1396 if (error == -1) { in gdb_write_mem()
1405 /* Write bytes to current page. */ in gdb_write_mem()
1406 todo = getpagesize() - gpa % getpagesize(); in gdb_write_mem()
1413 * If this page is guest RAM, write it a byte in gdb_write_mem()
1420 len -= 2; in gdb_write_mem()
1424 resid--; in gdb_write_mem()
1425 todo--; in gdb_write_mem()
1429 * If this page isn't guest RAM, try to handle in gdb_write_mem()
1449 resid -= bytes; in gdb_write_mem()
1450 todo -= bytes; in gdb_write_mem()
1452 len -= 2 * bytes; in gdb_write_mem()
1473 vcpu = CPU_FFS(&mask) - 1; in set_breakpoint_caps()
1508 debug("remove breakpoint at %#lx\n", bp->gpa); in remove_all_sw_breakpoints()
1509 cp = paddr_guest2host(ctx, bp->gpa, sizeof(bp->shadow_inst)); in remove_all_sw_breakpoints()
1510 write_instr(cp, bp->shadow_inst, sizeof(bp->shadow_inst)); in remove_all_sw_breakpoints()
1532 if (error == -1) { in update_sw_breakpoint()
1541 cp = paddr_guest2host(ctx, gpa, sizeof(bp->shadow_inst)); in update_sw_breakpoint()
1543 /* Only permit breakpoints in guest RAM. */ in update_sw_breakpoint()
1554 * requires these packets to be idempotent. in update_sw_breakpoint()
1564 bp->gpa = gpa; in update_sw_breakpoint()
1565 memcpy(bp->shadow_inst, cp, sizeof(bp->shadow_inst)); in update_sw_breakpoint()
1566 write_instr(cp, GDB_BP_INSTR, sizeof(bp->shadow_inst)); in update_sw_breakpoint()
1573 write_instr(cp, bp->shadow_inst, in update_sw_breakpoint()
1574 sizeof(bp->shadow_inst)); in update_sw_breakpoint()
1596 len -= 1; in parse_breakpoint()
1604 type = parse_integer(data, cp - data); in parse_breakpoint()
1605 len -= (cp - data) + 1; in parse_breakpoint()
1606 data += (cp - data) + 1; in parse_breakpoint()
1614 gva = parse_integer(data, cp - data); in parse_breakpoint()
1615 len -= (cp - data) + 1; in parse_breakpoint()
1616 data += (cp - data) + 1; in parse_breakpoint()
1686 value = feature + strlen(feature) - 1; in check_features()
1691 case '-': in check_features()
1726 * - qSearch in gdb_query()
1751 vcpu = CPU_FFS(&mask) - 1; in gdb_query()
1766 len -= strlen("qSupported"); in gdb_query()
1773 len -= strlen("qThreadExtraInfo"); in gdb_query()
1778 tid = parse_threadid(data + 1, len - 1); in gdb_query()
1779 if (tid <= 0 || !CPU_ISSET(tid - 1, &vcpus_active)) { in gdb_query()
1784 snprintf(buf, sizeof(buf), "vCPU %d", tid - 1); in gdb_query()
1798 len -= strlen("qXfer:features:read:"); in gdb_query()
1802 (size_t)(pathend - data) >= sizeof(path) - 1) { in gdb_query()
1806 memcpy(path, data, pathend - data); in gdb_query()
1807 path[pathend - data] = '\0'; in gdb_query()
1808 data += (pathend - data) + 1; in gdb_query()
1809 len -= (pathend - data) + 1; in gdb_query()
1811 if (len > sizeof(buf) - 1) { in gdb_query()
1846 append_binary_data(xml + doff, xmllen - doff); in gdb_query()
1861 /* Reject packets with a sequence-id. */ in handle_command()
1887 gdb_read_one_reg(data + 1, len - 1); in handle_command()
1896 tid = parse_threadid(data + 2, len - 2); in handle_command()
1897 if (tid == -2) { in handle_command()
1906 if (tid == -1 || tid == 0) in handle_command()
1907 cur_vcpu = CPU_FFS(&vcpus_active) - 1; in handle_command()
1908 else if (CPU_ISSET(tid - 1, &vcpus_active)) in handle_command()
1909 cur_vcpu = tid - 1; in handle_command()
1926 tid = parse_threadid(data + 1, len - 1); in handle_command()
1927 if (tid <= 0 || !CPU_ISSET(tid - 1, &vcpus_active)) { in handle_command()
1983 debug("<- Ctrl-C\n"); in check_command()
1990 debug("<- +\n"); in check_command()
1994 if (stopped_vcpu != -1 && report_next_stop) { in check_command()
1999 case '-': in check_command()
2001 debug("<- -\n"); in check_command()
2007 debug("-> %.*s\n", (int)cur_resp.len, in check_command()
2026 plen = (hash - head + 1) + 2; in check_command()
2029 debug("<- %.*s\n", (int)plen, head); in check_command()
2036 debug("-> -\n"); in check_command()
2037 send_char('-'); in check_command()
2043 handle_command(head + 1, hash - (head + 1)); in check_command()
2046 debug("-> +\n"); in check_command()
2051 debug("-> %02x\n", *head); in check_command()
2065 if (ioctl(fd, FIONREAD, &n) == -1) { in gdb_readable()
2073 * 'pending' might be zero due to EOF. We need to call read in gdb_readable()
2074 * with a non-zero length to detect EOF. in gdb_readable()
2086 } else if (nread == -1) { in gdb_readable()
2113 if (s == -1) { in new_connection()
2117 /* Silently ignore errors post-startup. */ in new_connection()
2123 -1) { in new_connection()
2124 warn("Failed to disable SIGPIPE for GDB connection"); in new_connection()
2130 if (cur_fd != -1) { in new_connection()
2138 err(1, "Failed to setup initial GDB connection"); in new_connection()
2145 err(1, "Failed to setup initial GDB connection"); in new_connection()
2152 stopped_vcpu = -1; in new_connection()
2170 if (caph_rights_limit(s, &rights) == -1) in limit_gdb_socket()
2171 errx(EX_OSERR, "Unable to apply rights for sandbox"); in limit_gdb_socket()
2172 if (caph_ioctls_limit(s, ioctls, nitems(ioctls)) == -1) in limit_gdb_socket()
2173 errx(EX_OSERR, "Unable to apply rights for sandbox"); in limit_gdb_socket()
2195 errx(4, "Failed to allocate memory"); in init_gdb()
2224 s = socket(gdbaddr->ai_family, gdbaddr->ai_socktype, 0); in init_gdb()
2231 if (bind(s, gdbaddr->ai_addr, gdbaddr->ai_addrlen) < 0) in init_gdb()
2237 stopped_vcpu = -1; in init_gdb()
2244 * logic in gdb_cpu_add() to suspend the first vcpu before in init_gdb()
2253 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) in init_gdb()
2254 err(1, "Failed to mark gdb socket non-blocking"); in init_gdb()
2265 if (xml_dfd == -1) in init_gdb()
2266 err(1, "Failed to open gdb xml directory"); in init_gdb()
2269 if (caph_rights_limit(xml_dfd, &rights) == -1) in init_gdb()