From patchwork Tue Sep 27 14:15:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Alex_Benn=C3=A9e?= X-Patchwork-Id: 609615 Delivered-To: patch@linaro.org Received: by 2002:a17:522:c983:b0:460:3032:e3c4 with SMTP id kr3csp431777pvb; Tue, 27 Sep 2022 08:57:55 -0700 (PDT) X-Google-Smtp-Source: AMsMyM6H3ACfVTAxRvNX0/vi7oOMCQ9RedRBJq5PBxNYY0vBByv0qC6M6RkC/gPSBMxKZKdI6Rpb X-Received: by 2002:ad4:5cc1:0:b0:4a7:dbb4:1118 with SMTP id iu1-20020ad45cc1000000b004a7dbb41118mr22295783qvb.84.1664294275009; Tue, 27 Sep 2022 08:57:55 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1664294275; cv=none; d=google.com; s=arc-20160816; b=qNQzHhDfd13LraPmx7Zq7qTtYVWJgDs07HE8/sBD3gVg61pybXMxKAh0hUzHEc3pL0 TqV53xG2+HmpO0eGbl4RPElWPj1LsFQODdAkx2Jv2Fc5+9y+O1AcDlv0xfOXgFBEds5o A9089sShG6cqVM8Po8MwXdDaqLCv67Sgcggcn7W9m8KAHF+D35XKxVIhbaIeIbxJBwwk 8uoeyuJZkvxgqud8ShfNCC5cVETe4z0EUeVIxRAgL1pP0oNUKhqkskNtZ82V+b4Lj2eP 8jpmxSAzRAJdDl918Y9tNohltMurFfA0PN4Nmu9HF7NUQ07MO+yQlfrX6Ruqp7Cnq3/J bT8w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=fTabJPCIPlhP85UMkzUVWmjvUxpiXA1PS7vvmHzeVyk=; b=ktc6iysGhX+QFvs8LNqdq+usLnokxO2h6sZI3imNxYmwjchuU9kDdFrLXTEF17Ibue laLU5f1rDAz9L0+dPSSEpTim+ioT7SwvYZXNrsXxnQkox57rMbRVYpAvbOdaPtuNivyg 8ELec7215dZUs4kMMqZ4GwI88Ah0qxC1oL8EhRIhK5UAWU3egNzWM/1ucJQBWrZH5T6J ipIZY/y6U9gkCOyOA27Y744YxLTcnAjcKr8NQT/M/+3iLE/WGWlcniifGTrjbfED4siy +rfFRwLWbt0EB0OcFIbyyY0IsXidae9+lj8pWd1X8bebuZP/ttmE/wHYalQYTVGHB9Nr 0Kww== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=lwckCi7R; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id 8-20020a0562140d0800b004ad1a00d349si1160711qvh.281.2022.09.27.08.57.54 for (version=TLS1_2 cipher=ECDHE-ECDSA-CHACHA20-POLY1305 bits=256/256); Tue, 27 Sep 2022 08:57:54 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=lwckCi7R; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([::1]:36248 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1odCy2-0007wp-Gs for patch@linaro.org; Tue, 27 Sep 2022 11:57:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45292) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1odBMq-0005IK-Oh for qemu-devel@nongnu.org; Tue, 27 Sep 2022 10:15:24 -0400 Received: from mail-wm1-x32d.google.com ([2a00:1450:4864:20::32d]:39529) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1odBMl-000625-TW for qemu-devel@nongnu.org; Tue, 27 Sep 2022 10:15:24 -0400 Received: by mail-wm1-x32d.google.com with SMTP id e10-20020a05600c4e4a00b003b4eff4ab2cso9514679wmq.4 for ; Tue, 27 Sep 2022 07:15:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date; bh=fTabJPCIPlhP85UMkzUVWmjvUxpiXA1PS7vvmHzeVyk=; b=lwckCi7R/CY+POaFVOCZaTOc0LImUUDH9/3CXVxQvkpq74L824UkYznKqqsBUSnIcY qKZlkAgu1F6eTHcdkYmUIQ6L5Aet46WqYBo8vbaXNf0CrHU1oSlWUb1XfaVat6daMmI8 KiTwI42aP6sBUJuof6/yGR8qptDYMLjnvCSW+nyN9dDuv0lffe6EpwRlgHgnv0sXYhrN uYJE8dL8fsFJUisyVlIZtoJ0O0HTZmm4y1VO3sOT6p1vC5uz/Jz1sjA9uHgpnshvU9PC 3+tdWLTI6M7+ryqo67BPc6J4unNmu9dbyD2VugPukwkwmdG7/Con65NdwUC48dxXbXKB OvSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date; bh=fTabJPCIPlhP85UMkzUVWmjvUxpiXA1PS7vvmHzeVyk=; b=eOwZN6lPBcPmbMrB8tBCGtGdB14CwilF8FqT+yhZhP4SGnS7aTn4NoPcj6tJDKkOtk FjbRZZzgCvawtD7Kfo+eiuE9NtV2BH8yaHBjuKqC30ftC7wa+3DCMFBRex9v0QarrtIj 8ATVcYumcNwG5/WKYo3ZYBXyZzJtZ9u4eS+D6t8iVyBXh/EI7IvMbWQUjnZ0LjG0ERiW 3a1Qke37WPUgtqOGQrvy/mGGj5RO2xjlSkouwBawgLR2zrMDIKa3qN4K7zh6i43E7GXx q08HYcOoYRV2nR7CxDfWlqzXwShAOczrtyLLIR6H8E04ky8ZpiPEhKF2onPl5F2hggO3 vdrQ== X-Gm-Message-State: ACrzQf0qKTAZe5JgDLsWf+C8pE2UqP/HHoZnfHNSryuUSpka0RuWbGDT djR9taUqgsWOvP5UyDpQv325YA== X-Received: by 2002:a7b:c4cc:0:b0:3b4:757b:492f with SMTP id g12-20020a7bc4cc000000b003b4757b492fmr2980454wmk.74.1664288115692; Tue, 27 Sep 2022 07:15:15 -0700 (PDT) Received: from zen.linaroharston ([185.81.254.11]) by smtp.gmail.com with ESMTPSA id t11-20020a05600c41cb00b003b31fc77407sm13907811wmh.30.2022.09.27.07.15.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Sep 2022 07:15:11 -0700 (PDT) Received: from zen.lan (localhost [127.0.0.1]) by zen.linaroharston (Postfix) with ESMTP id 814AD1FFBB; Tue, 27 Sep 2022 15:15:08 +0100 (BST) From: =?utf-8?q?Alex_Benn=C3=A9e?= To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, =?utf-8?q?Alex_Benn=C3=A9e?= , Richard Henderson , Mads Ynddal , Paolo Bonzini , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , kvm@vger.kernel.org (open list:Overall KVM CPUs) Subject: [PATCH v3 13/15] gdbstub: move breakpoint logic to accel ops Date: Tue, 27 Sep 2022 15:15:02 +0100 Message-Id: <20220927141504.3886314-14-alex.bennee@linaro.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220927141504.3886314-1-alex.bennee@linaro.org> References: <20220927141504.3886314-1-alex.bennee@linaro.org> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::32d; envelope-from=alex.bennee@linaro.org; helo=mail-wm1-x32d.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" As HW virtualization requires specific support to handle breakpoints lets push out special casing out of the core gdbstub code and into AccelOpsClass. This will make it easier to add other accelerator support and reduces some of the stub shenanigans. Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Cc: Mads Ynddal Reviewed-by: Mads Ynddal --- accel/kvm/kvm-cpus.h | 3 + gdbstub/internals.h | 16 +++++ include/sysemu/accel-ops.h | 6 ++ include/sysemu/cpus.h | 3 + include/sysemu/kvm.h | 5 -- accel/kvm/kvm-accel-ops.c | 8 +++ accel/kvm/kvm-all.c | 24 +------ accel/stubs/kvm-stub.c | 16 ----- accel/tcg/tcg-accel-ops.c | 92 +++++++++++++++++++++++++++ gdbstub/gdbstub.c | 127 +++---------------------------------- gdbstub/softmmu.c | 42 ++++++++++++ gdbstub/user.c | 62 ++++++++++++++++++ softmmu/cpus.c | 7 ++ gdbstub/meson.build | 8 +++ 14 files changed, 259 insertions(+), 160 deletions(-) create mode 100644 gdbstub/internals.h create mode 100644 gdbstub/softmmu.c create mode 100644 gdbstub/user.c diff --git a/accel/kvm/kvm-cpus.h b/accel/kvm/kvm-cpus.h index bf0bd1bee4..33e435d62b 100644 --- a/accel/kvm/kvm-cpus.h +++ b/accel/kvm/kvm-cpus.h @@ -18,5 +18,8 @@ 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); +int kvm_insert_breakpoint(CPUState *cpu, int type, hwaddr addr, hwaddr len); +int kvm_remove_breakpoint(CPUState *cpu, int type, hwaddr addr, hwaddr len); +void kvm_remove_all_breakpoints(CPUState *cpu); #endif /* KVM_CPUS_H */ diff --git a/gdbstub/internals.h b/gdbstub/internals.h new file mode 100644 index 0000000000..41e2e72dbf --- /dev/null +++ b/gdbstub/internals.h @@ -0,0 +1,16 @@ +/* + * gdbstub internals + * + * Copyright (c) 2022 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef _INTERNALS_H_ +#define _INTERNALS_H_ + +int gdb_breakpoint_insert(CPUState *cs, int type, hwaddr addr, hwaddr len); +int gdb_breakpoint_remove(CPUState *cs, int type, hwaddr addr, hwaddr len); +void gdb_breakpoint_remove_all(CPUState *cs); + +#endif /* _INTERNALS_H_ */ diff --git a/include/sysemu/accel-ops.h b/include/sysemu/accel-ops.h index a0572ea87a..86794ac273 100644 --- a/include/sysemu/accel-ops.h +++ b/include/sysemu/accel-ops.h @@ -10,6 +10,7 @@ #ifndef ACCEL_OPS_H #define ACCEL_OPS_H +#include "exec/hwaddr.h" #include "qom/object.h" #define ACCEL_OPS_SUFFIX "-ops" @@ -44,6 +45,11 @@ struct AccelOpsClass { int64_t (*get_virtual_clock)(void); int64_t (*get_elapsed_ticks)(void); + + /* gdbstub hooks */ + int (*insert_breakpoint)(CPUState *cpu, int type, hwaddr addr, hwaddr len); + int (*remove_breakpoint)(CPUState *cpu, int type, hwaddr addr, hwaddr len); + void (*remove_all_breakpoints)(CPUState *cpu); }; #endif /* ACCEL_OPS_H */ diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h index b5c87d48b3..1bace3379b 100644 --- a/include/sysemu/cpus.h +++ b/include/sysemu/cpus.h @@ -7,6 +7,9 @@ /* register accel-specific operations */ void cpus_register_accel(const AccelOpsClass *i); +/* return registers ops */ +const AccelOpsClass *cpus_get_accel(void); + /* accel/dummy-cpus.c */ /* Create a dummy vcpu for AccelOpsClass->create_vcpu_thread */ diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index a20ad51aad..21d3f1d01e 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -254,11 +254,6 @@ int kvm_on_sigbus(int code, void *addr); void kvm_flush_coalesced_mmio_buffer(void); -int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type); -int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type); -void kvm_remove_all_breakpoints(CPUState *cpu); int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap); /* internal API */ diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c index c4244a23c6..5c0e37514c 100644 --- a/accel/kvm/kvm-accel-ops.c +++ b/accel/kvm/kvm-accel-ops.c @@ -16,12 +16,14 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" +#include "sysemu/kvm.h" #include "sysemu/kvm_int.h" #include "sysemu/runstate.h" #include "sysemu/cpus.h" #include "qemu/guest-random.h" #include "qapi/error.h" +#include #include "kvm-cpus.h" static void *kvm_vcpu_thread_fn(void *arg) @@ -95,6 +97,12 @@ static void kvm_accel_ops_class_init(ObjectClass *oc, void *data) ops->synchronize_post_init = kvm_cpu_synchronize_post_init; ops->synchronize_state = kvm_cpu_synchronize_state; ops->synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm; + +#ifdef KVM_CAP_SET_GUEST_DEBUG + ops->insert_breakpoint = kvm_insert_breakpoint; + ops->remove_breakpoint = kvm_remove_breakpoint; + ops->remove_all_breakpoints = kvm_remove_all_breakpoints; +#endif } static const TypeInfo kvm_accel_ops_type = { diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index c55938453a..b8c734fe3a 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -3287,8 +3287,7 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap) return data.err; } -int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type) +int kvm_insert_breakpoint(CPUState *cpu, int type, hwaddr addr, hwaddr len) { struct kvm_sw_breakpoint *bp; int err; @@ -3326,8 +3325,7 @@ int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr, return 0; } -int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type) +int kvm_remove_breakpoint(CPUState *cpu, int type, hwaddr addr, hwaddr len) { struct kvm_sw_breakpoint *bp; int err; @@ -3393,26 +3391,10 @@ void kvm_remove_all_breakpoints(CPUState *cpu) #else /* !KVM_CAP_SET_GUEST_DEBUG */ -int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap) +static int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap) { return -EINVAL; } - -int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type) -{ - return -EINVAL; -} - -int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type) -{ - return -EINVAL; -} - -void kvm_remove_all_breakpoints(CPUState *cpu) -{ -} #endif /* !KVM_CAP_SET_GUEST_DEBUG */ static int kvm_set_signal_mask(CPUState *cpu, const sigset_t *sigset) diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c index 2ac5f9c036..2d79333143 100644 --- a/accel/stubs/kvm-stub.c +++ b/accel/stubs/kvm-stub.c @@ -51,22 +51,6 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap) return -ENOSYS; } -int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type) -{ - return -EINVAL; -} - -int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr, - target_ulong len, int type) -{ - return -EINVAL; -} - -void kvm_remove_all_breakpoints(CPUState *cpu) -{ -} - int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr) { return 1; diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c index 786d90c08f..965c2ad581 100644 --- a/accel/tcg/tcg-accel-ops.c +++ b/accel/tcg/tcg-accel-ops.c @@ -32,6 +32,8 @@ #include "qemu/main-loop.h" #include "qemu/guest-random.h" #include "exec/exec-all.h" +#include "exec/hwaddr.h" +#include "exec/gdbstub.h" #include "tcg-accel-ops.h" #include "tcg-accel-ops-mttcg.h" @@ -91,6 +93,92 @@ void tcg_handle_interrupt(CPUState *cpu, int mask) } } +/* Translate GDB watchpoint type to a flags value for cpu_watchpoint_* */ +static inline int xlat_gdb_type(CPUState *cpu, int gdbtype) +{ + static const int xlat[] = { + [GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE, + [GDB_WATCHPOINT_READ] = BP_GDB | BP_MEM_READ, + [GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS, + }; + + CPUClass *cc = CPU_GET_CLASS(cpu); + int cputype = xlat[gdbtype]; + + if (cc->gdb_stop_before_watchpoint) { + cputype |= BP_STOP_BEFORE_ACCESS; + } + return cputype; +} + +static int tcg_insert_breakpoint(CPUState *cs, int type, hwaddr addr, hwaddr len) +{ + CPUState *cpu; + int err = 0; + + switch (type) { + case GDB_BREAKPOINT_SW: + case GDB_BREAKPOINT_HW: + CPU_FOREACH(cpu) { + err = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL); + if (err) { + break; + } + } + return err; + case GDB_WATCHPOINT_WRITE: + case GDB_WATCHPOINT_READ: + case GDB_WATCHPOINT_ACCESS: + CPU_FOREACH(cpu) { + err = cpu_watchpoint_insert(cpu, addr, len, + xlat_gdb_type(cpu, type), NULL); + if (err) { + break; + } + } + return err; + default: + return -ENOSYS; + } +} + +static int tcg_remove_breakpoint(CPUState *cs, int type, hwaddr addr, hwaddr len) +{ + CPUState *cpu; + int err = 0; + + switch (type) { + case GDB_BREAKPOINT_SW: + case GDB_BREAKPOINT_HW: + CPU_FOREACH(cpu) { + err = cpu_breakpoint_remove(cpu, addr, BP_GDB); + if (err) { + break; + } + } + return err; + case GDB_WATCHPOINT_WRITE: + case GDB_WATCHPOINT_READ: + case GDB_WATCHPOINT_ACCESS: + CPU_FOREACH(cpu) { + err = cpu_watchpoint_remove(cpu, addr, len, + xlat_gdb_type(cpu, type)); + if (err) { + break; + } + } + return err; + default: + return -ENOSYS; + } +} + +static inline void tcg_remove_all_breakpoints(CPUState *cpu) +{ + cpu_breakpoint_remove_all(cpu, BP_GDB); + cpu_watchpoint_remove_all(cpu, BP_GDB); +} + static void tcg_accel_ops_init(AccelOpsClass *ops) { if (qemu_tcg_mttcg_enabled()) { @@ -109,6 +197,10 @@ static void tcg_accel_ops_init(AccelOpsClass *ops) ops->handle_interrupt = tcg_handle_interrupt; } } + + ops->insert_breakpoint = tcg_insert_breakpoint; + ops->remove_breakpoint = tcg_remove_breakpoint; + ops->remove_all_breakpoints = tcg_remove_all_breakpoints; } static void tcg_accel_ops_class_init(ObjectClass *oc, void *data) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index a0755e6505..ff9f3f9586 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -49,8 +49,11 @@ #include "sysemu/runstate.h" #include "semihosting/semihost.h" #include "exec/exec-all.h" +#include "exec/hwaddr.h" #include "sysemu/replay.h" +#include "internals.h" + #ifdef CONFIG_USER_ONLY #define GDB_ATTACHED "0" #else @@ -1012,130 +1015,16 @@ void gdb_register_coprocessor(CPUState *cpu, } } -#ifndef CONFIG_USER_ONLY -/* Translate GDB watchpoint type to a flags value for cpu_watchpoint_* */ -static inline int xlat_gdb_type(CPUState *cpu, int gdbtype) -{ - static const int xlat[] = { - [GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE, - [GDB_WATCHPOINT_READ] = BP_GDB | BP_MEM_READ, - [GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS, - }; - - CPUClass *cc = CPU_GET_CLASS(cpu); - int cputype = xlat[gdbtype]; - - if (cc->gdb_stop_before_watchpoint) { - cputype |= BP_STOP_BEFORE_ACCESS; - } - return cputype; -} -#endif - -static int gdb_breakpoint_insert(int type, target_ulong addr, target_ulong len) -{ - CPUState *cpu; - int err = 0; - - if (kvm_enabled()) { - return kvm_insert_breakpoint(gdbserver_state.c_cpu, addr, len, type); - } - - switch (type) { - case GDB_BREAKPOINT_SW: - case GDB_BREAKPOINT_HW: - CPU_FOREACH(cpu) { - err = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL); - if (err) { - break; - } - } - return err; -#ifndef CONFIG_USER_ONLY - case GDB_WATCHPOINT_WRITE: - case GDB_WATCHPOINT_READ: - case GDB_WATCHPOINT_ACCESS: - CPU_FOREACH(cpu) { - err = cpu_watchpoint_insert(cpu, addr, len, - xlat_gdb_type(cpu, type), NULL); - if (err) { - break; - } - } - return err; -#endif - default: - return -ENOSYS; - } -} - -static int gdb_breakpoint_remove(int type, target_ulong addr, target_ulong len) -{ - CPUState *cpu; - int err = 0; - - if (kvm_enabled()) { - return kvm_remove_breakpoint(gdbserver_state.c_cpu, addr, len, type); - } - - switch (type) { - case GDB_BREAKPOINT_SW: - case GDB_BREAKPOINT_HW: - CPU_FOREACH(cpu) { - err = cpu_breakpoint_remove(cpu, addr, BP_GDB); - if (err) { - break; - } - } - return err; -#ifndef CONFIG_USER_ONLY - case GDB_WATCHPOINT_WRITE: - case GDB_WATCHPOINT_READ: - case GDB_WATCHPOINT_ACCESS: - CPU_FOREACH(cpu) { - err = cpu_watchpoint_remove(cpu, addr, len, - xlat_gdb_type(cpu, type)); - if (err) - break; - } - return err; -#endif - default: - return -ENOSYS; - } -} - -static inline void gdb_cpu_breakpoint_remove_all(CPUState *cpu) -{ - cpu_breakpoint_remove_all(cpu, BP_GDB); -#ifndef CONFIG_USER_ONLY - cpu_watchpoint_remove_all(cpu, BP_GDB); -#endif -} - static void gdb_process_breakpoint_remove_all(GDBProcess *p) { CPUState *cpu = get_first_cpu_in_process(p); while (cpu) { - gdb_cpu_breakpoint_remove_all(cpu); + gdb_breakpoint_remove_all(cpu); cpu = gdb_next_cpu_in_process(cpu); } } -static void gdb_breakpoint_remove_all(void) -{ - CPUState *cpu; - - if (kvm_enabled()) { - kvm_remove_all_breakpoints(gdbserver_state.c_cpu); - return; - } - - CPU_FOREACH(cpu) { - gdb_cpu_breakpoint_remove_all(cpu); - } -} static void gdb_set_cpu_pc(target_ulong pc) { @@ -1667,7 +1556,8 @@ static void handle_insert_bp(GArray *params, void *user_ctx) return; } - res = gdb_breakpoint_insert(get_param(params, 0)->val_ul, + res = gdb_breakpoint_insert(gdbserver_state.c_cpu, + get_param(params, 0)->val_ul, get_param(params, 1)->val_ull, get_param(params, 2)->val_ull); if (res >= 0) { @@ -1690,7 +1580,8 @@ static void handle_remove_bp(GArray *params, void *user_ctx) return; } - res = gdb_breakpoint_remove(get_param(params, 0)->val_ul, + res = gdb_breakpoint_remove(gdbserver_state.c_cpu, + get_param(params, 0)->val_ul, get_param(params, 1)->val_ull, get_param(params, 2)->val_ull); if (res >= 0) { @@ -2541,7 +2432,7 @@ static void handle_target_halt(GArray *params, void *user_ctx) * because gdb is doing an initial connect and the state * should be cleaned up. */ - gdb_breakpoint_remove_all(); + gdb_breakpoint_remove_all(gdbserver_state.c_cpu); } static int gdb_handle_packet(const char *line_buf) diff --git a/gdbstub/softmmu.c b/gdbstub/softmmu.c new file mode 100644 index 0000000000..4e73890379 --- /dev/null +++ b/gdbstub/softmmu.c @@ -0,0 +1,42 @@ +/* + * gdb server stub - softmmu specific bits + * + * Debug integration depends on support from the individual + * accelerators so most of this involves calling the ops helpers. + * + * Copyright (c) 2022 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "exec/gdbstub.h" +#include "exec/hwaddr.h" +#include "sysemu/cpus.h" +#include "internals.h" + +int gdb_breakpoint_insert(CPUState *cs, int type, hwaddr addr, hwaddr len) +{ + const AccelOpsClass *ops = cpus_get_accel(); + if (ops->insert_breakpoint) { + return ops->insert_breakpoint(cs, type, addr, len); + } + return -ENOSYS; +} + +int gdb_breakpoint_remove(CPUState *cs, int type, hwaddr addr, hwaddr len) +{ + const AccelOpsClass *ops = cpus_get_accel(); + if (ops->remove_breakpoint) { + return ops->remove_breakpoint(cs, type, addr, len); + } + return -ENOSYS; +} + +void gdb_breakpoint_remove_all(CPUState *cs) +{ + const AccelOpsClass *ops = cpus_get_accel(); + if (ops->remove_all_breakpoints) { + ops->remove_all_breakpoints(cs); + } +} diff --git a/gdbstub/user.c b/gdbstub/user.c new file mode 100644 index 0000000000..42652b28a7 --- /dev/null +++ b/gdbstub/user.c @@ -0,0 +1,62 @@ +/* + * gdbstub user-mode helper routines. + * + * We know for user-mode we are using TCG so we can call stuff directly. + * + * Copyright (c) 2022 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "exec/hwaddr.h" +#include "exec/gdbstub.h" +#include "hw/core/cpu.h" +#include "internals.h" + +int gdb_breakpoint_insert(CPUState *cs, int type, hwaddr addr, hwaddr len) +{ + CPUState *cpu; + int err = 0; + + switch (type) { + case GDB_BREAKPOINT_SW: + case GDB_BREAKPOINT_HW: + CPU_FOREACH(cpu) { + err = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL); + if (err) { + break; + } + } + return err; + default: + /* user-mode doesn't support watchpoints */ + return -ENOSYS; + } +} + +int gdb_breakpoint_remove(CPUState *cs, int type, hwaddr addr, hwaddr len) +{ + CPUState *cpu; + int err = 0; + + switch (type) { + case GDB_BREAKPOINT_SW: + case GDB_BREAKPOINT_HW: + CPU_FOREACH(cpu) { + err = cpu_breakpoint_remove(cpu, addr, BP_GDB); + if (err) { + break; + } + } + return err; + default: + /* user-mode doesn't support watchpoints */ + return -ENOSYS; + } +} + +void gdb_breakpoint_remove_all(CPUState *cs) +{ + cpu_breakpoint_remove_all(cs, BP_GDB); +} diff --git a/softmmu/cpus.c b/softmmu/cpus.c index 23b30484b2..61b27ff59d 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -617,6 +617,13 @@ void cpus_register_accel(const AccelOpsClass *ops) cpus_accel = ops; } +const AccelOpsClass *cpus_get_accel(void) +{ + /* broken if we call this early */ + assert(cpus_accel); + return cpus_accel; +} + void qemu_init_vcpu(CPUState *cpu) { MachineState *ms = MACHINE(qdev_get_machine()); diff --git a/gdbstub/meson.build b/gdbstub/meson.build index 6d4ae2d03c..fc895a2c39 100644 --- a/gdbstub/meson.build +++ b/gdbstub/meson.build @@ -1 +1,9 @@ +# +# The main gdbstub still relies on per-build definitions of various +# types. The bits pushed to softmmu/user.c try to use guest agnostic +# types such as hwaddr. +# + specific_ss.add(files('gdbstub.c')) +softmmu_ss.add(files('softmmu.c')) +user_ss.add(files('user.c'))