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:
parent
5e728af444
commit
5f086566e0
|
@ -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))
|
||||||
|
|
Loading…
Reference in New Issue