diff options
| author | Stefan Hajnoczi <stefanha@redhat.com> | 2026-07-06 18:38:14 +0200 |
|---|---|---|
| committer | Stefan Hajnoczi <stefanha@redhat.com> | 2026-07-06 18:38:14 +0200 |
| commit | 94826ec1370328375c3b6d1e80fdc94c8f46c348 (patch) | |
| tree | 34903798c595361e8d3137893a37b61ea0de9721 | |
| parent | d0edff8ee17850d955c0b9724c296adcb9192c5c (diff) | |
| parent | c0df53752c86e5f51e12e7b99501b6f4d2e52c01 (diff) | |
| download | qemu-staging.tar.gz qemu-staging.zip | |
Merge tag 'accel-20260706' of https://github.com/philmd/qemu into stagingstaging
Accelerators patches queue
- Various cleanups around debugging APIs
- Correctly check singlestep flag enabled in CPUState
- Fix possible memory corruption with MSHV (CID 1660876)
# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmpLsRwACgkQ4+MsLN6t
# wN7TRRAAhTnAG0VuUat9MYUCuWWSiTrNKm6m2vVcO+Zec/bBbU1+twBSBzVQ/rwm
# kGzImAWip6nYorU5BxTKePlpCy6Rm+t0evYaA5ixF0aXtmm3n6IGIMSsi5yEJxF5
# YHDXxvpD56Z1p8kRvkp4ynABiiF5gfBFqbSuI7/gxSI2tcJ2uSx8MC+HEO/X4vJc
# +Clich5n4eyN7YL7vqGrVl84cqHOwe40bXAm1OOa5S83/y2hc//SHgFqTB8BL1P7
# 9SafbFIFiqbfy4kWV86mSu3LDsSYLoIU7bgpRb9mX9WVrvfuoQeVUf7XH+fjmqIo
# s/2uHN6ha/h12jS1q0nCYu585EzXCuPRF3upSslPaoEd16sFEO6ZiODmaMIsomA2
# SlCM3jGYUUw+vkfS/+SJUF17QEHtv0R8Dp5IfseE9Tp+huYvJuwn3Qh4UwbVRg0P
# YHoRa2KiXvBPntY/GkyhCL9Y5oWC5RaRHyKxMs83tdUouOeBy2t/ftnVtDqeRn3p
# 04W+pilUEodSnzcNfAGxQhkqDeGIOveRubaeNICgmxO0Bp9dMUZIOju84hY77KEw
# hClBI87cOc1REC7YNXkoouWcr8moNSZlKAyIbTf/Ag5cAheYOSvO5UDDVVepudSl
# kER+S1iuPkeb0uVvnvk5Kh4UBCMwdfYKe9bNu/SB0ab6N3IpY4s=
# =knBq
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 06 Jul 2026 15:43:56 CEST
# gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE
# gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full]
# Primary key fingerprint: FAAB E75E 1291 7221 DCFD 6BB2 E3E3 2C2C DEAD C0DE
* tag 'accel-20260706' of https://github.com/philmd/qemu: (32 commits)
cpu: Only check SSTEP_ENABLE flag in cpu_single_stepping()
cpu: Rename CPUState @singlestep_enabled -> @singlestep_flags
cpu: Introduce cpu_single_stepping() helper
cpu: Better name cpu_single_step() trace event
accel/tcg: Improve docstrings around TCGCPUOps::*watchpoint* handlers
target/ppc: Ensure TCG is used in ppc_update_daw()
target/arm: Inline check_watchpoints() in arm_debug_check_watchpoint()
accel: Use GdbBreakpointType enum
gdbstub: Introduce GdbBreakpointType enumerator
gdbstub: Reduce @type variable scope
gdbstub/user: Directly call gdb_breakpoint_remove_all() in user mode
accel: Remove unnecessary 'inline' qualifier in remove_all_breakpoints
cpu: Move BREAKPOINT definitions to 'exec/breakpoint.h'
cpu: Move cpu_breakpoint_test out of line
accel: Remove AccelOpsClass::supports_guest_debug
accel: Hold @can_reverse information in AccelGdbConfig
gdbstub: Make default replay_mode value explicit in stubs
accel: Have each implementation return their AccelGdbConfig
gdbstub: Move supported_sstep_flags in AccelGdbConfig structure
gdbstub: Reduce gdb_supports_guest_debug() scope
...
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
59 files changed, 339 insertions, 375 deletions
diff --git a/accel/accel-common.c b/accel/accel-common.c index 62590a7d9a..00a400243f 100644 --- a/accel/accel-common.c +++ b/accel/accel-common.c @@ -70,6 +70,11 @@ void accel_init_interfaces(AccelClass *ac) accel_init_cpu_interfaces(ac); } +bool accel_supports_guest_debug(AccelState *accel) +{ + return accel->gdbstub.sstep_flags & SSTEP_ENABLE; +} + void accel_cpu_instance_init(CPUState *cpu) { if (cpu->cc->accel_cpu && cpu->cc->accel_cpu->cpu_instance_init) { @@ -113,16 +118,6 @@ void accel_cpu_common_unrealize(CPUState *cpu) } } -int accel_supported_gdbstub_sstep_flags(void) -{ - AccelState *accel = current_accel(); - AccelClass *acc = ACCEL_GET_CLASS(accel); - if (acc->gdbstub_supported_sstep_flags) { - return acc->gdbstub_supported_sstep_flags(accel); - } - return 0; -} - static const TypeInfo accel_types[] = { { .name = TYPE_ACCEL, diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c index b74a5779c3..d2276d8513 100644 --- a/accel/hvf/hvf-accel-ops.c +++ b/accel/hvf/hvf-accel-ops.c @@ -62,8 +62,6 @@ HVFState *hvf_state; -/* Memory slots */ - static void do_hvf_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg) { if (!cpu->vcpu_dirty) { @@ -235,7 +233,8 @@ int hvf_update_guest_debug(CPUState *cpu) return 0; } -static int hvf_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len) +static int hvf_insert_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType type, + vaddr addr, vaddr len) { struct hvf_sw_breakpoint *bp; int err; @@ -258,7 +257,7 @@ static int hvf_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len) QTAILQ_INSERT_HEAD(&hvf_state->hvf_sw_breakpoints, bp, entry); } else { - err = hvf_arch_insert_hw_breakpoint(addr, len, type); + err = hvf_arch_insert_gdbstub_hw_breakpoint(addr, len, type); if (err) { return err; } @@ -273,7 +272,8 @@ static int hvf_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len) return 0; } -static int hvf_remove_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len) +static int hvf_remove_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType type, + vaddr addr, vaddr len) { struct hvf_sw_breakpoint *bp; int err; @@ -297,7 +297,7 @@ static int hvf_remove_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len) QTAILQ_REMOVE(&hvf_state->hvf_sw_breakpoints, bp, entry); g_free(bp); } else { - err = hvf_arch_remove_hw_breakpoint(addr, len, type); + err = hvf_arch_remove_gdbstub_hw_breakpoint(addr, len, type); if (err) { return err; } @@ -312,7 +312,7 @@ static int hvf_remove_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len) return 0; } -static void hvf_remove_all_breakpoints(CPUState *cpu) +static void hvf_remove_all_gdbstub_breakpoints(CPUState *cpu) { struct hvf_sw_breakpoint *bp, *next; CPUState *tmpcpu; @@ -330,7 +330,7 @@ static void hvf_remove_all_breakpoints(CPUState *cpu) QTAILQ_REMOVE(&hvf_state->hvf_sw_breakpoints, bp, entry); g_free(bp); } - hvf_arch_remove_all_hw_breakpoints(); + hvf_arch_remove_all_gdbstub_hw_breakpoints(); CPU_FOREACH(cpu) { hvf_update_guest_debug(cpu); @@ -367,11 +367,10 @@ static void hvf_accel_ops_class_init(ObjectClass *oc, const void *data) ops->synchronize_state = hvf_cpu_synchronize_state; ops->synchronize_pre_loadvm = hvf_cpu_synchronize_pre_loadvm; - ops->insert_breakpoint = hvf_insert_breakpoint; - ops->remove_breakpoint = hvf_remove_breakpoint; - ops->remove_all_breakpoints = hvf_remove_all_breakpoints; + ops->insert_gdbstub_breakpoint = hvf_insert_gdbstub_breakpoint; + ops->remove_gdbstub_breakpoint = hvf_remove_gdbstub_breakpoint; + ops->remove_all_gdbstub_breakpoints = hvf_remove_all_gdbstub_breakpoints; ops->update_guest_debug = hvf_update_guest_debug; - ops->supports_guest_debug = hvf_arch_supports_guest_debug; ops->get_vcpu_stats = hvf_get_vcpu_stats; }; diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c index 21b9b71a6d..8bd9154a50 100644 --- a/accel/hvf/hvf-all.c +++ b/accel/hvf/hvf-all.c @@ -220,6 +220,8 @@ static int hvf_accel_init(AccelState *as, MachineState *ms) } assert_hvf_ok(ret); + as->gdbstub.sstep_flags = SSTEP_ENABLE | SSTEP_NOIRQ; + QTAILQ_INIT(&s->hvf_sw_breakpoints); hvf_state = s; @@ -228,11 +230,6 @@ static int hvf_accel_init(AccelState *as, MachineState *ms) return hvf_arch_init(); } -static int hvf_gdbstub_sstep_flags(AccelState *as) -{ - return SSTEP_ENABLE | SSTEP_NOIRQ; -} - static void hvf_set_kernel_irqchip(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) @@ -278,7 +275,6 @@ static void hvf_accel_class_init(ObjectClass *oc, const void *data) ac->name = "HVF"; ac->init_machine = hvf_accel_init; ac->allowed = &hvf_allowed; - ac->gdbstub_supported_sstep_flags = hvf_gdbstub_sstep_flags; hvf_kernel_irqchip_override = false; hvf_kernel_irqchip = false; object_class_property_add(oc, "kernel-irqchip", "on|off|split", diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c index 6d9140e549..c8e7aa3870 100644 --- a/accel/kvm/kvm-accel-ops.c +++ b/accel/kvm/kvm-accel-ops.c @@ -107,10 +107,9 @@ static void kvm_accel_ops_class_init(ObjectClass *oc, const void *data) #ifdef TARGET_KVM_HAVE_GUEST_DEBUG ops->update_guest_debug = kvm_update_guest_debug_ops; - ops->supports_guest_debug = kvm_supports_guest_debug; - ops->insert_breakpoint = kvm_insert_breakpoint; - ops->remove_breakpoint = kvm_remove_breakpoint; - ops->remove_all_breakpoints = kvm_remove_all_breakpoints; + ops->insert_gdbstub_breakpoint = kvm_insert_gdbstub_breakpoint; + ops->remove_gdbstub_breakpoint = kvm_remove_gdbstub_breakpoint; + ops->remove_all_gdbstub_breakpoints = kvm_remove_all_gdbstub_breakpoints; #endif } diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 5d55cb45cf..83cbd120a8 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -104,8 +104,6 @@ bool kvm_readonly_mem_allowed; bool kvm_vm_attributes_allowed; bool kvm_msi_use_devid; bool kvm_pre_fault_memory_supported; -static bool kvm_has_guest_debug; -static int kvm_sstep_flags; static bool kvm_immediate_exit; static uint64_t kvm_supported_memory_attributes; static bool kvm_guest_memfd_supported; @@ -3038,23 +3036,17 @@ static int kvm_init(AccelState *as, MachineState *ms) (kvm_check_extension(s, KVM_CAP_VM_ATTRIBUTES) > 0); #ifdef TARGET_KVM_HAVE_GUEST_DEBUG - kvm_has_guest_debug = - (kvm_check_extension(s, KVM_CAP_SET_GUEST_DEBUG) > 0); -#endif - - kvm_sstep_flags = 0; - if (kvm_has_guest_debug) { - kvm_sstep_flags = SSTEP_ENABLE; + if (kvm_check_extension(s, KVM_CAP_SET_GUEST_DEBUG) > 0) { + as->gdbstub.sstep_flags = SSTEP_ENABLE; -#if defined TARGET_KVM_HAVE_GUEST_DEBUG int guest_debug_flags = kvm_check_extension(s, KVM_CAP_SET_GUEST_DEBUG2); if (guest_debug_flags & KVM_GUESTDBG_BLOCKIRQ) { - kvm_sstep_flags |= SSTEP_NOIRQ; + as->gdbstub.sstep_flags |= SSTEP_NOIRQ; } -#endif } +#endif kvm_state = s; @@ -3820,10 +3812,10 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap) data.dbg.control = reinject_trap; - if (cpu->singlestep_enabled) { + if (cpu_single_stepping(cpu)) { data.dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP; - if (cpu->singlestep_enabled & SSTEP_NOIRQ) { + if (cpu->singlestep_flags & SSTEP_NOIRQ) { data.dbg.control |= KVM_GUESTDBG_BLOCKIRQ; } } @@ -3834,13 +3826,8 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap) return data.err; } -bool kvm_supports_guest_debug(void) -{ - /* probed during kvm_init() */ - return kvm_has_guest_debug; -} - -int kvm_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len) +int kvm_insert_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType type, + vaddr addr, vaddr len) { struct kvm_sw_breakpoint *bp; int err; @@ -3863,7 +3850,7 @@ int kvm_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len) QTAILQ_INSERT_HEAD(&cpu->kvm_state->kvm_sw_breakpoints, bp, entry); } else { - err = kvm_arch_insert_hw_breakpoint(addr, len, type); + err = kvm_arch_insert_gdbstub_hw_breakpoint(addr, len, type); if (err) { return err; } @@ -3878,7 +3865,8 @@ int kvm_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len) return 0; } -int kvm_remove_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len) +int kvm_remove_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType type, + vaddr addr, vaddr len) { struct kvm_sw_breakpoint *bp; int err; @@ -3902,7 +3890,7 @@ int kvm_remove_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len) QTAILQ_REMOVE(&cpu->kvm_state->kvm_sw_breakpoints, bp, entry); g_free(bp); } else { - err = kvm_arch_remove_hw_breakpoint(addr, len, type); + err = kvm_arch_remove_gdbstub_hw_breakpoint(addr, len, type); if (err) { return err; } @@ -3917,7 +3905,7 @@ int kvm_remove_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len) return 0; } -void kvm_remove_all_breakpoints(CPUState *cpu) +void kvm_remove_all_gdbstub_breakpoints(CPUState *cpu) { struct kvm_sw_breakpoint *bp, *next; KVMState *s = cpu->kvm_state; @@ -3935,7 +3923,7 @@ void kvm_remove_all_breakpoints(CPUState *cpu) QTAILQ_REMOVE(&s->kvm_sw_breakpoints, bp, entry); g_free(bp); } - kvm_arch_remove_all_hw_breakpoints(); + kvm_arch_remove_all_gdbstub_hw_breakpoints(); CPU_FOREACH(cpu) { kvm_update_guest_debug(cpu, 0); @@ -4281,17 +4269,6 @@ static void kvm_accel_instance_init(Object *obj) s->honor_guest_pat = ON_OFF_AUTO_OFF; } -/** - * kvm_gdbstub_sstep_flags(): - * - * Returns: SSTEP_* flags that KVM supports for guest debug. The - * support is probed during kvm_init() - */ -static int kvm_gdbstub_sstep_flags(AccelState *as) -{ - return kvm_sstep_flags; -} - static void kvm_accel_class_init(ObjectClass *oc, const void *data) { AccelClass *ac = ACCEL_CLASS(oc); @@ -4300,7 +4277,6 @@ static void kvm_accel_class_init(ObjectClass *oc, const void *data) ac->rebuild_guest = kvm_reset_vmfd; ac->has_memory = kvm_accel_has_memory; ac->allowed = &kvm_allowed; - ac->gdbstub_supported_sstep_flags = kvm_gdbstub_sstep_flags; object_class_property_add(oc, "kernel-irqchip", "on|off|split", NULL, kvm_set_kernel_irqchip, diff --git a/accel/kvm/kvm-cpus.h b/accel/kvm/kvm-cpus.h index 688511151c..bc2dd82e68 100644 --- a/accel/kvm/kvm-cpus.h +++ b/accel/kvm/kvm-cpus.h @@ -10,14 +10,18 @@ #ifndef KVM_CPUS_H #define KVM_CPUS_H +#include "gdbstub/enums.h" + int kvm_init_vcpu(CPUState *cpu, Error **errp); int kvm_cpu_exec(CPUState *cpu); void kvm_destroy_vcpu(CPUState *cpu); void kvm_cpu_synchronize_post_reset(CPUState *cpu); void kvm_cpu_synchronize_post_init(CPUState *cpu); void kvm_cpu_synchronize_pre_loadvm(CPUState *cpu); -bool kvm_supports_guest_debug(void); -int kvm_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len); -int kvm_remove_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len); -void kvm_remove_all_breakpoints(CPUState *cpu); +int kvm_insert_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType type, + vaddr addr, vaddr len); +int kvm_remove_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType type, + vaddr addr, vaddr len); +void kvm_remove_all_gdbstub_breakpoints(CPUState *cpu); + #endif /* KVM_CPUS_H */ diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c index 9452504ac2..72721d0f0d 100644 --- a/accel/mshv/mshv-all.c +++ b/accel/mshv/mshv-all.c @@ -167,7 +167,7 @@ static int get_proc_features(int vm_fd, ret = get_partition_property(vm_fd, HV_PARTITION_PROPERTY_PROCESSOR_FEATURES0, - features[0].as_uint64); + &features->as_uint64[0]); if (ret < 0) { error_report("Failed to get processor features bank 0"); return -1; @@ -175,7 +175,7 @@ static int get_proc_features(int vm_fd, ret = get_partition_property(vm_fd, HV_PARTITION_PROPERTY_PROCESSOR_FEATURES1, - features[1].as_uint64); + &features->as_uint64[1]); if (ret < 0) { error_report("Failed to get processor features bank 1"); return -1; @@ -531,7 +531,7 @@ static int mshv_init_vcpu(CPUState *cpu) } mshv_arch_init_vcpu(cpu); - cpu->accel->dirty = true; + cpu->vcpu_dirty = true; return 0; } @@ -617,7 +617,7 @@ static int mshv_cpu_exec(CPUState *cpu) cpu_exec_start(cpu); do { - if (cpu->accel->dirty) { + if (cpu->vcpu_dirty) { ret = mshv_arch_store_vcpu_state(cpu); if (ret) { error_report("Failed to put registers after init: %s", @@ -625,7 +625,7 @@ static int mshv_cpu_exec(CPUState *cpu) ret = -1; break; } - cpu->accel->dirty = false; + cpu->vcpu_dirty = false; } ret = mshv_run_vcpu(mshv_state->vm, cpu, &mshv_msg, &exit_reason); @@ -746,7 +746,7 @@ static void do_mshv_cpu_synchronize_post_init(CPUState *cpu, abort(); } - cpu->accel->dirty = false; + cpu->vcpu_dirty = false; } static void mshv_cpu_synchronize_post_init(CPUState *cpu) @@ -763,13 +763,13 @@ static void mshv_cpu_synchronize_post_reset(CPUState *cpu) cpu_dump_state(cpu, stderr, CPU_DUMP_CODE); vm_stop(RUN_STATE_INTERNAL_ERROR); } - cpu->accel->dirty = false; + cpu->vcpu_dirty = false; } static void do_mshv_cpu_synchronize_pre_loadvm(CPUState *cpu, run_on_cpu_data arg) { - cpu->accel->dirty = true; + cpu->vcpu_dirty = true; } static void mshv_cpu_synchronize_pre_loadvm(CPUState *cpu) @@ -779,7 +779,7 @@ static void mshv_cpu_synchronize_pre_loadvm(CPUState *cpu) static void do_mshv_cpu_synchronize(CPUState *cpu, run_on_cpu_data arg) { - if (!cpu->accel->dirty) { + if (!cpu->vcpu_dirty) { int ret = mshv_arch_load_vcpu_state(cpu); if (ret < 0) { error_report("Failed to load registers for vcpu %d", @@ -789,13 +789,13 @@ static void do_mshv_cpu_synchronize(CPUState *cpu, run_on_cpu_data arg) vm_stop(RUN_STATE_INTERNAL_ERROR); } - cpu->accel->dirty = true; + cpu->vcpu_dirty = true; } } static void mshv_cpu_synchronize(CPUState *cpu) { - if (!cpu->accel->dirty) { + if (!cpu->vcpu_dirty) { run_on_cpu(cpu, do_mshv_cpu_synchronize, RUN_ON_CPU_NULL); } } diff --git a/accel/tcg/cpu-exec-common.c b/accel/tcg/cpu-exec-common.c index e48ea31373..44e84344f3 100644 --- a/accel/tcg/cpu-exec-common.c +++ b/accel/tcg/cpu-exec-common.c @@ -47,7 +47,7 @@ uint32_t curr_cflags(CPUState *cpu) * For singlestep and -d nochain, suppress goto_tb so that * we can log -d cpu,exec after every TB. */ - if (unlikely(cpu->singlestep_enabled)) { + if (unlikely(cpu_single_stepping(cpu))) { cflags |= CF_NO_GOTO_TB | CF_NO_GOTO_PTR | CF_SINGLE_STEP | 1; } else if (qatomic_read(&one_insn_per_tb)) { cflags |= CF_NO_GOTO_TB | 1; diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 9c754b0365..257211235d 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -308,7 +308,7 @@ static bool check_for_breakpoints_slow(CPUState *cpu, vaddr pc, * so that one could (gdb) singlestep into the guest kernel's * architectural breakpoint handler. */ - if (cpu->singlestep_enabled) { + if (cpu_single_stepping(cpu)) { return false; } @@ -460,7 +460,7 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit) * counter hit zero); we must restore the guest PC to the address * of the start of the TB. */ - CPUClass *cc = cpu->cc; + const CPUClass *cc = cpu->cc; const TCGCPUOps *tcg_ops = cc->tcg_ops; if (tcg_ops->synchronize_from_tb) { @@ -485,7 +485,7 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit) * raise a debug exception. Single-step with another exception * is handled in cpu_handle_exception. */ - if (unlikely(cpu->singlestep_enabled) && cpu->exception_index == -1) { + if (unlikely(cpu_single_stepping(cpu)) && cpu->exception_index == -1) { cpu->exception_index = EXCP_DEBUG; cpu_loop_exit(cpu); } @@ -732,7 +732,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) bql_unlock(); cpu->exception_index = -1; - if (unlikely(cpu->singlestep_enabled)) { + if (unlikely(cpu_single_stepping(cpu))) { /* * After processing the exception, ensure an EXCP_DEBUG is * raised when single-stepping so that GDB doesn't miss the @@ -828,7 +828,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, return true; } - if (unlikely(cpu->singlestep_enabled & SSTEP_NOIRQ)) { + if (unlikely(cpu->singlestep_flags & SSTEP_NOIRQ)) { /* Mask out external interrupts for this step. */ interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK; } @@ -849,7 +849,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, * raised when single-stepping so that GDB doesn't miss the * next instruction. */ - if (unlikely(cpu->singlestep_enabled)) { + if (unlikely(cpu_single_stepping(cpu))) { cpu->exception_index = EXCP_DEBUG; bql_unlock(); return true; diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 6e66f3c6e9..7f7c208ba1 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1,5 +1,5 @@ /* - * Common CPU TLB handling + * Common CPU TLB handling (system emulation) * * Copyright (c) 2003 Fabrice Bellard * @@ -47,6 +47,7 @@ #include "tb-hash.h" #include "tlb-bounds.h" #include "internal-common.h" +#include "system-page-protection.h" #ifdef CONFIG_PLUGIN #include "qemu/plugin-memory.h" #endif diff --git a/accel/tcg/system-page-protection.h b/accel/tcg/system-page-protection.h new file mode 100644 index 0000000000..52896c6d24 --- /dev/null +++ b/accel/tcg/system-page-protection.h @@ -0,0 +1,17 @@ +/* + * QEMU page protection (system emulation) + * + * Copyright (c) 2003 Fabrice Bellard + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ +#ifndef SYSTEM_PAGE_PROTECTION_H +#define SYSTEM_PAGE_PROTECTION_H + +#include "system/ram_addr.h" + +void tlb_protect_code(ram_addr_t ram_addr); +void tlb_unprotect_code(ram_addr_t ram_addr); + +#endif + diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index c33dbf65e7..4313864d2c 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -38,6 +38,7 @@ #include "user/page-protection.h" #define runstate_is_running() true #else +#include "system-page-protection.h" #include "system/runstate.h" #endif #include "trace.h" diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c index 5b132d3d5d..cdaa3e1180 100644 --- a/accel/tcg/tcg-accel-ops-rr.c +++ b/accel/tcg/tcg-accel-ops-rr.c @@ -274,7 +274,7 @@ static void *rr_cpu_thread_fn(void *arg) current_cpu = cpu; qemu_clock_enable(QEMU_CLOCK_VIRTUAL, - (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0); + (cpu->singlestep_flags & SSTEP_NOTIMER) == 0); if (cpu_can_run(cpu)) { int r; diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c index c179cd4ade..560fe2554b 100644 --- a/accel/tcg/tcg-accel-ops.c +++ b/accel/tcg/tcg-accel-ops.c @@ -109,13 +109,8 @@ void tcg_handle_interrupt(CPUState *cpu, int mask) } } -static bool tcg_supports_guest_debug(void) -{ - return true; -} - /* Translate GDB watchpoint type to a flags value for cpu_watchpoint_* */ -static inline int xlat_gdb_type(CPUState *cpu, int gdbtype) +static inline int xlat_gdb_type(CPUState *cpu, GdbBreakpointType gdbtype) { static const int xlat[] = { [GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE, @@ -131,7 +126,8 @@ static inline int xlat_gdb_type(CPUState *cpu, int gdbtype) return cputype; } -static int tcg_insert_breakpoint(CPUState *cs, int type, vaddr addr, vaddr len) +static int tcg_insert_gdbstub_breakpoint(CPUState *cs, GdbBreakpointType type, + vaddr addr, vaddr len) { CPUState *cpu; int err = 0; @@ -162,7 +158,8 @@ static int tcg_insert_breakpoint(CPUState *cs, int type, vaddr addr, vaddr len) } } -static int tcg_remove_breakpoint(CPUState *cs, int type, vaddr addr, vaddr len) +static int tcg_remove_gdbstub_breakpoint(CPUState *cs, GdbBreakpointType type, + vaddr addr, vaddr len) { CPUState *cpu; int err = 0; @@ -193,7 +190,7 @@ static int tcg_remove_breakpoint(CPUState *cs, int type, vaddr addr, vaddr len) } } -static inline void tcg_remove_all_breakpoints(CPUState *cpu) +static void tcg_remove_all_gdbstub_breakpoints(CPUState *cpu) { cpu_breakpoint_remove_all(cpu, BP_GDB); cpu_watchpoint_remove_all(cpu, BP_GDB); @@ -221,10 +218,9 @@ static void tcg_accel_ops_init(AccelClass *ac) } ops->cpu_reset_hold = tcg_cpu_reset_hold; - ops->supports_guest_debug = tcg_supports_guest_debug; - ops->insert_breakpoint = tcg_insert_breakpoint; - ops->remove_breakpoint = tcg_remove_breakpoint; - ops->remove_all_breakpoints = tcg_remove_all_breakpoints; + ops->insert_gdbstub_breakpoint = tcg_insert_gdbstub_breakpoint; + ops->remove_gdbstub_breakpoint = tcg_remove_gdbstub_breakpoint; + ops->remove_all_gdbstub_breakpoints = tcg_remove_all_gdbstub_breakpoints; } static void tcg_accel_ops_class_init(ObjectClass *oc, const void *data) diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 8eb4a6b89e..7186c10cf0 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -149,6 +149,20 @@ static int tcg_init_machine(AccelState *as, MachineState *ms) tcg_allowed = true; + as->gdbstub.sstep_flags = SSTEP_ENABLE; + if (replay_mode == REPLAY_MODE_NONE) { + /* + * In replay mode all events will come from the log and can't be + * suppressed otherwise we would break determinism. However as those + * events are tied to the number of executed instructions we won't see + * them occurring every time we single step. + */ + as->gdbstub.sstep_flags |= SSTEP_NOIRQ | SSTEP_NOTIMER; + } + if (replay_mode == REPLAY_MODE_PLAY) { + as->gdbstub.can_reverse = true; + } + page_init(); tb_htable_init(); tcg_init(s->tb_size * MiB, s->splitwx_enabled, max_threads); @@ -242,21 +256,6 @@ static void tcg_set_one_insn_per_tb(Object *obj, bool value, Error **errp) qatomic_set(&one_insn_per_tb, value); } -static int tcg_gdbstub_supported_sstep_flags(AccelState *as) -{ - /* - * In replay mode all events will come from the log and can't be - * suppressed otherwise we would break determinism. However as those - * events are tied to the number of executed instructions we won't see - * them occurring every time we single step. - */ - if (replay_mode != REPLAY_MODE_NONE) { - return SSTEP_ENABLE; - } else { - return SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER; - } -} - static void tcg_accel_class_init(ObjectClass *oc, const void *data) { AccelClass *ac = ACCEL_CLASS(oc); @@ -266,7 +265,6 @@ static void tcg_accel_class_init(ObjectClass *oc, const void *data) ac->cpu_common_unrealize = tcg_exec_unrealizefn; ac->get_stats = tcg_get_stats; ac->allowed = &tcg_allowed; - ac->gdbstub_supported_sstep_flags = tcg_gdbstub_supported_sstep_flags; object_class_property_add_str(oc, "thread", tcg_get_thread, diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 3f1a3a2843..328d96aba3 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -575,7 +575,7 @@ void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr) void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) { TranslationBlock *tb; - CPUClass *cc; + const CPUClass *cc = cpu->cc; uint32_t n; tb = tcg_tb_lookup(retaddr); @@ -591,7 +591,6 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) * to account for the re-execution of the branch. */ n = 1; - cc = cpu->cc; if (cc->tcg_ops->io_recompile_replay_branch && cc->tcg_ops->io_recompile_replay_branch(cpu, tb)) { cpu->neg.icount_decr.u16.low++; diff --git a/accel/whpx/whpx-accel-ops.c b/accel/whpx/whpx-accel-ops.c index b8f41544cb..ca5a119521 100644 --- a/accel/whpx/whpx-accel-ops.c +++ b/accel/whpx/whpx-accel-ops.c @@ -82,11 +82,6 @@ static bool whpx_vcpu_thread_is_idle(CPUState *cpu) return !whpx_irqchip_in_kernel(); } -static bool whpx_supports_guest_debug(void) -{ - return whpx_arch_supports_guest_debug(); -} - static void whpx_accel_ops_class_init(ObjectClass *oc, const void *data) { @@ -96,7 +91,6 @@ static void whpx_accel_ops_class_init(ObjectClass *oc, const void *data) ops->kick_vcpu_thread = whpx_kick_vcpu_thread; ops->cpu_thread_is_idle = whpx_vcpu_thread_is_idle; ops->handle_interrupt = generic_handle_interrupt; - ops->supports_guest_debug = whpx_supports_guest_debug; ops->synchronize_post_reset = whpx_cpu_synchronize_post_reset; ops->synchronize_post_init = whpx_cpu_synchronize_post_init; diff --git a/cpu-common.c b/cpu-common.c index 988d057d84..adb76b3a78 100644 --- a/cpu-common.c +++ b/cpu-common.c @@ -388,6 +388,21 @@ void process_queued_cpu_work(CPUState *cpu) qemu_cond_broadcast(&qemu_work_cond); } +/* Return true if PC matches an installed breakpoint. */ +bool cpu_breakpoint_test(CPUState *cpu, vaddr pc, int mask) +{ + CPUBreakpoint *bp; + + if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) { + QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) { + if (bp->pc == pc && (bp->flags & mask)) { + return true; + } + } + } + return false; +} + /* Add a breakpoint. */ int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags, CPUBreakpoint **breakpoint) diff --git a/cpu-target.c b/cpu-target.c index f030e2c642..4783845c9b 100644 --- a/cpu-target.c +++ b/cpu-target.c @@ -28,10 +28,12 @@ /* enable or disable single step mode. EXCP_DEBUG is returned by the CPU loop after each instruction */ -void cpu_single_step(CPUState *cpu, int enabled) +void cpu_single_step(CPUState *cpu, unsigned flags) { - if (cpu->singlestep_enabled != enabled) { - cpu->singlestep_enabled = enabled; + if (cpu->singlestep_flags != flags) { + trace_cpu_change_singlestep_flags(cpu->cpu_index, + cpu->singlestep_flags, flags); + cpu->singlestep_flags = flags; #if !defined(CONFIG_USER_ONLY) const AccelOpsClass *ops = cpus_get_accel(); @@ -39,8 +41,6 @@ void cpu_single_step(CPUState *cpu, int enabled) ops->update_guest_debug(cpu); } #endif - - trace_breakpoint_singlestep(cpu->cpu_index, enabled); } } diff --git a/docs/system/gdb.rst b/docs/system/gdb.rst index d50470b135..b6d8f8e77d 100644 --- a/docs/system/gdb.rst +++ b/docs/system/gdb.rst @@ -54,7 +54,7 @@ While GDB can always fall back to inserting breakpoints into memory accelerator. For TCG system emulation we advertise an infinite number of hardware assisted breakpoints and watchpoints. For other accelerators it will depend on if support has been added (see -supports_guest_debug and related hooks in AccelOpsClass). +the AccelGdbConfig structure). As TCG cannot track all memory accesses in user-mode there is no support for watchpoints. diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index c3c944e965..0a328b0dd4 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -72,9 +72,9 @@ void gdb_init_gdbserver_state(void) * By default try to use no IRQs and no timers while single * stepping so as to make single stepping like a typical ICE HW step. */ - gdbserver_state.supported_sstep_flags = accel_supported_gdbstub_sstep_flags(); + gdbserver_state.accel_config = current_accel()->gdbstub; gdbserver_state.sstep_flags = SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER; - gdbserver_state.sstep_flags &= gdbserver_state.supported_sstep_flags; + gdbserver_state.sstep_flags &= gdbserver_state.accel_config.sstep_flags; } /* writes 2*len+1 bytes in buf */ @@ -578,7 +578,7 @@ static void gdb_register_feature(CPUState *cpu, int base_reg, static const char *gdb_get_core_xml_file(CPUState *cpu) { - CPUClass *cc = cpu->cc; + const CPUClass *cc = cpu->cc; /* * The CPU class can provide the XML filename via a method, @@ -1369,14 +1369,16 @@ static void handle_step(GArray *params, void *user_ctx) gdb_set_cpu_pc(gdb_get_cmd_param(params, 0)->val_ull); } + trace_gdbstub_op_stepping(gdbserver_state.c_cpu->cpu_index); cpu_single_step(gdbserver_state.c_cpu, gdbserver_state.sstep_flags); gdb_continue(); } static void handle_backward(GArray *params, void *user_ctx) { - if (!gdb_can_reverse()) { + if (!gdbserver_state.accel_config.can_reverse) { gdb_put_packet("E22"); + return; } if (params->len == 1) { switch (gdb_get_cmd_param(params, 0)->opcode) { @@ -1535,12 +1537,12 @@ static void handle_query_qemu_sstepbits(GArray *params, void *user_ctx) { g_string_printf(gdbserver_state.str_buf, "ENABLE=%x", SSTEP_ENABLE); - if (gdbserver_state.supported_sstep_flags & SSTEP_NOIRQ) { + if (gdbserver_state.accel_config.sstep_flags & SSTEP_NOIRQ) { g_string_append_printf(gdbserver_state.str_buf, ",NOIRQ=%x", SSTEP_NOIRQ); } - if (gdbserver_state.supported_sstep_flags & SSTEP_NOTIMER) { + if (gdbserver_state.accel_config.sstep_flags & SSTEP_NOTIMER) { g_string_append_printf(gdbserver_state.str_buf, ",NOTIMER=%x", SSTEP_NOTIMER); } @@ -1558,7 +1560,7 @@ static void handle_set_qemu_sstep(GArray *params, void *user_ctx) new_sstep_flags = gdb_get_cmd_param(params, 0)->val_ul; - if (new_sstep_flags & ~gdbserver_state.supported_sstep_flags) { + if (new_sstep_flags & ~gdbserver_state.accel_config.sstep_flags) { gdb_put_packet("E22"); return; } @@ -1682,7 +1684,7 @@ static void handle_query_supported(GArray *params, void *user_ctx) g_string_append(gdbserver_state.str_buf, ";qXfer:features:read+"); } - if (gdb_can_reverse()) { + if (gdbserver_state.accel_config.can_reverse) { g_string_append(gdbserver_state.str_buf, ";ReverseStep+;ReverseContinue+"); } diff --git a/gdbstub/internals.h b/gdbstub/internals.h index 9b25bf58b8..33f68672d1 100644 --- a/gdbstub/internals.h +++ b/gdbstub/internals.h @@ -9,7 +9,9 @@ #ifndef GDBSTUB_INTERNALS_H #define GDBSTUB_INTERNALS_H +#include "qemu/accel.h" #include "exec/cpu-common.h" +#include "gdbstub/enums.h" /* * Most "large" transfers (e.g. memory reads, feature XML @@ -83,8 +85,8 @@ typedef struct GDBState { int process_num; GString *str_buf; GByteArray *mem_buf; + AccelGdbConfig accel_config; int sstep_flags; - int supported_sstep_flags; /* * Whether we are allowed to send a stop reply packet at this moment. * Must be set off after sending the stop reply itself. @@ -153,7 +155,6 @@ CPUState *gdb_first_attached_cpu(void); void gdb_append_thread_id(CPUState *cpu, GString *buf); int gdb_get_cpu_index(CPUState *cpu); unsigned int gdb_get_max_cpus(void); /* both */ -bool gdb_can_reverse(void); /* system emulation, stub for user */ int gdb_target_sigtrap(void); /* user */ void gdb_create_default_process(GDBState *s); @@ -217,9 +218,10 @@ void gdb_syscall_handling(const char *syscall_packet); * Break/Watch point support - there is an implementation for system * and user mode. */ -bool gdb_supports_guest_debug(void); -int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len); -int gdb_breakpoint_remove(CPUState *cs, int type, vaddr addr, vaddr len); +int gdb_breakpoint_insert(CPUState *cs, GdbBreakpointType type, + vaddr addr, vaddr len); +int gdb_breakpoint_remove(CPUState *cs, GdbBreakpointType type, + vaddr addr, vaddr len); void gdb_breakpoint_remove_all(CPUState *cs); /** diff --git a/gdbstub/system.c b/gdbstub/system.c index 2063b63b2f..3098fd5574 100644 --- a/gdbstub/system.c +++ b/gdbstub/system.c @@ -125,7 +125,6 @@ static void gdb_vm_state_change(void *opaque, bool running, RunState state) CPUState *cpu = gdbserver_state.c_cpu; g_autoptr(GString) buf = g_string_new(NULL); g_autoptr(GString) tid = g_string_new(NULL); - const char *type; int ret; if (running || gdbserver_state.state == RS_INACTIVE) { @@ -151,6 +150,8 @@ static void gdb_vm_state_change(void *opaque, bool running, RunState state) switch (state) { case RUN_STATE_DEBUG: if (cpu->watchpoint_hit) { + const char *type; + switch (cpu->watchpoint_hit->flags & BP_MEM_ACCESS) { case BP_MEM_READ: type = "r"; @@ -343,7 +344,7 @@ bool gdbserver_start(const char *device, Error **errp) return false; } - if (!gdb_supports_guest_debug()) { + if (!accel_supports_guest_debug(current_accel())) { error_setg(errp, "gdbstub: current accelerator doesn't " "support guest debugging"); return false; @@ -477,11 +478,6 @@ unsigned int gdb_get_max_cpus(void) return ms->smp.max_cpus; } -bool gdb_can_reverse(void) -{ - return replay_mode == REPLAY_MODE_PLAY; -} - /* * Softmmu specific command helpers */ @@ -627,29 +623,22 @@ int gdb_signal_to_target(int sig) * Break/Watch point helpers */ -bool gdb_supports_guest_debug(void) -{ - const AccelOpsClass *ops = cpus_get_accel(); - if (ops->supports_guest_debug) { - return ops->supports_guest_debug(); - } - return false; -} - -int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len) +int gdb_breakpoint_insert(CPUState *cs, GdbBreakpointType type, + vaddr addr, vaddr len) { const AccelOpsClass *ops = cpus_get_accel(); - if (ops->insert_breakpoint) { - return ops->insert_breakpoint(cs, type, addr, len); + if (ops->insert_gdbstub_breakpoint) { + return ops->insert_gdbstub_breakpoint(cs, type, addr, len); } return -ENOSYS; } -int gdb_breakpoint_remove(CPUState *cs, int type, vaddr addr, vaddr len) +int gdb_breakpoint_remove(CPUState *cs, GdbBreakpointType type, + vaddr addr, vaddr len) { const AccelOpsClass *ops = cpus_get_accel(); - if (ops->remove_breakpoint) { - return ops->remove_breakpoint(cs, type, addr, len); + if (ops->remove_gdbstub_breakpoint) { + return ops->remove_gdbstub_breakpoint(cs, type, addr, len); } return -ENOSYS; } @@ -657,8 +646,8 @@ int gdb_breakpoint_remove(CPUState *cs, int type, vaddr addr, vaddr len) void gdb_breakpoint_remove_all(CPUState *cs) { const AccelOpsClass *ops = cpus_get_accel(); - if (ops->remove_all_breakpoints) { - ops->remove_all_breakpoints(cs); + if (ops->remove_all_gdbstub_breakpoints) { + ops->remove_all_gdbstub_breakpoints(cs); } } diff --git a/gdbstub/user.c b/gdbstub/user.c index 97eb13e796..9e6f9a6f37 100644 --- a/gdbstub/user.c +++ b/gdbstub/user.c @@ -557,7 +557,7 @@ static void disable_gdbstub(CPUState *thread_cpu) close(gdbserver_user_state.fd); gdbserver_user_state.fd = -1; CPU_FOREACH(cpu) { - cpu_breakpoint_remove_all(cpu, BP_GDB); + gdb_breakpoint_remove_all(cpu); /* no cpu_watchpoint_remove_all for user-mode */ cpu_single_step(cpu, 0); } @@ -786,23 +786,12 @@ unsigned int gdb_get_max_cpus(void) return max_cpus; } -/* replay not supported for user-mode */ -bool gdb_can_reverse(void) -{ - return false; -} - /* * Break/Watch point helpers */ -bool gdb_supports_guest_debug(void) -{ - /* user-mode == TCG == supported */ - return true; -} - -int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len) +int gdb_breakpoint_insert(CPUState *cs, GdbBreakpointType type, + vaddr addr, vaddr len) { CPUState *cpu; int err = 0; @@ -823,7 +812,8 @@ int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len) } } -int gdb_breakpoint_remove(CPUState *cs, int type, vaddr addr, vaddr len) +int gdb_breakpoint_remove(CPUState *cs, GdbBreakpointType type, + vaddr addr, vaddr len) { CPUState *cpu; int err = 0; diff --git a/include/accel/accel-cpu-ops.h b/include/accel/accel-cpu-ops.h index 9c07a903ea..f0c7ee7542 100644 --- a/include/accel/accel-cpu-ops.h +++ b/include/accel/accel-cpu-ops.h @@ -13,6 +13,7 @@ #include "qemu/accel.h" #include "exec/vaddr.h" #include "qom/object.h" +#include "gdbstub/enums.h" #define ACCEL_OPS_SUFFIX "-ops" #define TYPE_ACCEL_OPS "accel" ACCEL_OPS_SUFFIX @@ -84,11 +85,12 @@ struct AccelOpsClass { int64_t (*get_elapsed_ticks)(void); /* gdbstub hooks */ - bool (*supports_guest_debug)(void); int (*update_guest_debug)(CPUState *cpu); - int (*insert_breakpoint)(CPUState *cpu, int type, vaddr addr, vaddr len); - int (*remove_breakpoint)(CPUState *cpu, int type, vaddr addr, vaddr len); - void (*remove_all_breakpoints)(CPUState *cpu); + int (*insert_gdbstub_breakpoint)(CPUState *cpu, GdbBreakpointType type, + vaddr addr, vaddr len); + int (*remove_gdbstub_breakpoint)(CPUState *cpu, GdbBreakpointType type, + vaddr addr, vaddr len); + void (*remove_all_gdbstub_breakpoints)(CPUState *cpu); }; void generic_handle_interrupt(CPUState *cpu, int mask); diff --git a/include/accel/accel-ops.h b/include/accel/accel-ops.h index f46492e3fe..9f3f329c44 100644 --- a/include/accel/accel-ops.h +++ b/include/accel/accel-ops.h @@ -13,6 +13,8 @@ struct AccelState { Object parent_obj; + + AccelGdbConfig gdbstub; }; struct AccelClass { @@ -36,9 +38,6 @@ struct AccelClass { bool (*has_memory)(AccelState *accel, AddressSpace *as, hwaddr start_addr, hwaddr size); - /* gdbstub related hooks */ - int (*gdbstub_supported_sstep_flags)(AccelState *as); - bool *allowed; /* * Array of global properties that would be applied when specific diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h index 710da12b82..3ff6e6810e 100644 --- a/include/accel/tcg/cpu-ops.h +++ b/include/accel/tcg/cpu-ops.h @@ -250,14 +250,13 @@ struct TCGCPUOps { int mmu_idx, uintptr_t retaddr); /** - * @adjust_watchpoint_address: hack for cpu_check_watchpoint used by ARM + * @adjust_watchpoint_address: hack for cpu_check_watchpoint (used by ARM) */ vaddr (*adjust_watchpoint_address)(CPUState *cpu, vaddr addr, int len); /** * @debug_check_watchpoint: return true if the architectural - * watchpoint whose address has matched should really fire, used by ARM - * and RISC-V + * watchpoint whose address has matched should really fire. */ bool (*debug_check_watchpoint)(CPUState *cpu, CPUWatchpoint *wp); diff --git a/include/exec/breakpoint.h b/include/exec/breakpoint.h index 95f0482e6d..cc6fedd09f 100644 --- a/include/exec/breakpoint.h +++ b/include/exec/breakpoint.h @@ -12,6 +12,20 @@ #include "exec/vaddr.h" #include "exec/memattrs.h" +/* Breakpoint/watchpoint flags */ +#define BP_MEM_READ 0x01 +#define BP_MEM_WRITE 0x02 +#define BP_MEM_ACCESS (BP_MEM_READ | BP_MEM_WRITE) +#define BP_STOP_BEFORE_ACCESS 0x04 +/* 0x08 currently unused */ +#define BP_GDB 0x10 +#define BP_CPU 0x20 +#define BP_ANY (BP_GDB | BP_CPU) +#define BP_HIT_SHIFT 6 +#define BP_WATCHPOINT_HIT_READ (BP_MEM_READ << BP_HIT_SHIFT) +#define BP_WATCHPOINT_HIT_WRITE (BP_MEM_WRITE << BP_HIT_SHIFT) +#define BP_WATCHPOINT_HIT (BP_MEM_ACCESS << BP_HIT_SHIFT) + typedef struct CPUBreakpoint { vaddr pc; int flags; /* BP_* */ diff --git a/include/exec/cputlb.h b/include/exec/cputlb.h index 3a9603a696..f7f7020382 100644 --- a/include/exec/cputlb.h +++ b/include/exec/cputlb.h @@ -24,14 +24,10 @@ #include "exec/hwaddr.h" #include "exec/memattrs.h" #include "exec/vaddr.h" -#include "system/ram_addr.h" - -#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) -void tlb_protect_code(ram_addr_t ram_addr); -void tlb_unprotect_code(ram_addr_t ram_addr); -#endif #ifndef CONFIG_USER_ONLY +#include "system/ram_addr.h" + void tlb_reset_dirty(CPUState *cpu, uintptr_t start, uintptr_t length); void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length); #endif diff --git a/include/gdbstub/enums.h b/include/gdbstub/enums.h index c4d54a1d08..e4e2043d92 100644 --- a/include/gdbstub/enums.h +++ b/include/gdbstub/enums.h @@ -12,10 +12,12 @@ #define DEFAULT_GDBSTUB_PORT "1234" /* GDB breakpoint/watchpoint types */ -#define GDB_BREAKPOINT_SW 0 -#define GDB_BREAKPOINT_HW 1 -#define GDB_WATCHPOINT_WRITE 2 -#define GDB_WATCHPOINT_READ 3 -#define GDB_WATCHPOINT_ACCESS 4 +typedef enum GdbBreakpointType { + GDB_BREAKPOINT_SW = 0, + GDB_BREAKPOINT_HW = 1, + GDB_WATCHPOINT_WRITE = 2, + GDB_WATCHPOINT_READ = 3, + GDB_WATCHPOINT_ACCESS = 4, +} GdbBreakpointType; #endif /* GDBSTUB_ENUMS_H */ diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 59d601465b..b54035fb13 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -440,7 +440,7 @@ struct qemu_work_item; * @stopped: Indicates the CPU has been artificially stopped. * @unplug: Indicates a pending CPU unplug request. * @crash_occurred: Indicates the OS reported a crash (panic) for this CPU - * @singlestep_enabled: Flags for single-stepping. + * @singlestep_flags: Flags for single-stepping. * @icount_extra: Instructions until next timer event. * @cpu_ases: Pointer to array of CPUAddressSpaces (which define the * AddressSpaces this CPU has) @@ -480,7 +480,7 @@ struct CPUState { /*< private >*/ DeviceState parent_obj; /* cache to avoid expensive CPU_GET_CLASS */ - CPUClass *cc; + const CPUClass *cc; /*< public >*/ int nr_threads; @@ -505,7 +505,7 @@ struct CPUState { int exclusive_context_count; uint32_t cflags_next_tb; uint32_t interrupt_request; - int singlestep_enabled; + unsigned singlestep_flags; int64_t icount_budget; int64_t icount_extra; uint64_t random_seed; @@ -1132,46 +1132,29 @@ void qemu_init_vcpu(CPUState *cpu); /** * cpu_single_step: * @cpu: CPU to the flags for. - * @enabled: Flags to enable. + * @flags: Flags to enable. * * Enables or disables single-stepping for @cpu. */ -void cpu_single_step(CPUState *cpu, int enabled); - -/* Breakpoint/watchpoint flags */ -#define BP_MEM_READ 0x01 -#define BP_MEM_WRITE 0x02 -#define BP_MEM_ACCESS (BP_MEM_READ | BP_MEM_WRITE) -#define BP_STOP_BEFORE_ACCESS 0x04 -/* 0x08 currently unused */ -#define BP_GDB 0x10 -#define BP_CPU 0x20 -#define BP_ANY (BP_GDB | BP_CPU) -#define BP_HIT_SHIFT 6 -#define BP_WATCHPOINT_HIT_READ (BP_MEM_READ << BP_HIT_SHIFT) -#define BP_WATCHPOINT_HIT_WRITE (BP_MEM_WRITE << BP_HIT_SHIFT) -#define BP_WATCHPOINT_HIT (BP_MEM_ACCESS << BP_HIT_SHIFT) +void cpu_single_step(CPUState *cpu, unsigned flags); + +/** + * cpu_single_stepping: + * @cpu: The vCPU to check + * + * Returns whether the vCPU has single-stepping enabled. + */ +static inline bool cpu_single_stepping(const CPUState *cpu) +{ + return cpu->singlestep_flags & SSTEP_ENABLE; +} int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags, CPUBreakpoint **breakpoint); int cpu_breakpoint_remove(CPUState *cpu, vaddr pc, int flags); void cpu_breakpoint_remove_by_ref(CPUState *cpu, CPUBreakpoint *breakpoint); void cpu_breakpoint_remove_all(CPUState *cpu, int mask); - -/* Return true if PC matches an installed breakpoint. */ -static inline bool cpu_breakpoint_test(CPUState *cpu, vaddr pc, int mask) -{ - CPUBreakpoint *bp; - - if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) { - QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) { - if (bp->pc == pc && (bp->flags & mask)) { - return true; - } - } - } - return false; -} +bool cpu_breakpoint_test(CPUState *cpu, vaddr pc, int mask); /** * cpu_get_address_space: diff --git a/include/qemu/accel.h b/include/qemu/accel.h index d3638c7bfd..6f65f1cb89 100644 --- a/include/qemu/accel.h +++ b/include/qemu/accel.h @@ -74,11 +74,16 @@ bool accel_cpu_common_realize(CPUState *cpu, Error **errp); void accel_cpu_common_unrealize(CPUState *cpu); /** - * accel_supported_gdbstub_sstep_flags: + * struct AccelGdbConfig - gdbstub configuration for an accelerator. * - * Returns the supported single step modes for the configured - * accelerator. + * @sstep_flags: Set SSTEP_* flags that accelerator supports for guest debug. + * @can_reverse: Whether reverse mode is supported. */ -int accel_supported_gdbstub_sstep_flags(void); +typedef struct AccelGdbConfig { + unsigned sstep_flags; + bool can_reverse; +} AccelGdbConfig; + +bool accel_supports_guest_debug(AccelState *accel); #endif /* QEMU_ACCEL_H */ diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h index 58fb865eba..a01691ce17 100644 --- a/include/system/hvf_int.h +++ b/include/system/hvf_int.h @@ -13,6 +13,7 @@ #include "qemu/queue.h" #include "exec/vaddr.h" +#include "gdbstub/enums.h" #include "qom/object.h" #include "accel/accel-ops.h" @@ -91,9 +92,11 @@ int hvf_sw_breakpoints_active(CPUState *cpu); int hvf_arch_insert_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp); int hvf_arch_remove_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp); -int hvf_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type); -int hvf_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type); -void hvf_arch_remove_all_hw_breakpoints(void); +int hvf_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type); +int hvf_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type); +void hvf_arch_remove_all_gdbstub_hw_breakpoints(void); /* * hvf_update_guest_debug: @@ -104,11 +107,6 @@ void hvf_arch_remove_all_hw_breakpoints(void); */ int hvf_update_guest_debug(CPUState *cpu); -/* - * Return whether the guest supports debugging. - */ -bool hvf_arch_supports_guest_debug(void); - bool hvf_arch_cpu_realize(CPUState *cpu, Error **errp); uint32_t hvf_arch_get_default_ipa_bit_size(void); uint32_t hvf_arch_get_max_ipa_bit_size(void); diff --git a/include/system/kvm.h b/include/system/kvm.h index cdd1856ac5..714b8c7b01 100644 --- a/include/system/kvm.h +++ b/include/system/kvm.h @@ -17,6 +17,7 @@ #define QEMU_KVM_H #include "exec/memattrs.h" +#include "gdbstub/enums.h" #include "qemu/accel.h" #include "accel/accel-route.h" #include "qom/object.h" @@ -412,9 +413,11 @@ int kvm_arch_insert_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp); int kvm_arch_remove_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp); -int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type); -int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type); -void kvm_arch_remove_all_hw_breakpoints(void); +int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type); +int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type); +void kvm_arch_remove_all_gdbstub_hw_breakpoints(void); void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg); diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h index ba3073888a..b91c4d661a 100644 --- a/include/system/mshv_int.h +++ b/include/system/mshv_int.h @@ -43,7 +43,6 @@ typedef struct MshvHvCallArgs { struct AccelCPUState { int cpufd; - bool dirty; MshvHvCallArgs hvcall_args; }; diff --git a/include/system/whpx-all.h b/include/system/whpx-all.h index 4022571fff..d018e67e4f 100644 --- a/include/system/whpx-all.h +++ b/include/system/whpx-all.h @@ -22,7 +22,4 @@ void whpx_translate_cpu_breakpoints( void whpx_arch_destroy_vcpu(CPUState *cpu); void whpx_arch_accel_class_init(ObjectClass *oc); -/* called by whpx-accel-ops */ -bool whpx_arch_supports_guest_debug(void); - #endif diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c index eecc8d1517..6f27a06da4 100644 --- a/linux-user/riscv/cpu_loop.c +++ b/linux-user/riscv/cpu_loop.c @@ -68,7 +68,7 @@ void cpu_loop(CPURISCVState *env) } else if (ret != -QEMU_ESIGRETURN && ret != -QEMU_ESETPC) { env->gpr[xA0] = ret; } - if (cs->singlestep_enabled) { + if (cpu_single_stepping(cs)) { goto gdbstep; } break; diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c index 67d2a803fb..25f19f725e 100644 --- a/linux-user/s390x/cpu_loop.c +++ b/linux-user/s390x/cpu_loop.c @@ -87,7 +87,7 @@ void cpu_loop(CPUS390XState *env) env->regs[2] = ret; } - if (unlikely(cs->singlestep_enabled)) { + if (unlikely(cpu_single_stepping(cs))) { /* * cpu_tb_exec() did not raise EXCP_DEBUG, because it has seen * that EXCP_SVC was already pending. diff --git a/stubs/replay-mode.c b/stubs/replay-mode.c index 439d97e4a8..5bc8f7d658 100644 --- a/stubs/replay-mode.c +++ b/stubs/replay-mode.c @@ -1,4 +1,4 @@ #include "qemu/osdep.h" #include "system/replay.h" -ReplayMode replay_mode; +ReplayMode replay_mode = REPLAY_MODE_NONE; diff --git a/system/cpus.c b/system/cpus.c index b31c825b46..97e5a5edee 100644 --- a/system/cpus.c +++ b/system/cpus.c @@ -344,7 +344,7 @@ bool cpu_can_run(CPUState *cpu) void cpu_handle_guest_debug(CPUState *cpu) { if (replay_running_debug()) { - if (!cpu->singlestep_enabled) { + if (!cpu_single_stepping(cpu)) { /* * Report about the breakpoint and * make a single step to skip it diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 6310cfaf3e..da3ec521fc 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -2338,7 +2338,7 @@ static int hvf_handle_exception(CPUState *cpu, hv_vcpu_exit_exception_t *excp) case EC_SOFTWARESTEP: { ret = EXCP_DEBUG; - if (!cpu->singlestep_enabled) { + if (!cpu_single_stepping(cpu)) { error_report("EC_SOFTWARESTEP but single-stepping not enabled"); } break; @@ -2547,7 +2547,7 @@ static int hvf_handle_exception(CPUState *cpu, hv_vcpu_exit_exception_t *excp) assert_hvf_ok(r); /* Handle single-stepping over instructions which trigger a VM exit */ - if (cpu->singlestep_enabled) { + if (cpu_single_stepping(cpu)) { ret = EXCP_DEBUG; } } @@ -2601,7 +2601,7 @@ int hvf_arch_vcpu_exec(CPUState *cpu) flush_cpu_state(cpu); do { - if (!(cpu->singlestep_enabled & SSTEP_NOIRQ) && + if (!(cpu->singlestep_flags & SSTEP_NOIRQ) && hvf_inject_interrupts(cpu)) { return EXCP_INTERRUPT; } @@ -2724,7 +2724,8 @@ int hvf_arch_remove_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp) return 0; } -int hvf_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) +int hvf_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { switch (type) { case GDB_BREAKPOINT_HW: @@ -2732,13 +2733,14 @@ int hvf_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) case GDB_WATCHPOINT_READ: case GDB_WATCHPOINT_WRITE: case GDB_WATCHPOINT_ACCESS: - return insert_hw_watchpoint(addr, len, type); + return insert_gdbstub_hw_watchpoint(addr, len, type); default: return -ENOSYS; } } -int hvf_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) +int hvf_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { switch (type) { case GDB_BREAKPOINT_HW: @@ -2746,13 +2748,13 @@ int hvf_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) case GDB_WATCHPOINT_READ: case GDB_WATCHPOINT_WRITE: case GDB_WATCHPOINT_ACCESS: - return delete_hw_watchpoint(addr, len, type); + return delete_gdbstub_hw_watchpoint(addr, len, type); default: return -ENOSYS; } } -void hvf_arch_remove_all_hw_breakpoints(void) +void hvf_arch_remove_all_gdbstub_hw_breakpoints(void) { if (cur_hw_wps > 0) { g_array_remove_range(hw_watchpoints, 0, cur_hw_wps); @@ -2864,7 +2866,7 @@ void hvf_arch_update_guest_debug(CPUState *cpu) CPUARMState *env = &arm_cpu->env; /* Check whether guest debugging is enabled */ - cpu->accel->guest_debug_enabled = cpu->singlestep_enabled || + cpu->accel->guest_debug_enabled = cpu_single_stepping(cpu) || hvf_sw_breakpoints_active(cpu) || hvf_arm_hw_debug_active(cpu); @@ -2878,7 +2880,7 @@ void hvf_arch_update_guest_debug(CPUState *cpu) cpu_synchronize_state(cpu); /* Enable/disable single-stepping */ - if (cpu->singlestep_enabled) { + if (cpu_single_stepping(cpu)) { env->cp15.mdscr_el1 = deposit64(env->cp15.mdscr_el1, MDSCR_EL1_SS_SHIFT, 1, 1); pstate_write(env, pstate_read(env) | PSTATE_SS); @@ -2898,8 +2900,3 @@ void hvf_arch_update_guest_debug(CPUState *cpu) hvf_arch_set_traps(cpu); } - -bool hvf_arch_supports_guest_debug(void) -{ - return true; -} diff --git a/target/arm/hyp_gdbstub.c b/target/arm/hyp_gdbstub.c index bb5969720c..dda6946dda 100644 --- a/target/arm/hyp_gdbstub.c +++ b/target/arm/hyp_gdbstub.c @@ -94,7 +94,7 @@ int delete_hw_breakpoint(vaddr pc) } /** - * insert_hw_watchpoint() + * insert_gdbstub_hw_watchpoint() * @addr: address of watch point * @len: size of area * @type: type of watch point @@ -125,7 +125,7 @@ int delete_hw_breakpoint(vaddr pc) * need to ensure you mask the address as required and set BAS=0xff */ -int insert_hw_watchpoint(vaddr addr, vaddr len, int type) +int insert_gdbstub_hw_watchpoint(vaddr addr, vaddr len, GdbBreakpointType type) { HWWatchpoint wp = { .wcr = R_DBGWCR_E_MASK, /* E=1, enable */ @@ -208,13 +208,13 @@ bool check_watchpoint_in_range(int i, vaddr addr) } /** - * delete_hw_watchpoint() + * delete_gdbstub_hw_watchpoint() * @addr: address of breakpoint * * Delete a breakpoint and shuffle any above down */ -int delete_hw_watchpoint(vaddr addr, vaddr len, int type) +int delete_gdbstub_hw_watchpoint(vaddr addr, vaddr len, GdbBreakpointType type) { int i; for (i = 0; i < cur_hw_wps; i++) { diff --git a/target/arm/internals.h b/target/arm/internals.h index a50290383d..4026f67579 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -29,6 +29,7 @@ #include "exec/vaddr.h" #include "exec/breakpoint.h" #include "exec/memop.h" +#include "gdbstub/enums.h" #ifdef CONFIG_TCG #include "accel/tcg/tb-cpu-state.h" #include "tcg/tcg-gvec-desc.h" @@ -1976,8 +1977,8 @@ int delete_hw_breakpoint(vaddr pc); bool check_watchpoint_in_range(int i, vaddr addr); CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, vaddr addr); -int insert_hw_watchpoint(vaddr addr, vaddr len, int type); -int delete_hw_watchpoint(vaddr addr, vaddr len, int type); +int insert_gdbstub_hw_watchpoint(vaddr addr, vaddr len, GdbBreakpointType type); +int delete_gdbstub_hw_watchpoint(vaddr addr, vaddr len, GdbBreakpointType type); /* Return the current value of the system counter in ticks */ uint64_t gt_get_countervalue(CPUARMState *env); diff --git a/target/arm/kvm.c b/target/arm/kvm.c index a54ef51ec2..d40a6a9859 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -1492,7 +1492,7 @@ static bool kvm_arm_handle_debug(ARMCPU *cpu, switch (hsr_ec) { case EC_SOFTWARESTEP: - if (cs->singlestep_enabled) { + if (cpu_single_stepping(cs)) { return true; } else { /* @@ -1784,7 +1784,8 @@ void kvm_arch_accel_class_init(ObjectClass *oc) "Eager Page Split chunk size for hugepages. (default: 0, disabled)"); } -int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) +int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { switch (type) { case GDB_BREAKPOINT_HW: @@ -1793,13 +1794,14 @@ int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) case GDB_WATCHPOINT_READ: case GDB_WATCHPOINT_WRITE: case GDB_WATCHPOINT_ACCESS: - return insert_hw_watchpoint(addr, len, type); + return insert_gdbstub_hw_watchpoint(addr, len, type); default: return -ENOSYS; } } -int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) +int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { switch (type) { case GDB_BREAKPOINT_HW: @@ -1807,13 +1809,13 @@ int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) case GDB_WATCHPOINT_READ: case GDB_WATCHPOINT_WRITE: case GDB_WATCHPOINT_ACCESS: - return delete_hw_watchpoint(addr, len, type); + return delete_gdbstub_hw_watchpoint(addr, len, type); default: return -ENOSYS; } } -void kvm_arch_remove_all_hw_breakpoints(void) +void kvm_arch_remove_all_gdbstub_hw_breakpoints(void) { if (cur_hw_wps > 0) { g_array_remove_range(hw_watchpoints, 0, cur_hw_wps); diff --git a/target/arm/tcg/debug.c b/target/arm/tcg/debug.c index 07a52643e7..528d2889c3 100644 --- a/target/arm/tcg/debug.c +++ b/target/arm/tcg/debug.c @@ -351,28 +351,6 @@ static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp) return true; } -static bool check_watchpoints(ARMCPU *cpu) -{ - CPUARMState *env = &cpu->env; - int n; - - /* - * If watchpoints are disabled globally or we can't take debug - * exceptions here then watchpoint firings are ignored. - */ - if (extract32(env->cp15.mdscr_el1, 15, 1) == 0 - || !arm_generate_debug_exceptions(env)) { - return false; - } - - for (n = 0; n < ARRAY_SIZE(env->cpu_watchpoint); n++) { - if (bp_wp_matches(cpu, n, true)) { - return true; - } - } - return false; -} - bool arm_debug_check_breakpoint(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); @@ -426,8 +404,24 @@ bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp) * is also an architectural watchpoint match. */ ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + int n; - return check_watchpoints(cpu); + /* + * If watchpoints are disabled globally or we can't take debug + * exceptions here then watchpoint firings are ignored. + */ + if (extract32(env->cp15.mdscr_el1, 15, 1) == 0 + || !arm_generate_debug_exceptions(env)) { + return false; + } + + for (n = 0; n < ARRAY_SIZE(env->cpu_watchpoint); n++) { + if (bp_wp_matches(cpu, n, true)) { + return true; + } + } + return false; } /* diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c index 3079c6293c..00a5de8cdc 100644 --- a/target/arm/whpx/whpx-all.c +++ b/target/arm/whpx/whpx-all.c @@ -295,11 +295,6 @@ void whpx_translate_cpu_breakpoints( /* Breakpoints aren’t supported on this platform */ } -bool whpx_arch_supports_guest_debug(void) -{ - return false; -} - void whpx_arch_destroy_vcpu(CPUState *cpu) { /* currently empty on Arm */ diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 2d1a943b96..150598418e 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -1049,25 +1049,22 @@ int hvf_arch_remove_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp) return -ENOSYS; } -int hvf_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) +int hvf_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { return -ENOSYS; } -int hvf_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) +int hvf_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { return -ENOSYS; } -void hvf_arch_remove_all_hw_breakpoints(void) +void hvf_arch_remove_all_gdbstub_hw_breakpoints(void) { } void hvf_arch_update_guest_debug(CPUState *cpu) { } - -bool hvf_arch_supports_guest_debug(void) -{ - return false; -} diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 64cc421abe..4272b6770c 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -6159,12 +6159,12 @@ int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) static struct { target_ulong addr; int len; - int type; + GdbBreakpointType type; } hw_breakpoint[4]; static int nb_hw_breakpoint; -static int find_hw_breakpoint(target_ulong addr, int len, int type) +static int find_hw_breakpoint(target_ulong addr, int len, GdbBreakpointType type) { int n; @@ -6177,7 +6177,8 @@ static int find_hw_breakpoint(target_ulong addr, int len, int type) return -1; } -int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) +int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { switch (type) { case GDB_BREAKPOINT_HW: @@ -6217,7 +6218,8 @@ int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) return 0; } -int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) +int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { int n; @@ -6231,7 +6233,7 @@ int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) return 0; } -void kvm_arch_remove_all_hw_breakpoints(void) +void kvm_arch_remove_all_gdbstub_hw_breakpoints(void) { nb_hw_breakpoint = 0; } @@ -6248,7 +6250,7 @@ static int kvm_handle_debug(X86CPU *cpu, if (arch_info->exception == EXCP01_DB) { if (arch_info->dr6 & DR6_BS) { - if (cs->singlestep_enabled) { + if (cpu_single_stepping(cs)) { ret = EXCP_DEBUG; } } else { diff --git a/target/i386/machine.c b/target/i386/machine.c index 1f5c517e56..df0e0c178e 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -401,7 +401,6 @@ static int cpu_post_load(void *opaque, int version_id) env->dr[7] = dr7 & ~(DR7_GLOBAL_BP_MASK | DR7_LOCAL_BP_MASK); cpu_x86_update_dr7(env, dr7); } - tlb_flush(cs); return 0; } diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c index 126ca40b48..1c433c408c 100644 --- a/target/i386/mshv/mshv-cpu.c +++ b/target/i386/mshv/mshv-cpu.c @@ -1692,7 +1692,7 @@ static int pio_write(uint64_t port, const uint8_t *data, uintptr_t size, return ret; } -static int handle_pio_non_str(const CPUState *cpu, +static int handle_pio_non_str(CPUState *cpu, hv_x64_io_port_intercept_message *info) { size_t len = info->access_info.access_size; @@ -1748,7 +1748,7 @@ static int handle_pio_non_str(const CPUState *cpu, return -1; } - cpu->accel->dirty = false; + cpu->vcpu_dirty = false; return 0; } @@ -1909,7 +1909,7 @@ static int handle_pio_str(CPUState *cpu, hv_x64_io_port_intercept_message *info) return -1; } - cpu->accel->dirty = false; + cpu->vcpu_dirty = false; return 0; } diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index e626acef2f..634d542821 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -1853,11 +1853,6 @@ void whpx_apply_breakpoints( } } -bool whpx_arch_supports_guest_debug(void) -{ - return true; -} - void whpx_arch_destroy_vcpu(CPUState *cpu) { X86CPU *x86cpu = X86_CPU(cpu); @@ -2271,7 +2266,7 @@ int whpx_vcpu_run(CPUState *cpu) } } - if (exclusive_step_mode != WHPX_STEP_NONE || cpu->singlestep_enabled) { + if (exclusive_step_mode != WHPX_STEP_NONE || cpu_single_stepping(cpu)) { whpx_vcpu_configure_single_stepping(cpu, true, NULL); } @@ -2288,7 +2283,7 @@ int whpx_vcpu_run(CPUState *cpu) break; } - if (exclusive_step_mode != WHPX_STEP_NONE || cpu->singlestep_enabled) { + if (exclusive_step_mode != WHPX_STEP_NONE || cpu_single_stepping(cpu)) { whpx_vcpu_configure_single_stepping(cpu, false, &vcpu->exit_ctx.VpContext.Rflags); @@ -2653,7 +2648,7 @@ int whpx_vcpu_run(CPUState *cpu) cpu->exception_index = EXCP_DEBUG; } else if ((vcpu->exit_ctx.VpException.ExceptionType == WHvX64ExceptionTypeDebugTrapOrFault) && - !cpu->singlestep_enabled) { + !cpu_single_stepping(cpu)) { /* * Just finished stepping over a breakpoint, but the * gdb does not expect us to do single-stepping. @@ -3343,6 +3338,8 @@ int whpx_accel_init(AccelState *as, MachineState *ms) whpx_memory_init(); whpx_init_emu(); + as->gdbstub.sstep_flags = SSTEP_ENABLE; + return 0; error: diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c index d6539c12ac..48cdb78a4c 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -1418,17 +1418,19 @@ int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) return 0; } -int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) +int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { return -ENOSYS; } -int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) +int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { return -ENOSYS; } -void kvm_arch_remove_all_hw_breakpoints(void) +void kvm_arch_remove_all_gdbstub_hw_breakpoints(void) { } @@ -1438,7 +1440,7 @@ static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run) CPULoongArchState *env = &cpu->env; kvm_cpu_synchronize_state(cs); - if (cs->singlestep_enabled) { + if (cpu_single_stepping(cs)) { return true; } diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index a93f14d6e0..8b219afb5d 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1772,7 +1772,7 @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) } /* Finish DISAS_EXIT_* */ - if (unlikely(cs->singlestep_enabled)) { + if (unlikely(cpu_single_stepping(cs))) { gen_raise_exception(dc, EXCP_DEBUG); } else { tcg_gen_exit_tb(NULL, 0); diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c index 41edb18643..47467ee163 100644 --- a/target/ppc/cpu.c +++ b/target/ppc/cpu.c @@ -147,6 +147,8 @@ void ppc_update_daw(CPUPPCState *env, int rid) vaddr len; int flags; + assert(tcg_enabled()); + if (env->dawr_watchpoint[rid]) { cpu_watchpoint_remove_by_ref(cs, env->dawr_watchpoint[rid]); env->dawr_watchpoint[rid] = NULL; diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 78a1c4a839..116b39a00f 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -455,7 +455,7 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu) static struct HWBreakpoint { target_ulong addr; - int type; + GdbBreakpointType type; } hw_debug_points[MAX_HW_BKPTS]; static CPUWatchpoint hw_watchpoint; @@ -1412,7 +1412,7 @@ int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) return 0; } -static int find_hw_breakpoint(target_ulong addr, int type) +static int find_hw_breakpoint(target_ulong addr, GdbBreakpointType type) { int n; @@ -1454,7 +1454,8 @@ static int find_hw_watchpoint(target_ulong addr, int *flag) return -1; } -int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) +int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { const unsigned breakpoint_index = nb_hw_breakpoint + nb_hw_watchpoint; if (breakpoint_index >= ARRAY_SIZE(hw_debug_points)) { @@ -1498,7 +1499,8 @@ int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) return 0; } -int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) +int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { int n; @@ -1526,7 +1528,7 @@ int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) return 0; } -void kvm_arch_remove_all_hw_breakpoints(void) +void kvm_arch_remove_all_gdbstub_hw_breakpoints(void) { nb_hw_breakpoint = nb_hw_watchpoint = 0; } @@ -1613,7 +1615,7 @@ static int kvm_handle_debug(PowerPCCPU *cpu, struct kvm_run *run) CPUPPCState *env = &cpu->env; struct kvm_debug_exit_arch *arch_info = &run->debug.arch; - if (cs->singlestep_enabled) { + if (cpu_single_stepping(cs)) { return kvm_handle_singlestep(); } diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 3f6d326cef..06ed2adf10 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -198,7 +198,7 @@ struct DisasContext { bool pmu_insn_cnt; bool bhrb_enable; ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ - int singlestep_enabled; + int singlestep_flags; uint32_t flags; uint64_t insns_flags; uint64_t insns_flags2; @@ -367,7 +367,7 @@ static void gen_debug_exception(DisasContext *ctx, bool rfi_type) #if !defined(CONFIG_USER_ONLY) if (ctx->flags & POWERPC_FLAG_DE) { target_ulong dbsr = 0; - if (ctx->singlestep_enabled & CPU_SINGLE_STEP) { + if (ctx->singlestep_flags & CPU_SINGLE_STEP) { dbsr = DBCR0_ICMP; } else { /* Must have been branch */ @@ -3645,7 +3645,7 @@ static void pmu_count_insns(DisasContext *ctx) static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) { - if (unlikely(ctx->singlestep_enabled)) { + if (unlikely(ctx->singlestep_flags)) { return false; } return translator_use_goto_tb(&ctx->base, dest); @@ -3653,7 +3653,7 @@ static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) static void gen_lookup_and_goto_ptr(DisasContext *ctx) { - if (unlikely(ctx->singlestep_enabled)) { + if (unlikely(ctx->singlestep_flags)) { gen_debug_exception(ctx, false); } else { /* @@ -6559,13 +6559,13 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->pmu_insn_cnt = (hflags >> HFLAGS_INSN_CNT) & 1; ctx->bhrb_enable = (hflags >> HFLAGS_BHRB_ENABLE) & 1; - ctx->singlestep_enabled = 0; + ctx->singlestep_flags = 0; if ((hflags >> HFLAGS_SE) & 1) { - ctx->singlestep_enabled |= CPU_SINGLE_STEP; + ctx->singlestep_flags |= CPU_SINGLE_STEP; ctx->base.max_insns = 1; } if ((hflags >> HFLAGS_BE) & 1) { - ctx->singlestep_enabled |= CPU_BRANCH_STEP; + ctx->singlestep_flags |= CPU_BRANCH_STEP; } } @@ -6641,7 +6641,7 @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) } /* Honor single stepping. */ - if (unlikely(ctx->singlestep_enabled & CPU_SINGLE_STEP)) { + if (unlikely(ctx->singlestep_flags & CPU_SINGLE_STEP)) { bool rfi_type = false; switch (is_jmp) { diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 39d48a9db4..2a5440d584 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -2215,19 +2215,21 @@ int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) return 0; } -int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) +int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { /* TODO; To be implemented later. */ return -EINVAL; } -int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) +int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { /* TODO; To be implemented later. */ return -EINVAL; } -void kvm_arch_remove_all_hw_breakpoints(void) +void kvm_arch_remove_all_gdbstub_hw_breakpoints(void) { /* TODO; To be implemented later. */ } diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index fdef8f9e8a..19ddf59e00 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -907,7 +907,8 @@ static int insert_hw_breakpoint(vaddr addr, int len, int type) return 0; } -int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) +int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { switch (type) { case GDB_BREAKPOINT_HW: @@ -925,7 +926,8 @@ int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) return insert_hw_breakpoint(addr, len, type); } -int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) +int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len, + GdbBreakpointType type) { int size; struct kvm_hw_breakpoint *bp = find_hw_breakpoint(addr, len, type); @@ -954,7 +956,7 @@ int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) return 0; } -void kvm_arch_remove_all_hw_breakpoints(void) +void kvm_arch_remove_all_gdbstub_hw_breakpoints(void) { nb_hw_breakpoints = 0; g_free(hw_breakpoints); @@ -1872,7 +1874,7 @@ static int kvm_arch_handle_debug_exit(S390CPU *cpu) } break; case KVM_SINGLESTEP: - if (cs->singlestep_enabled) { + if (cpu_single_stepping(cs)) { ret = EXCP_DEBUG; } break; diff --git a/trace-events b/trace-events index faeba6242f..ea1d2b11a2 100644 --- a/trace-events +++ b/trace-events @@ -28,7 +28,7 @@ # cpu.c breakpoint_insert(int cpu_index, uint64_t pc, int flags) "cpu=%d pc=0x%" PRIx64 " flags=0x%x" breakpoint_remove(int cpu_index, uint64_t pc, int flags) "cpu=%d pc=0x%" PRIx64 " flags=0x%x" -breakpoint_singlestep(int cpu_index, int enabled) "cpu=%d enable=%d" +cpu_change_singlestep_flags(int cpu_index, int old_flags, int new_flags) "cpu=%d flags=0x%x -> 0x%x" cpu_exec_start(int cpu_index) "cpu=%d" cpu_exec_end(int cpu_index) "cpu=%d" |
