bhyve: Prepare to add arm64 support to the gdb stub

In particular:
- Stop assuming that the breakpoint size is one byte.
- Avoid referencing the "rip" field in machine-independent code, use a
  helper.

No functional change intended.

Reviewed by:	corvink, jhb
MFC after:	1 week
Sponsored by:	Innovate UK
Differential Revision:	https://reviews.freebsd.org/D43483
This commit is contained in:
Mark Johnston 2024-01-23 11:41:13 -05:00
parent 5e728af444
commit 5f086566e0
1 changed files with 25 additions and 12 deletions

View File

@ -69,6 +69,13 @@
*/ */
#define GDB_SIGNAL_TRAP 5 #define GDB_SIGNAL_TRAP 5
#define GDB_BP_SIZE 1
#define GDB_BP_INSTR (uint8_t []){0xcc}
#define GDB_PC_REGNAME VM_REG_GUEST_RIP
_Static_assert(sizeof(GDB_BP_INSTR) == GDB_BP_SIZE,
"GDB_BP_INSTR has wrong size");
static void gdb_resume_vcpus(void); static void gdb_resume_vcpus(void);
static void check_command(int fd); static void check_command(int fd);
@ -95,7 +102,7 @@ struct io_buffer {
struct breakpoint { struct breakpoint {
uint64_t gpa; uint64_t gpa;
uint8_t shadow_inst; uint8_t shadow_inst[GDB_BP_SIZE];
TAILQ_ENTRY(breakpoint) link; TAILQ_ENTRY(breakpoint) link;
}; };
@ -263,6 +270,12 @@ guest_vaddr2paddr(struct vcpu *vcpu, uint64_t vaddr, uint64_t *paddr)
return (1); return (1);
} }
static uint64_t
guest_pc(struct vm_exit *vme)
{
return (vme->rip);
}
static void static void
io_buffer_reset(struct io_buffer *io) io_buffer_reset(struct io_buffer *io)
{ {
@ -931,7 +944,7 @@ gdb_cpu_breakpoint(struct vcpu *vcpu, struct vm_exit *vmexit)
} }
vcpuid = vcpu_id(vcpu); vcpuid = vcpu_id(vcpu);
pthread_mutex_lock(&gdb_lock); pthread_mutex_lock(&gdb_lock);
error = guest_vaddr2paddr(vcpu, vmexit->rip, &gpa); error = guest_vaddr2paddr(vcpu, guest_pc(vmexit), &gpa);
assert(error == 1); assert(error == 1);
bp = find_breakpoint(gpa); bp = find_breakpoint(gpa);
if (bp != NULL) { if (bp != NULL) {
@ -940,11 +953,11 @@ gdb_cpu_breakpoint(struct vcpu *vcpu, struct vm_exit *vmexit)
assert(vs->stepped == false); assert(vs->stepped == false);
assert(vs->hit_swbreak == false); assert(vs->hit_swbreak == false);
vs->hit_swbreak = true; vs->hit_swbreak = true;
vm_set_register(vcpu, VM_REG_GUEST_RIP, vmexit->rip); vm_set_register(vcpu, GDB_PC_REGNAME, guest_pc(vmexit));
for (;;) { for (;;) {
if (stopped_vcpu == -1) { if (stopped_vcpu == -1) {
debug("$vCPU %d reporting breakpoint at rip %#lx\n", debug("$vCPU %d reporting breakpoint at rip %#lx\n",
vcpuid, vmexit->rip); vcpuid, guest_pc(vmexit));
stopped_vcpu = vcpuid; stopped_vcpu = vcpuid;
gdb_suspend_vcpus(); gdb_suspend_vcpus();
} }
@ -963,7 +976,7 @@ gdb_cpu_breakpoint(struct vcpu *vcpu, struct vm_exit *vmexit)
gdb_cpu_resume(vcpu); gdb_cpu_resume(vcpu);
} else { } else {
debug("$vCPU %d injecting breakpoint at rip %#lx\n", vcpuid, debug("$vCPU %d injecting breakpoint at rip %#lx\n", vcpuid,
vmexit->rip); guest_pc(vmexit));
error = vm_set_register(vcpu, VM_REG_GUEST_ENTRY_INST_LENGTH, error = vm_set_register(vcpu, VM_REG_GUEST_ENTRY_INST_LENGTH,
vmexit->u.bpt.inst_length); vmexit->u.bpt.inst_length);
assert(error == 0); assert(error == 0);
@ -1277,8 +1290,8 @@ remove_all_sw_breakpoints(void)
TAILQ_FOREACH_SAFE(bp, &breakpoints, link, nbp) { TAILQ_FOREACH_SAFE(bp, &breakpoints, link, nbp) {
debug("remove breakpoint at %#lx\n", bp->gpa); debug("remove breakpoint at %#lx\n", bp->gpa);
cp = paddr_guest2host(ctx, bp->gpa, 1); cp = paddr_guest2host(ctx, bp->gpa, sizeof(bp->shadow_inst));
*cp = bp->shadow_inst; memcpy(cp, bp->shadow_inst, sizeof(bp->shadow_inst));
TAILQ_REMOVE(&breakpoints, bp, link); TAILQ_REMOVE(&breakpoints, bp, link);
free(bp); free(bp);
} }
@ -1294,7 +1307,7 @@ update_sw_breakpoint(uint64_t gva, int kind, bool insert)
uint8_t *cp; uint8_t *cp;
int error; int error;
if (kind != 1) { if (kind != GDB_BP_SIZE) {
send_error(EINVAL); send_error(EINVAL);
return; return;
} }
@ -1309,7 +1322,7 @@ update_sw_breakpoint(uint64_t gva, int kind, bool insert)
return; return;
} }
cp = paddr_guest2host(ctx, gpa, 1); cp = paddr_guest2host(ctx, gpa, sizeof(bp->shadow_inst));
/* Only permit breakpoints in guest RAM. */ /* Only permit breakpoints in guest RAM. */
if (cp == NULL) { if (cp == NULL) {
@ -1333,15 +1346,15 @@ update_sw_breakpoint(uint64_t gva, int kind, bool insert)
} }
bp = malloc(sizeof(*bp)); bp = malloc(sizeof(*bp));
bp->gpa = gpa; bp->gpa = gpa;
bp->shadow_inst = *cp; memcpy(bp->shadow_inst, cp, sizeof(bp->shadow_inst));
*cp = 0xcc; /* INT 3 */ memcpy(cp, GDB_BP_INSTR, sizeof(bp->shadow_inst));
TAILQ_INSERT_TAIL(&breakpoints, bp, link); TAILQ_INSERT_TAIL(&breakpoints, bp, link);
debug("new breakpoint at %#lx\n", gpa); debug("new breakpoint at %#lx\n", gpa);
} }
} else { } else {
if (bp != NULL) { if (bp != NULL) {
debug("remove breakpoint at %#lx\n", gpa); debug("remove breakpoint at %#lx\n", gpa);
*cp = bp->shadow_inst; memcpy(cp, bp->shadow_inst, sizeof(bp->shadow_inst));
TAILQ_REMOVE(&breakpoints, bp, link); TAILQ_REMOVE(&breakpoints, bp, link);
free(bp); free(bp);
if (TAILQ_EMPTY(&breakpoints)) if (TAILQ_EMPTY(&breakpoints))