From patchwork Tue Aug 11 11:00:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 11709049 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 64DA5109A for ; Tue, 11 Aug 2020 11:02:08 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 43F612075D for ; Tue, 11 Aug 2020 11:02:08 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 43F612075D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=ispras.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:48146 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5S2g-00042A-2v for patchwork-qemu-devel@patchwork.kernel.org; Tue, 11 Aug 2020 07:02:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46016) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S1h-0002Qv-4b for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:05 -0400 Received: from mail.ispras.ru ([83.149.199.84]:42236) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S1e-0003JL-O5 for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:04 -0400 Received: from [127.0.1.1] (unknown [62.118.151.149]) by mail.ispras.ru (Postfix) with ESMTPSA id B1FFA4089F07; Tue, 11 Aug 2020 11:00:59 +0000 (UTC) Subject: [PATCH v2 01/14] replay: don't record interrupt poll From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Tue, 11 Aug 2020 14:00:59 +0300 Message-ID: <159714365945.18946.1418837025361709268.stgit@pasha-ThinkPad-X280> In-Reply-To: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> References: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Received-SPF: pass client-ip=83.149.199.84; envelope-from=pavel.dovgalyuk@ispras.ru; helo=mail.ispras.ru X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 07:00:54 X-ACL-Warn: Detected OS = Linux 3.11 and newer X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, wrampazz@redhat.com, pavel.dovgalyuk@ispras.ru, ehabkost@redhat.com, alex.bennee@linaro.org, mtosatti@redhat.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com, philmd@redhat.com, zhiwei_liu@c-sky.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" Interrupt poll is not a real interrupt event. It is needed only for thread safety. This interrupt is used for i386 and converted to hardware interrupt by cpu_handle_interrupt function. Therefore it is not needed to be recorded, because hardware interrupt will be recorded after converting. Signed-off-by: Pavel Dovgalyuk --- accel/tcg/cpu-exec.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 66d38f9d85..28aff1bb1e 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -429,8 +429,7 @@ static inline bool cpu_handle_halt(CPUState *cpu) { if (cpu->halted) { #if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY) - if ((cpu->interrupt_request & CPU_INTERRUPT_POLL) - && replay_interrupt()) { + if (cpu->interrupt_request & CPU_INTERRUPT_POLL) { X86CPU *x86_cpu = X86_CPU(cpu); qemu_mutex_lock_iothread(); apic_poll_irq(x86_cpu->apic_state); @@ -587,7 +586,13 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, and via longjmp via cpu_loop_exit. */ else { if (cc->cpu_exec_interrupt(cpu, interrupt_request)) { - replay_interrupt(); + if (true +#if defined(TARGET_I386) + && !(interrupt_request & CPU_INTERRUPT_POLL) +#endif + ) { + replay_interrupt(); + } /* * After processing the interrupt, ensure an EXCP_DEBUG is * raised when single-stepping so that GDB doesn't miss the From patchwork Tue Aug 11 11:01:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 11709057 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 65BCF16B1 for ; Tue, 11 Aug 2020 11:03:45 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 46F1D2075D for ; Tue, 11 Aug 2020 11:03:45 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 46F1D2075D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=ispras.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:56610 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5S4G-0007Py-Ev for patchwork-qemu-devel@patchwork.kernel.org; Tue, 11 Aug 2020 07:03:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46034) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S1l-0002Wd-9l for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:09 -0400 Received: from mail.ispras.ru ([83.149.199.84]:42262) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S1j-0003Jp-EC for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:08 -0400 Received: from [127.0.1.1] (unknown [62.118.151.149]) by mail.ispras.ru (Postfix) with ESMTPSA id 678924089EF7; Tue, 11 Aug 2020 11:01:05 +0000 (UTC) Subject: [PATCH v2 02/14] replay: provide an accessor for rr filename From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Tue, 11 Aug 2020 14:01:05 +0300 Message-ID: <159714366516.18946.1119244635375641050.stgit@pasha-ThinkPad-X280> In-Reply-To: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> References: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Received-SPF: pass client-ip=83.149.199.84; envelope-from=pavel.dovgalyuk@ispras.ru; helo=mail.ispras.ru X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 07:00:54 X-ACL-Warn: Detected OS = Linux 3.11 and newer X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, wrampazz@redhat.com, pavel.dovgalyuk@ispras.ru, ehabkost@redhat.com, alex.bennee@linaro.org, mtosatti@redhat.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com, philmd@redhat.com, zhiwei_liu@c-sky.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Pavel Dovgalyuk This patch adds an accessor function for the name of the record/replay log file. Adding an accessor instead of making variable global, prevents accidental modification of this variable by other modules. Signed-off-by: Pavel Dovgalyuk Reviewed-by: Alex Bennée --- include/sysemu/replay.h | 2 ++ replay/replay.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index 5471bb514d..c9c896ae8d 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -72,6 +72,8 @@ void replay_start(void); void replay_finish(void); /*! Adds replay blocker with the specified error description */ void replay_add_blocker(Error *reason); +/* Returns name of the replay log file */ +const char *replay_get_filename(void); /* Processing the instructions */ diff --git a/replay/replay.c b/replay/replay.c index 83ed9e0e24..42e82f7bc7 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -399,3 +399,8 @@ void replay_add_blocker(Error *reason) { replay_blockers = g_slist_prepend(replay_blockers, reason); } + +const char *replay_get_filename(void) +{ + return replay_filename; +} From patchwork Tue Aug 11 11:01:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 11709051 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CE94E13A4 for ; Tue, 11 Aug 2020 11:02:21 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id AE6992075D for ; Tue, 11 Aug 2020 11:02:21 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org AE6992075D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=ispras.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:48944 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5S2u-0004Mz-Ol for patchwork-qemu-devel@patchwork.kernel.org; Tue, 11 Aug 2020 07:02:20 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46096) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S1r-0002gP-TC for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:15 -0400 Received: from mail.ispras.ru ([83.149.199.84]:42274) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S1o-0003KC-V0 for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:15 -0400 Received: from [127.0.1.1] (unknown [62.118.151.149]) by mail.ispras.ru (Postfix) with ESMTPSA id 1B66A4089EF7; Tue, 11 Aug 2020 11:01:11 +0000 (UTC) Subject: [PATCH v2 03/14] qcow2: introduce icount field for snapshots From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Tue, 11 Aug 2020 14:01:10 +0300 Message-ID: <159714367084.18946.504483964831159477.stgit@pasha-ThinkPad-X280> In-Reply-To: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> References: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Received-SPF: pass client-ip=83.149.199.84; envelope-from=pavel.dovgalyuk@ispras.ru; helo=mail.ispras.ru X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 07:00:54 X-ACL-Warn: Detected OS = Linux 3.11 and newer X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, wrampazz@redhat.com, pavel.dovgalyuk@ispras.ru, ehabkost@redhat.com, alex.bennee@linaro.org, mtosatti@redhat.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com, philmd@redhat.com, zhiwei_liu@c-sky.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Pavel Dovgalyuk This patch introduces the icount field for saving within the snapshot. It is required for navigation between the snapshots in record/replay mode. Signed-off-by: Pavel Dovgalyuk Acked-by: Kevin Wolf --- block/qcow2-snapshot.c | 7 +++++++ block/qcow2.h | 3 +++ docs/interop/qcow2.txt | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 2756b37d24..d14e7be1aa 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -164,6 +164,12 @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair, sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE; } + if (sn->extra_data_size >= endof(QCowSnapshotExtraData, icount)) { + sn->icount = be64_to_cpu(extra.icount); + } else { + sn->icount = -1ULL; + } + if (sn->extra_data_size > sizeof(extra)) { uint64_t extra_data_end; size_t unknown_extra_data_size; @@ -333,6 +339,7 @@ int qcow2_write_snapshots(BlockDriverState *bs) memset(&extra, 0, sizeof(extra)); extra.vm_state_size_large = cpu_to_be64(sn->vm_state_size); extra.disk_size = cpu_to_be64(sn->disk_size); + extra.icount = cpu_to_be64(sn->icount); id_str_size = strlen(sn->id_str); name_size = strlen(sn->name); diff --git a/block/qcow2.h b/block/qcow2.h index 7ce2c23bdb..9c81086991 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -179,6 +179,7 @@ typedef struct QEMU_PACKED QCowSnapshotHeader { typedef struct QEMU_PACKED QCowSnapshotExtraData { uint64_t vm_state_size_large; uint64_t disk_size; + uint64_t icount; } QCowSnapshotExtraData; @@ -192,6 +193,8 @@ typedef struct QCowSnapshot { uint32_t date_sec; uint32_t date_nsec; uint64_t vm_clock_nsec; + /* icount value for the moment when snapshot was taken */ + uint64_t icount; /* Size of all extra data, including QCowSnapshotExtraData if available */ uint32_t extra_data_size; /* Data beyond QCowSnapshotExtraData, if any */ diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt index f072e27900..3dc4b9f89a 100644 --- a/docs/interop/qcow2.txt +++ b/docs/interop/qcow2.txt @@ -645,6 +645,11 @@ Snapshot table entry: Byte 48 - 55: Virtual disk size of the snapshot in bytes + Byte 56 - 63: icount value which corresponds to + the record/replay instruction count + when the snapshot was taken. Set to -1 + if icount was disabled + Version 3 images must include extra data at least up to byte 55. From patchwork Tue Aug 11 11:01:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 11709059 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 31A0013A4 for ; Tue, 11 Aug 2020 11:03:52 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 12D9B2075D for ; Tue, 11 Aug 2020 11:03:52 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 12D9B2075D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=ispras.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:57316 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5S4N-0007hh-9k for patchwork-qemu-devel@patchwork.kernel.org; Tue, 11 Aug 2020 07:03:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46126) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S1x-0002sM-Bb for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:21 -0400 Received: from mail.ispras.ru ([83.149.199.84]:42302) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S1u-0003Km-Td for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:20 -0400 Received: from [127.0.1.1] (unknown [62.118.151.149]) by mail.ispras.ru (Postfix) with ESMTPSA id D2C684089EF7; Tue, 11 Aug 2020 11:01:16 +0000 (UTC) Subject: [PATCH v2 04/14] migration: introduce icount field for snapshots From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Tue, 11 Aug 2020 14:01:16 +0300 Message-ID: <159714367656.18946.3762380501960237309.stgit@pasha-ThinkPad-X280> In-Reply-To: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> References: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Received-SPF: pass client-ip=83.149.199.84; envelope-from=pavel.dovgalyuk@ispras.ru; helo=mail.ispras.ru X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 07:00:54 X-ACL-Warn: Detected OS = Linux 3.11 and newer X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, wrampazz@redhat.com, pavel.dovgalyuk@ispras.ru, ehabkost@redhat.com, alex.bennee@linaro.org, mtosatti@redhat.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com, philmd@redhat.com, zhiwei_liu@c-sky.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Pavel Dovgalyuk Saving icount as a parameters of the snapshot allows navigation between them in the execution replay scenario. This information can be used for finding a specific snapshot for proceeding the recorded execution to the specific moment of the time. E.g., 'reverse step' action (introduced in one of the following patches) needs to load the nearest snapshot which is prior to the current moment of time. Signed-off-by: Pavel Dovgalyuk Acked-by: Markus Armbruster Acked-by: Kevin Wolf --- block/qapi.c | 18 ++++++++++++++---- block/qcow2-snapshot.c | 2 ++ blockdev.c | 10 ++++++++++ include/block/snapshot.h | 1 + migration/savevm.c | 5 +++++ qapi/block-core.json | 10 ++++++++-- stubs/replay.c | 5 +++++ 7 files changed, 45 insertions(+), 6 deletions(-) diff --git a/block/qapi.c b/block/qapi.c index afd9f3b4a7..3c73db54c4 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -226,6 +226,8 @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs, info->date_nsec = sn_tab[i].date_nsec; info->vm_clock_sec = sn_tab[i].vm_clock_nsec / 1000000000; info->vm_clock_nsec = sn_tab[i].vm_clock_nsec % 1000000000; + info->icount = sn_tab[i].icount; + info->has_icount = sn_tab[i].icount != -1ULL; info_list = g_new0(SnapshotInfoList, 1); info_list->value = info; @@ -658,14 +660,15 @@ BlockStatsList *qmp_query_blockstats(bool has_query_nodes, void bdrv_snapshot_dump(QEMUSnapshotInfo *sn) { char date_buf[128], clock_buf[128]; + char icount_buf[128] = {0}; struct tm tm; time_t ti; int64_t secs; char *sizing = NULL; if (!sn) { - qemu_printf("%-10s%-20s%11s%20s%15s", - "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK"); + qemu_printf("%-10s%-18s%7s%20s%13s%11s", + "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK", "ICOUNT"); } else { ti = sn->date_sec; localtime_r(&ti, &tm); @@ -679,11 +682,16 @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn) (int)(secs % 60), (int)((sn->vm_clock_nsec / 1000000) % 1000)); sizing = size_to_str(sn->vm_state_size); - qemu_printf("%-10s%-20s%11s%20s%15s", + if (sn->icount != -1ULL) { + snprintf(icount_buf, sizeof(icount_buf), + "%"PRId64, sn->icount); + } + qemu_printf("%-10s%-18s%7s%20s%13s%11s", sn->id_str, sn->name, sizing, date_buf, - clock_buf); + clock_buf, + icount_buf); } g_free(sizing); } @@ -845,6 +853,8 @@ void bdrv_image_info_dump(ImageInfo *info) .date_nsec = elem->value->date_nsec, .vm_clock_nsec = elem->value->vm_clock_sec * 1000000000ULL + elem->value->vm_clock_nsec, + .icount = elem->value->has_icount ? + elem->value->icount : -1ULL, }; pstrcpy(sn.id_str, sizeof(sn.id_str), elem->value->id); diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index d14e7be1aa..4b127ea6af 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -663,6 +663,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) sn->date_sec = sn_info->date_sec; sn->date_nsec = sn_info->date_nsec; sn->vm_clock_nsec = sn_info->vm_clock_nsec; + sn->icount = sn_info->icount; sn->extra_data_size = sizeof(QCowSnapshotExtraData); /* Allocate the L1 table of the snapshot and copy the current one there. */ @@ -1007,6 +1008,7 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) sn_info->date_sec = sn->date_sec; sn_info->date_nsec = sn->date_nsec; sn_info->vm_clock_nsec = sn->vm_clock_nsec; + sn_info->icount = sn->icount; } *psn_tab = sn_tab; return s->nb_snapshots; diff --git a/blockdev.c b/blockdev.c index 3848a9c8ab..622a436c94 100644 --- a/blockdev.c +++ b/blockdev.c @@ -59,6 +59,7 @@ #include "sysemu/arch_init.h" #include "sysemu/qtest.h" #include "sysemu/runstate.h" +#include "sysemu/replay.h" #include "qemu/cutils.h" #include "qemu/help_option.h" #include "qemu/main-loop.h" @@ -1190,6 +1191,10 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device, info->vm_state_size = sn.vm_state_size; info->vm_clock_nsec = sn.vm_clock_nsec % 1000000000; info->vm_clock_sec = sn.vm_clock_nsec / 1000000000; + if (sn.icount != -1ULL) { + info->icount = sn.icount; + info->has_icount = true; + } return info; @@ -1350,6 +1355,11 @@ static void internal_snapshot_prepare(BlkActionState *common, sn->date_sec = tv.tv_sec; sn->date_nsec = tv.tv_usec * 1000; sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + if (replay_mode != REPLAY_MODE_NONE) { + sn->icount = replay_get_current_icount(); + } else { + sn->icount = -1ULL; + } ret1 = bdrv_snapshot_create(bs, sn); if (ret1 < 0) { diff --git a/include/block/snapshot.h b/include/block/snapshot.h index 2bfcd57578..b0fe42993d 100644 --- a/include/block/snapshot.h +++ b/include/block/snapshot.h @@ -42,6 +42,7 @@ typedef struct QEMUSnapshotInfo { uint32_t date_sec; /* UTC date of the snapshot */ uint32_t date_nsec; uint64_t vm_clock_nsec; /* VM clock relative to boot */ + uint64_t icount; /* record/replay step */ } QEMUSnapshotInfo; int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, diff --git a/migration/savevm.c b/migration/savevm.c index a843d202b5..d56d9729bd 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -2723,6 +2723,11 @@ int save_snapshot(const char *name, Error **errp) sn->date_sec = tv.tv_sec; sn->date_nsec = tv.tv_usec * 1000; sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + if (replay_mode != REPLAY_MODE_NONE) { + sn->icount = replay_get_current_icount(); + } else { + sn->icount = -1ULL; + } if (name) { ret = bdrv_snapshot_find(bs, old_sn, name); diff --git a/qapi/block-core.json b/qapi/block-core.json index 197bdc1c36..b32c698da3 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -27,13 +27,18 @@ # # @vm-clock-nsec: fractional part in nano seconds to be used with vm-clock-sec # +# @icount: Current instruction count. Appears when execution record/replay +# is enabled. Used for "time-traveling" to match the moment +# in the recorded execution with the snapshots. (since 5.2) +# # Since: 1.3 # ## { 'struct': 'SnapshotInfo', 'data': { 'id': 'str', 'name': 'str', 'vm-state-size': 'int', 'date-sec': 'int', 'date-nsec': 'int', - 'vm-clock-sec': 'int', 'vm-clock-nsec': 'int' } } + 'vm-clock-sec': 'int', 'vm-clock-nsec': 'int', + '*icount': 'int' } } ## # @ImageInfoSpecificQCow2EncryptionBase: @@ -5512,7 +5517,8 @@ # "date-sec": 1000012, # "date-nsec": 10, # "vm-clock-sec": 100, -# "vm-clock-nsec": 20 +# "vm-clock-nsec": 20, +# "icount": 220414 # } # } # diff --git a/stubs/replay.c b/stubs/replay.c index 5974ec1f50..eacb366aa8 100644 --- a/stubs/replay.c +++ b/stubs/replay.c @@ -88,3 +88,8 @@ int replay_read_random(void *buf, size_t len) { return 0; } + +uint64_t replay_get_current_icount(void) +{ + return 0; +} From patchwork Tue Aug 11 11:01:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 11709067 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2A98816B1 for ; Tue, 11 Aug 2020 11:05:26 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0B33B2075D for ; Tue, 11 Aug 2020 11:05:26 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0B33B2075D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=ispras.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:37538 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5S5t-0002ge-8j for patchwork-qemu-devel@patchwork.kernel.org; Tue, 11 Aug 2020 07:05:25 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46176) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S23-00036R-H3 for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:27 -0400 Received: from mail.ispras.ru ([83.149.199.84]:42326) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S20-0003LB-G7 for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:27 -0400 Received: from [127.0.1.1] (unknown [62.118.151.149]) by mail.ispras.ru (Postfix) with ESMTPSA id 8A9FF4089EF7; Tue, 11 Aug 2020 11:01:22 +0000 (UTC) Subject: [PATCH v2 05/14] iotests: update snapshot test for new output format From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Tue, 11 Aug 2020 14:01:22 +0300 Message-ID: <159714368230.18946.15293043865526975163.stgit@pasha-ThinkPad-X280> In-Reply-To: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> References: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Received-SPF: pass client-ip=83.149.199.84; envelope-from=pavel.dovgalyuk@ispras.ru; helo=mail.ispras.ru X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 07:00:54 X-ACL-Warn: Detected OS = Linux 3.11 and newer X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, wrampazz@redhat.com, pavel.dovgalyuk@ispras.ru, ehabkost@redhat.com, alex.bennee@linaro.org, mtosatti@redhat.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com, philmd@redhat.com, zhiwei_liu@c-sky.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Pavel Dovgalyuk This patch updates iotests that verify qemu monitor output. New output format for snapshot listing include ICOUNT column. Signed-off-by: Pavel Dovgalyuk --- tests/qemu-iotests/267.out | 48 ++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/tests/qemu-iotests/267.out b/tests/qemu-iotests/267.out index d6d80c099f..d4fa1b24f8 100644 --- a/tests/qemu-iotests/267.out +++ b/tests/qemu-iotests/267.out @@ -33,8 +33,8 @@ QEMU X.Y.Z monitor - type 'help' for more information (qemu) savevm snap0 (qemu) info snapshots List of snapshots present on all disks: -ID TAG VM SIZE DATE VM CLOCK --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +ID TAG VM SIZE DATE VM CLOCK ICOUNT +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 (qemu) loadvm snap0 (qemu) quit @@ -44,8 +44,8 @@ QEMU X.Y.Z monitor - type 'help' for more information (qemu) savevm snap0 (qemu) info snapshots List of snapshots present on all disks: -ID TAG VM SIZE DATE VM CLOCK --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +ID TAG VM SIZE DATE VM CLOCK ICOUNT +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 (qemu) loadvm snap0 (qemu) quit @@ -69,8 +69,8 @@ QEMU X.Y.Z monitor - type 'help' for more information (qemu) savevm snap0 (qemu) info snapshots List of snapshots present on all disks: -ID TAG VM SIZE DATE VM CLOCK --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +ID TAG VM SIZE DATE VM CLOCK ICOUNT +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 (qemu) loadvm snap0 (qemu) quit @@ -94,8 +94,8 @@ QEMU X.Y.Z monitor - type 'help' for more information (qemu) savevm snap0 (qemu) info snapshots List of snapshots present on all disks: -ID TAG VM SIZE DATE VM CLOCK --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +ID TAG VM SIZE DATE VM CLOCK ICOUNT +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 (qemu) loadvm snap0 (qemu) quit @@ -105,8 +105,8 @@ QEMU X.Y.Z monitor - type 'help' for more information (qemu) savevm snap0 (qemu) info snapshots List of snapshots present on all disks: -ID TAG VM SIZE DATE VM CLOCK --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +ID TAG VM SIZE DATE VM CLOCK ICOUNT +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 (qemu) loadvm snap0 (qemu) quit @@ -119,8 +119,8 @@ QEMU X.Y.Z monitor - type 'help' for more information (qemu) savevm snap0 (qemu) info snapshots List of snapshots present on all disks: -ID TAG VM SIZE DATE VM CLOCK --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +ID TAG VM SIZE DATE VM CLOCK ICOUNT +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 (qemu) loadvm snap0 (qemu) quit @@ -134,8 +134,8 @@ QEMU X.Y.Z monitor - type 'help' for more information (qemu) savevm snap0 (qemu) info snapshots List of snapshots present on all disks: -ID TAG VM SIZE DATE VM CLOCK --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +ID TAG VM SIZE DATE VM CLOCK ICOUNT +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 (qemu) loadvm snap0 (qemu) quit @@ -145,15 +145,15 @@ QEMU X.Y.Z monitor - type 'help' for more information (qemu) savevm snap0 (qemu) info snapshots List of snapshots present on all disks: -ID TAG VM SIZE DATE VM CLOCK --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +ID TAG VM SIZE DATE VM CLOCK ICOUNT +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 (qemu) loadvm snap0 (qemu) quit Internal snapshots on overlay: Snapshot list: -ID TAG VM SIZE DATE VM CLOCK -1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +ID TAG VM SIZE DATE VM CLOCK ICOUNT +1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 Internal snapshots on backing file: === -blockdev with NBD server on the backing file === @@ -166,17 +166,17 @@ QEMU X.Y.Z monitor - type 'help' for more information (qemu) savevm snap0 (qemu) info snapshots List of snapshots present on all disks: -ID TAG VM SIZE DATE VM CLOCK --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +ID TAG VM SIZE DATE VM CLOCK ICOUNT +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 (qemu) loadvm snap0 (qemu) quit Internal snapshots on overlay: Snapshot list: -ID TAG VM SIZE DATE VM CLOCK -1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +ID TAG VM SIZE DATE VM CLOCK ICOUNT +1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 Internal snapshots on backing file: Snapshot list: -ID TAG VM SIZE DATE VM CLOCK -1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +ID TAG VM SIZE DATE VM CLOCK ICOUNT +1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 *** done From patchwork Tue Aug 11 11:01:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 11709063 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D5906174A for ; Tue, 11 Aug 2020 11:05:18 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B67592075D for ; Tue, 11 Aug 2020 11:05:18 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B67592075D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=ispras.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:36764 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5S5l-0002No-TI for patchwork-qemu-devel@patchwork.kernel.org; Tue, 11 Aug 2020 07:05:17 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46192) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S28-0003Ga-Ac for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:32 -0400 Received: from mail.ispras.ru ([83.149.199.84]:42344) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S26-0003Ld-85 for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:31 -0400 Received: from [127.0.1.1] (unknown [62.118.151.149]) by mail.ispras.ru (Postfix) with ESMTPSA id 496F04089F07; Tue, 11 Aug 2020 11:01:28 +0000 (UTC) Subject: [PATCH v2 06/14] qapi: introduce replay.json for record/replay-related stuff From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Tue, 11 Aug 2020 14:01:28 +0300 Message-ID: <159714368801.18946.17142001761682131437.stgit@pasha-ThinkPad-X280> In-Reply-To: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> References: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Received-SPF: pass client-ip=83.149.199.84; envelope-from=pavel.dovgalyuk@ispras.ru; helo=mail.ispras.ru X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 07:00:54 X-ACL-Warn: Detected OS = Linux 3.11 and newer X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, wrampazz@redhat.com, pavel.dovgalyuk@ispras.ru, ehabkost@redhat.com, alex.bennee@linaro.org, mtosatti@redhat.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com, philmd@redhat.com, zhiwei_liu@c-sky.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Pavel Dovgalyuk This patch adds replay.json file. It will be used for adding record/replay-related data structures and commands. Signed-off-by: Pavel Dovgalyuk Reviewed-by: Markus Armbruster Reviewed-by: Alex Bennée --- MAINTAINERS | 1 + include/sysemu/replay.h | 1 + qapi/Makefile.objs | 4 ++-- qapi/misc.json | 18 ------------------ qapi/qapi-schema.json | 1 + qapi/replay.json | 26 ++++++++++++++++++++++++++ 6 files changed, 31 insertions(+), 20 deletions(-) create mode 100644 qapi/replay.json diff --git a/MAINTAINERS b/MAINTAINERS index 0886eb3d2b..50fc44680c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2643,6 +2643,7 @@ F: include/sysemu/replay.h F: docs/replay.txt F: stubs/replay.c F: tests/acceptance/replay_kernel.py +F: qapi/replay.json IOVA Tree M: Peter Xu diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index c9c896ae8d..e00ed2f4a5 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -14,6 +14,7 @@ #include "qapi/qapi-types-misc.h" #include "qapi/qapi-types-run-state.h" +#include "qapi/qapi-types-replay.h" #include "qapi/qapi-types-ui.h" #include "block/aio.h" diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs index 4673ab7490..eff501a97d 100644 --- a/qapi/Makefile.objs +++ b/qapi/Makefile.objs @@ -7,8 +7,8 @@ util-obj-y += qapi-util.o QAPI_COMMON_MODULES = audio authz block-core block char common control crypto QAPI_COMMON_MODULES += dump error introspect job machine migration misc -QAPI_COMMON_MODULES += net pragma qdev qom rdma rocker run-state sockets tpm -QAPI_COMMON_MODULES += trace transaction ui +QAPI_COMMON_MODULES += net pragma qdev qom rdma replay rocker run-state sockets +QAPI_COMMON_MODULES += tpm trace transaction ui QAPI_TARGET_MODULES = machine-target misc-target QAPI_MODULES = $(QAPI_COMMON_MODULES) $(QAPI_TARGET_MODULES) diff --git a/qapi/misc.json b/qapi/misc.json index 9d32820dc1..87fcb90135 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -1556,24 +1556,6 @@ { 'event': 'ACPI_DEVICE_OST', 'data': { 'info': 'ACPIOSTInfo' } } -## -# @ReplayMode: -# -# Mode of the replay subsystem. -# -# @none: normal execution mode. Replay or record are not enabled. -# -# @record: record mode. All non-deterministic data is written into the -# replay log. -# -# @play: replay mode. Non-deterministic data required for system execution -# is read from the log. -# -# Since: 2.5 -## -{ 'enum': 'ReplayMode', - 'data': [ 'none', 'record', 'play' ] } - ## # @xen-load-devices-state: # diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index f03ff91ceb..2604fcf6ec 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -82,6 +82,7 @@ { 'include': 'qdev.json' } { 'include': 'machine.json' } { 'include': 'machine-target.json' } +{ 'include': 'replay.json' } { 'include': 'misc.json' } { 'include': 'misc-target.json' } { 'include': 'audio.json' } diff --git a/qapi/replay.json b/qapi/replay.json new file mode 100644 index 0000000000..9e13551d20 --- /dev/null +++ b/qapi/replay.json @@ -0,0 +1,26 @@ +# -*- Mode: Python -*- +# + +## +# = Record/replay +## + +{ 'include': 'common.json' } + +## +# @ReplayMode: +# +# Mode of the replay subsystem. +# +# @none: normal execution mode. Replay or record are not enabled. +# +# @record: record mode. All non-deterministic data is written into the +# replay log. +# +# @play: replay mode. Non-deterministic data required for system execution +# is read from the log. +# +# Since: 2.5 +## +{ 'enum': 'ReplayMode', + 'data': [ 'none', 'record', 'play' ] } From patchwork Tue Aug 11 11:01:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 11709053 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 19745109A for ; Tue, 11 Aug 2020 11:02:42 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id EE0F42075D for ; Tue, 11 Aug 2020 11:02:41 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EE0F42075D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=ispras.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:51034 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5S3F-0005Ck-3w for patchwork-qemu-devel@patchwork.kernel.org; Tue, 11 Aug 2020 07:02:41 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46226) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2D-0003Op-S7 for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:37 -0400 Received: from mail.ispras.ru ([83.149.199.84]:42358) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2B-0003N3-Qp for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:37 -0400 Received: from [127.0.1.1] (unknown [62.118.151.149]) by mail.ispras.ru (Postfix) with ESMTPSA id 064094089EF7; Tue, 11 Aug 2020 11:01:34 +0000 (UTC) Subject: [PATCH v2 07/14] replay: introduce info hmp/qmp command From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Tue, 11 Aug 2020 14:01:33 +0300 Message-ID: <159714369374.18946.15033736609218104463.stgit@pasha-ThinkPad-X280> In-Reply-To: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> References: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Received-SPF: pass client-ip=83.149.199.84; envelope-from=pavel.dovgalyuk@ispras.ru; helo=mail.ispras.ru X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 07:00:54 X-ACL-Warn: Detected OS = Linux 3.11 and newer X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, wrampazz@redhat.com, pavel.dovgalyuk@ispras.ru, ehabkost@redhat.com, alex.bennee@linaro.org, mtosatti@redhat.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com, philmd@redhat.com, zhiwei_liu@c-sky.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Pavel Dovgalyuk This patch introduces 'info replay' monitor command and corresponding qmp request. These commands request the current record/replay mode, replay log file name, and the instruction count (number of recorded/replayed instructions). The instruction count can be used with the replay_seek/replay_break commands added in the next two patches. Signed-off-by: Pavel Dovgalyuk Acked-by: Dr. David Alan Gilbert Acked-by: Markus Armbruster --- hmp-commands-info.hx | 11 +++++++++++ include/monitor/hmp.h | 1 + qapi/block-core.json | 3 ++- qapi/replay.json | 39 +++++++++++++++++++++++++++++++++++++++ replay/Makefile.objs | 1 + replay/replay-debugging.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 replay/replay-debugging.c diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index 30209e3903..117ba25f91 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -881,4 +881,15 @@ SRST Show SEV information. ERST + { + .name = "replay", + .args_type = "", + .params = "", + .help = "show record/replay information", + .cmd = hmp_info_replay, + }, +SRST + ``info replay`` + Display the record/replay information: mode and the current icount. +ERST diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index c986cfd28b..a790589b9e 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -130,5 +130,6 @@ void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict); void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict); void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict); void hmp_info_sev(Monitor *mon, const QDict *qdict); +void hmp_info_replay(Monitor *mon, const QDict *qdict); #endif diff --git a/qapi/block-core.json b/qapi/block-core.json index b32c698da3..46723adab4 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -29,7 +29,8 @@ # # @icount: Current instruction count. Appears when execution record/replay # is enabled. Used for "time-traveling" to match the moment -# in the recorded execution with the snapshots. (since 5.2) +# in the recorded execution with the snapshots. This counter may +# be obtained through @query-replay command (since 5.2) # # Since: 1.3 # diff --git a/qapi/replay.json b/qapi/replay.json index 9e13551d20..e6b3f6001d 100644 --- a/qapi/replay.json +++ b/qapi/replay.json @@ -24,3 +24,42 @@ ## { 'enum': 'ReplayMode', 'data': [ 'none', 'record', 'play' ] } + +## +# @ReplayInfo: +# +# Record/replay information. +# +# @mode: current mode. +# +# @filename: name of the record/replay log file. +# It is present only in record or replay modes, when the log +# is recorded or replayed. +# +# @icount: current number of executed instructions. +# +# Since: 5.2 +# +## +{ 'struct': 'ReplayInfo', + 'data': { 'mode': 'ReplayMode', '*filename': 'str', 'icount': 'int' } } + +## +# @query-replay: +# +# Retrieve the record/replay information. +# It includes current instruction count which may be used for +# @replay-break and @replay-seek commands. +# +# Returns: record/replay information. +# +# Since: 5.2 +# +# Example: +# +# -> { "execute": "query-replay" } +# <- { "return": { "mode": "play", "filename": "log.rr", "icount": 220414 } } +# +## +{ 'command': 'query-replay', + 'returns': 'ReplayInfo' } diff --git a/replay/Makefile.objs b/replay/Makefile.objs index 939be964a9..f847c5c023 100644 --- a/replay/Makefile.objs +++ b/replay/Makefile.objs @@ -8,3 +8,4 @@ common-obj-y += replay-snapshot.o common-obj-y += replay-net.o common-obj-y += replay-audio.o common-obj-y += replay-random.o +common-obj-y += replay-debugging.o diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c new file mode 100644 index 0000000000..51a6de4e81 --- /dev/null +++ b/replay/replay-debugging.c @@ -0,0 +1,43 @@ +/* + * replay-debugging.c + * + * Copyright (c) 2010-2020 Institute for System Programming + * of the Russian Academy of Sciences. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "sysemu/replay.h" +#include "replay-internal.h" +#include "monitor/hmp.h" +#include "monitor/monitor.h" +#include "qapi/qapi-commands-replay.h" + +void hmp_info_replay(Monitor *mon, const QDict *qdict) +{ + if (replay_mode == REPLAY_MODE_NONE) { + monitor_printf(mon, "Record/replay is not active\n"); + } else { + monitor_printf(mon, + "%s execution '%s': instruction count = %"PRId64"\n", + replay_mode == REPLAY_MODE_RECORD ? "Recording" : "Replaying", + replay_get_filename(), replay_get_current_icount()); + } +} + +ReplayInfo *qmp_query_replay(Error **errp) +{ + ReplayInfo *retval = g_new0(ReplayInfo, 1); + + retval->mode = replay_mode; + if (replay_get_filename()) { + retval->filename = g_strdup(replay_get_filename()); + retval->has_filename = true; + } + retval->icount = replay_get_current_icount(); + return retval; +} From patchwork Tue Aug 11 11:01:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 11709071 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 88B4314F6 for ; Tue, 11 Aug 2020 11:07:07 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 27BAC2075D for ; Tue, 11 Aug 2020 11:07:07 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 27BAC2075D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=ispras.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:44866 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5S7W-0005h7-2H for patchwork-qemu-devel@patchwork.kernel.org; Tue, 11 Aug 2020 07:07:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46276) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2L-0003Zm-Pm for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:46 -0400 Received: from mail.ispras.ru ([83.149.199.84]:42384) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2I-0003NQ-GS for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:44 -0400 Received: from [127.0.1.1] (unknown [62.118.151.149]) by mail.ispras.ru (Postfix) with ESMTPSA id B6C5B4089EF7; Tue, 11 Aug 2020 11:01:39 +0000 (UTC) Subject: [PATCH v2 08/14] replay: introduce breakpoint at the specified step From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Tue, 11 Aug 2020 14:01:39 +0300 Message-ID: <159714369946.18946.14765685415271964997.stgit@pasha-ThinkPad-X280> In-Reply-To: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> References: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Received-SPF: pass client-ip=83.149.199.84; envelope-from=pavel.dovgalyuk@ispras.ru; helo=mail.ispras.ru X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 07:00:54 X-ACL-Warn: Detected OS = Linux 3.11 and newer X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, wrampazz@redhat.com, pavel.dovgalyuk@ispras.ru, ehabkost@redhat.com, alex.bennee@linaro.org, mtosatti@redhat.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com, philmd@redhat.com, zhiwei_liu@c-sky.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Pavel Dovgalyuk This patch introduces replay_break, replay_delete_break qmp and hmp commands. These commands allow stopping at the specified instruction. It may be useful for debugging when there are some known events that should be investigated. replay_break command has one argument - number of instructions executed since the start of the replay. replay_delete_break removes previously set breakpoint. Signed-off-by: Pavel Dovgalyuk Acked-by: Markus Armbruster --- hmp-commands.hx | 32 +++++++++++++++++ include/monitor/hmp.h | 2 + qapi/replay.json | 36 +++++++++++++++++++ replay/replay-debugging.c | 86 +++++++++++++++++++++++++++++++++++++++++++++ replay/replay-internal.h | 4 ++ replay/replay.c | 17 +++++++++ 6 files changed, 177 insertions(+) diff --git a/hmp-commands.hx b/hmp-commands.hx index 60f395c276..e8ce385879 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1819,6 +1819,38 @@ SRST Set QOM property *property* of object at location *path* to value *value* ERST + { + .name = "replay_break", + .args_type = "icount:i", + .params = "icount", + .help = "set breakpoint at the specified instruction count", + .cmd = hmp_replay_break, + }, + +SRST +``replay_break`` *icount* + Set replay breakpoint at instruction count *icount*. + Execution stops when the specified instruction is reached. + There can be at most one breakpoint. When breakpoint is set, any prior + one is removed. The breakpoint may be set only in replay mode and only + "in the future", i.e. at instruction counts greater than the current one. + The current instruction count can be observed with ``info replay``. +ERST + + { + .name = "replay_delete_break", + .args_type = "", + .params = "", + .help = "remove replay breakpoint", + .cmd = hmp_replay_delete_break, + }, + +SRST +``replay_delete_break`` + Remove replay breakpoint which was previously set with ``replay_break``. + The command is ignored when there are no replay breakpoints. +ERST + { .name = "info", .args_type = "item:s?", diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index a790589b9e..21849bdda5 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -131,5 +131,7 @@ void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict); void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict); void hmp_info_sev(Monitor *mon, const QDict *qdict); void hmp_info_replay(Monitor *mon, const QDict *qdict); +void hmp_replay_break(Monitor *mon, const QDict *qdict); +void hmp_replay_delete_break(Monitor *mon, const QDict *qdict); #endif diff --git a/qapi/replay.json b/qapi/replay.json index e6b3f6001d..173ba76107 100644 --- a/qapi/replay.json +++ b/qapi/replay.json @@ -63,3 +63,39 @@ ## { 'command': 'query-replay', 'returns': 'ReplayInfo' } + +## +# @replay-break: +# +# Set replay breakpoint at instruction count @icount. +# Execution stops when the specified instruction is reached. +# There can be at most one breakpoint. When breakpoint is set, any prior +# one is removed. The breakpoint may be set only in replay mode and only +# "in the future", i.e. at instruction counts greater than the current one. +# The current instruction count can be observed with @query-replay. +# +# @icount: instruction count to stop at +# +# Since: 5.2 +# +# Example: +# +# -> { "execute": "replay-break", "data": { "icount": 220414 } } +# +## +{ 'command': 'replay-break', 'data': { 'icount': 'int' } } + +## +# @replay-delete-break: +# +# Remove replay breakpoint which was set with @replay-break. +# The command is ignored when there are no replay breakpoints. +# +# Since: 5.2 +# +# Example: +# +# -> { "execute": "replay-delete-break" } +# +## +{ 'command': 'replay-delete-break' } diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c index 51a6de4e81..86e19bb217 100644 --- a/replay/replay-debugging.c +++ b/replay/replay-debugging.c @@ -12,10 +12,13 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "sysemu/replay.h" +#include "sysemu/runstate.h" #include "replay-internal.h" #include "monitor/hmp.h" #include "monitor/monitor.h" #include "qapi/qapi-commands-replay.h" +#include "qapi/qmp/qdict.h" +#include "qemu/timer.h" void hmp_info_replay(Monitor *mon, const QDict *qdict) { @@ -41,3 +44,86 @@ ReplayInfo *qmp_query_replay(Error **errp) retval->icount = replay_get_current_icount(); return retval; } + +static void replay_break(uint64_t icount, QEMUTimerCB callback, void *opaque) +{ + assert(replay_mode == REPLAY_MODE_PLAY); + assert(replay_mutex_locked()); + assert(replay_break_icount >= replay_get_current_icount()); + assert(callback); + + replay_break_icount = icount; + + if (replay_break_timer) { + timer_del(replay_break_timer); + } + replay_break_timer = timer_new_ns(QEMU_CLOCK_REALTIME, + callback, opaque); +} + +static void replay_delete_break(void) +{ + assert(replay_mode == REPLAY_MODE_PLAY); + assert(replay_mutex_locked()); + + if (replay_break_timer) { + timer_del(replay_break_timer); + timer_free(replay_break_timer); + replay_break_timer = NULL; + } + replay_break_icount = -1ULL; +} + +static void replay_stop_vm(void *opaque) +{ + vm_stop(RUN_STATE_PAUSED); + replay_delete_break(); +} + +void qmp_replay_break(int64_t icount, Error **errp) +{ + if (replay_mode == REPLAY_MODE_PLAY) { + if (icount >= replay_get_current_icount()) { + replay_break(icount, replay_stop_vm, NULL); + } else { + error_setg(errp, + "cannot set breakpoint at the instruction in the past"); + } + } else { + error_setg(errp, "setting the breakpoint is allowed only in play mode"); + } +} + +void hmp_replay_break(Monitor *mon, const QDict *qdict) +{ + int64_t icount = qdict_get_try_int(qdict, "icount", -1LL); + Error *err = NULL; + + qmp_replay_break(icount, &err); + if (err) { + error_report_err(err); + error_free(err); + return; + } +} + +void qmp_replay_delete_break(Error **errp) +{ + if (replay_mode == REPLAY_MODE_PLAY) { + replay_delete_break(); + } else { + error_setg(errp, "replay breakpoints are allowed only in play mode"); + } +} + +void hmp_replay_delete_break(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + + qmp_replay_delete_break(&err); + if (err) { + error_report_err(err); + error_free(err); + return; + } +} diff --git a/replay/replay-internal.h b/replay/replay-internal.h index 33ac551e78..2f6145ec7c 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -94,6 +94,10 @@ extern ReplayState replay_state; /* File for replay writing */ extern FILE *replay_file; +/* Instruction count of the replay breakpoint */ +extern uint64_t replay_break_icount; +/* Timer for the replay breakpoint callback */ +extern QEMUTimer *replay_break_timer; void replay_put_byte(uint8_t byte); void replay_put_event(uint8_t event); diff --git a/replay/replay.c b/replay/replay.c index 42e82f7bc7..220886e32e 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -34,6 +34,10 @@ static char *replay_filename; ReplayState replay_state; static GSList *replay_blockers; +/* Replay breakpoints */ +uint64_t replay_break_icount = -1ULL; +QEMUTimer *replay_break_timer; + bool replay_next_event_is(int event) { bool res = false; @@ -73,6 +77,13 @@ int replay_get_instructions(void) replay_mutex_lock(); if (replay_next_event_is(EVENT_INSTRUCTION)) { res = replay_state.instruction_count; + if (replay_break_icount != -1LL) { + uint64_t current = replay_get_current_icount(); + assert(replay_break_icount >= current); + if (current + res > replay_break_icount) { + res = replay_break_icount - current; + } + } } replay_mutex_unlock(); return res; @@ -99,6 +110,12 @@ void replay_account_executed_instructions(void) will be read from the log. */ qemu_notify_event(); } + /* Execution reached the break step */ + if (replay_break_icount == replay_state.current_icount) { + /* Cannot make callback directly from the vCPU thread */ + timer_mod_ns(replay_break_timer, + qemu_clock_get_ns(QEMU_CLOCK_REALTIME)); + } } } } From patchwork Tue Aug 11 11:01:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 11709055 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A61D913A4 for ; Tue, 11 Aug 2020 11:03:44 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 867522075D for ; Tue, 11 Aug 2020 11:03:44 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 867522075D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=ispras.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:56530 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5S4F-0007O0-Oa for patchwork-qemu-devel@patchwork.kernel.org; Tue, 11 Aug 2020 07:03:43 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46306) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2Q-0003hl-A1 for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:50 -0400 Received: from mail.ispras.ru ([83.149.199.84]:42406) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2N-0003Nv-TS for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:49 -0400 Received: from [127.0.1.1] (unknown [62.118.151.149]) by mail.ispras.ru (Postfix) with ESMTPSA id 73FCC4089F07; Tue, 11 Aug 2020 11:01:45 +0000 (UTC) Subject: [PATCH v2 09/14] replay: implement replay-seek command From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Tue, 11 Aug 2020 14:01:45 +0300 Message-ID: <159714370522.18946.4046018214444656193.stgit@pasha-ThinkPad-X280> In-Reply-To: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> References: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Received-SPF: pass client-ip=83.149.199.84; envelope-from=pavel.dovgalyuk@ispras.ru; helo=mail.ispras.ru X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 07:00:54 X-ACL-Warn: Detected OS = Linux 3.11 and newer X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, wrampazz@redhat.com, pavel.dovgalyuk@ispras.ru, ehabkost@redhat.com, alex.bennee@linaro.org, mtosatti@redhat.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com, philmd@redhat.com, zhiwei_liu@c-sky.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Pavel Dovgalyuk This patch adds hmp/qmp commands replay_seek/replay-seek that proceed the execution to the specified instruction count. The command automatically loads nearest snapshot and replays the execution to find the desired instruction count. Signed-off-by: Pavel Dovgalyuk Acked-by: Markus Armbruster --- hmp-commands.hx | 18 +++++++++ include/monitor/hmp.h | 1 qapi/replay.json | 20 ++++++++++ replay/replay-debugging.c | 92 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+) diff --git a/hmp-commands.hx b/hmp-commands.hx index e8ce385879..4288274c4e 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1851,6 +1851,24 @@ SRST The command is ignored when there are no replay breakpoints. ERST + { + .name = "replay_seek", + .args_type = "icount:i", + .params = "icount", + .help = "replay execution to the specified instruction count", + .cmd = hmp_replay_seek, + }, + +SRST +``replay_seek`` *icount* +Automatically proceed to the instruction count *icount*, when +replaying the execution. The command automatically loads nearest +snapshot and replays the execution to find the desired instruction. +When there is no preceding snapshot or the execution is not replayed, +then the command fails. +*icount* for the reference may be observed with ``info replay`` command. +ERST + { .name = "info", .args_type = "item:s?", diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index 21849bdda5..655eb81a4c 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -133,5 +133,6 @@ void hmp_info_sev(Monitor *mon, const QDict *qdict); void hmp_info_replay(Monitor *mon, const QDict *qdict); void hmp_replay_break(Monitor *mon, const QDict *qdict); void hmp_replay_delete_break(Monitor *mon, const QDict *qdict); +void hmp_replay_seek(Monitor *mon, const QDict *qdict); #endif diff --git a/qapi/replay.json b/qapi/replay.json index 173ba76107..bfd83d7591 100644 --- a/qapi/replay.json +++ b/qapi/replay.json @@ -99,3 +99,23 @@ # ## { 'command': 'replay-delete-break' } + +## +# @replay-seek: +# +# Automatically proceed to the instruction count @icount, when +# replaying the execution. The command automatically loads nearest +# snapshot and replays the execution to find the desired instruction. +# When there is no preceding snapshot or the execution is not replayed, +# then the command fails. +# icount for the reference may be obtained with @query-replay command. +# +# @icount: target instruction count +# +# Since: 5.2 +# +# Example: +# +# -> { "execute": "replay-seek", "data": { "icount": 220414 } } +## +{ 'command': 'replay-seek', 'data': { 'icount': 'int' } } diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c index 86e19bb217..cfd0221692 100644 --- a/replay/replay-debugging.c +++ b/replay/replay-debugging.c @@ -19,6 +19,8 @@ #include "qapi/qapi-commands-replay.h" #include "qapi/qmp/qdict.h" #include "qemu/timer.h" +#include "block/snapshot.h" +#include "migration/snapshot.h" void hmp_info_replay(Monitor *mon, const QDict *qdict) { @@ -127,3 +129,93 @@ void hmp_replay_delete_break(Monitor *mon, const QDict *qdict) return; } } + +static char *replay_find_nearest_snapshot(int64_t icount, + int64_t *snapshot_icount) +{ + BlockDriverState *bs; + QEMUSnapshotInfo *sn_tab; + QEMUSnapshotInfo *nearest = NULL; + char *ret = NULL; + int nb_sns, i; + AioContext *aio_context; + + *snapshot_icount = -1; + + bs = bdrv_all_find_vmstate_bs(); + if (!bs) { + goto fail; + } + aio_context = bdrv_get_aio_context(bs); + + aio_context_acquire(aio_context); + nb_sns = bdrv_snapshot_list(bs, &sn_tab); + aio_context_release(aio_context); + + for (i = 0; i < nb_sns; i++) { + if (bdrv_all_find_snapshot(sn_tab[i].name, &bs) == 0) { + if (sn_tab[i].icount != -1ULL + && sn_tab[i].icount <= icount + && (!nearest || nearest->icount < sn_tab[i].icount)) { + nearest = &sn_tab[i]; + } + } + } + if (nearest) { + ret = g_strdup(nearest->name); + *snapshot_icount = nearest->icount; + } + g_free(sn_tab); + +fail: + return ret; +} + +static void replay_seek(int64_t icount, QEMUTimerCB callback, Error **errp) +{ + char *snapshot = NULL; + int64_t snapshot_icount; + + if (replay_mode != REPLAY_MODE_PLAY) { + error_setg(errp, "replay must be enabled to seek"); + return; + } + if (!replay_snapshot) { + error_setg(errp, "snapshotting is disabled"); + return; + } + + snapshot = replay_find_nearest_snapshot(icount, &snapshot_icount); + if (snapshot) { + if (icount < replay_get_current_icount() + || replay_get_current_icount() < snapshot_icount) { + vm_stop(RUN_STATE_RESTORE_VM); + load_snapshot(snapshot, errp); + } + g_free(snapshot); + } + if (replay_get_current_icount() <= icount) { + replay_break(icount, callback, NULL); + vm_start(); + } else { + error_setg(errp, "cannot seek to the specified instruction count"); + } +} + +void qmp_replay_seek(int64_t icount, Error **errp) +{ + replay_seek(icount, replay_stop_vm, errp); +} + +void hmp_replay_seek(Monitor *mon, const QDict *qdict) +{ + int64_t icount = qdict_get_try_int(qdict, "icount", -1LL); + Error *err = NULL; + + qmp_replay_seek(icount, &err); + if (err) { + error_report_err(err); + error_free(err); + return; + } +} From patchwork Tue Aug 11 11:01:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 11709073 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E046714E3 for ; Tue, 11 Aug 2020 11:07:12 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C101B2075D for ; Tue, 11 Aug 2020 11:07:12 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C101B2075D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=ispras.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:45368 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5S7c-0005tB-2d for patchwork-qemu-devel@patchwork.kernel.org; Tue, 11 Aug 2020 07:07:12 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46326) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2U-0003sA-VS for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:54 -0400 Received: from mail.ispras.ru ([83.149.199.84]:42422) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2T-0003OG-2v for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:01:54 -0400 Received: from [127.0.1.1] (unknown [62.118.151.149]) by mail.ispras.ru (Postfix) with ESMTPSA id 303AB4089F07; Tue, 11 Aug 2020 11:01:51 +0000 (UTC) Subject: [PATCH v2 10/14] replay: flush rr queue before loading the vmstate From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Tue, 11 Aug 2020 14:01:50 +0300 Message-ID: <159714371090.18946.17522377300666666629.stgit@pasha-ThinkPad-X280> In-Reply-To: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> References: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Received-SPF: pass client-ip=83.149.199.84; envelope-from=pavel.dovgalyuk@ispras.ru; helo=mail.ispras.ru X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 07:00:54 X-ACL-Warn: Detected OS = Linux 3.11 and newer X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, wrampazz@redhat.com, pavel.dovgalyuk@ispras.ru, ehabkost@redhat.com, alex.bennee@linaro.org, mtosatti@redhat.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com, philmd@redhat.com, zhiwei_liu@c-sky.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Pavel Dovgalyuk Non-empty record/replay queue prevents saving and loading the VM state, because it includes pending bottom halves and block coroutines. But when the new VM state is loaded, we don't have to preserve the consistency of the current state anymore. Therefore this patch just flushes the queue allowing the coroutines to finish and removes checking for empty rr queue for load_snapshot function. Signed-off-by: Pavel Dovgalyuk --- include/sysemu/replay.h | 2 ++ migration/savevm.c | 12 ++++++------ replay/replay-events.c | 4 ++++ replay/replay-internal.h | 2 -- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index e00ed2f4a5..239c01e7df 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -149,6 +149,8 @@ void replay_disable_events(void); void replay_enable_events(void); /*! Returns true when saving events is enabled */ bool replay_events_enabled(void); +/* Flushes events queue */ +void replay_flush_events(void); /*! Adds bottom half event to the queue */ void replay_bh_schedule_event(QEMUBH *bh); /* Adds oneshot bottom half event to the queue */ diff --git a/migration/savevm.c b/migration/savevm.c index d56d9729bd..25df75179a 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -2880,12 +2880,6 @@ int load_snapshot(const char *name, Error **errp) AioContext *aio_context; MigrationIncomingState *mis = migration_incoming_get_current(); - if (!replay_can_snapshot()) { - error_setg(errp, "Record/replay does not allow loading snapshot " - "right now. Try once more later."); - return -EINVAL; - } - if (!bdrv_all_can_snapshot(&bs)) { error_setg(errp, "Device '%s' is writable but does not support snapshots", @@ -2919,6 +2913,12 @@ int load_snapshot(const char *name, Error **errp) return -EINVAL; } + /* + * Flush the record/replay queue. Now the VM state is going + * to change. Therefore we don't need to preserve its consistency + */ + replay_flush_events(); + /* Flush all IO requests so they don't interfere with the new state. */ bdrv_drain_all_begin(); diff --git a/replay/replay-events.c b/replay/replay-events.c index 302b84043a..a1c6bb934e 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -77,6 +77,10 @@ bool replay_has_events(void) void replay_flush_events(void) { + if (replay_mode == REPLAY_MODE_NONE) { + return; + } + g_assert(replay_mutex_locked()); while (!QTAILQ_EMPTY(&events_list)) { diff --git a/replay/replay-internal.h b/replay/replay-internal.h index 2f6145ec7c..97649ed8d7 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -149,8 +149,6 @@ void replay_read_next_clock(unsigned int kind); void replay_init_events(void); /*! Clears internal data structures for events handling */ void replay_finish_events(void); -/*! Flushes events queue */ -void replay_flush_events(void); /*! Returns true if there are any unsaved events in the queue */ bool replay_has_events(void); /*! Saves events from queue into the file */ From patchwork Tue Aug 11 11:01:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 11709061 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E9808109A for ; Tue, 11 Aug 2020 11:04:11 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C8AAA2076C for ; Tue, 11 Aug 2020 11:04:11 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C8AAA2076C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=ispras.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:59474 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5S4h-00008u-1V for patchwork-qemu-devel@patchwork.kernel.org; Tue, 11 Aug 2020 07:04:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46346) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2c-00044N-HO for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:02:02 -0400 Received: from mail.ispras.ru ([83.149.199.84]:42438) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2a-0003Od-0U for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:02:02 -0400 Received: from [127.0.1.1] (unknown [62.118.151.149]) by mail.ispras.ru (Postfix) with ESMTPSA id E7AD94089EF7; Tue, 11 Aug 2020 11:01:56 +0000 (UTC) Subject: [PATCH v2 11/14] gdbstub: add reverse step support in replay mode From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Tue, 11 Aug 2020 14:01:56 +0300 Message-ID: <159714371666.18946.16052695579115520332.stgit@pasha-ThinkPad-X280> In-Reply-To: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> References: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Received-SPF: pass client-ip=83.149.199.84; envelope-from=pavel.dovgalyuk@ispras.ru; helo=mail.ispras.ru X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 07:00:54 X-ACL-Warn: Detected OS = Linux 3.11 and newer X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, wrampazz@redhat.com, pavel.dovgalyuk@ispras.ru, ehabkost@redhat.com, alex.bennee@linaro.org, mtosatti@redhat.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com, philmd@redhat.com, zhiwei_liu@c-sky.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Pavel Dovgalyuk GDB remote protocol supports two reverse debugging commands: reverse step and reverse continue. This patch adds support of the first one to the gdbstub. Reverse step is intended to step one instruction in the backwards direction. This is not possible in regular execution. But replayed execution is deterministic, therefore we can load one of the prior snapshots and proceed to the desired step. It is equivalent to stepping one instruction back. There should be at least one snapshot preceding the debugged part of the replay log. Signed-off-by: Pavel Dovgalyuk --- accel/tcg/translator.c | 1 + exec.c | 7 ++++++ gdbstub.c | 55 +++++++++++++++++++++++++++++++++++++++++++-- include/sysemu/replay.h | 11 +++++++++ replay/replay-debugging.c | 33 +++++++++++++++++++++++++++ softmmu/cpus.c | 14 +++++++++-- stubs/replay.c | 5 ++++ 7 files changed, 121 insertions(+), 5 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 603d17ff83..fb1e19c585 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -17,6 +17,7 @@ #include "exec/log.h" #include "exec/translator.h" #include "exec/plugin-gen.h" +#include "sysemu/replay.h" /* Pairs with tcg_clear_temp_count. To be called by #TranslatorOps.{translate_insn,tb_stop} if diff --git a/exec.c b/exec.c index 6f381f98e2..8bcc8180e4 100644 --- a/exec.c +++ b/exec.c @@ -2750,6 +2750,13 @@ void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len, QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) { if (watchpoint_address_matches(wp, addr, len) && (wp->flags & flags)) { + if (replay_running_debug()) { + /* + * Don't process the watchpoints when we are + * in a reverse debugging operation. + */ + return; + } if (flags == BP_MEM_READ) { wp->flags |= BP_WATCHPOINT_HIT_READ; } else { diff --git a/gdbstub.c b/gdbstub.c index f3a318cd7f..03c8a491ed 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -51,6 +51,7 @@ #include "sysemu/runstate.h" #include "hw/semihosting/semihost.h" #include "exec/exec-all.h" +#include "sysemu/replay.h" #ifdef CONFIG_USER_ONLY #define GDB_ATTACHED "0" @@ -375,6 +376,20 @@ typedef struct GDBState { */ static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER; +/* Retrieves flags for single step mode. */ +static int get_sstep_flags(void) +{ + /* + * In replay mode all events written into the log should be replayed. + * That is why NOIRQ flag is removed in this mode. + */ + if (replay_mode != REPLAY_MODE_NONE) { + return SSTEP_ENABLE; + } else { + return sstep_flags; + } +} + static GDBState gdbserver_state; static void init_gdbserver_state(void) @@ -501,7 +516,7 @@ static int gdb_continue_partial(char *newstates) break; /* nothing to do here */ case 's': trace_gdbstub_op_stepping(cpu->cpu_index); - cpu_single_step(cpu, sstep_flags); + cpu_single_step(cpu, get_sstep_flags()); cpu_resume(cpu); flag = 1; break; @@ -1874,10 +1889,31 @@ static void handle_step(GdbCmdContext *gdb_ctx, void *user_ctx) gdb_set_cpu_pc((target_ulong)gdb_ctx->params[0].val_ull); } - cpu_single_step(gdbserver_state.c_cpu, sstep_flags); + cpu_single_step(gdbserver_state.c_cpu, get_sstep_flags()); gdb_continue(); } +static void handle_backward(GdbCmdContext *gdb_ctx, void *user_ctx) +{ + if (replay_mode != REPLAY_MODE_PLAY) { + put_packet("E22"); + } + if (gdb_ctx->num_params == 1) { + switch (gdb_ctx->params[0].opcode) { + case 's': + if (replay_reverse_step()) { + gdb_continue(); + } else { + put_packet("E14"); + } + return; + } + } + + /* Default invalid command */ + put_packet(""); +} + static void handle_v_cont_query(GdbCmdContext *gdb_ctx, void *user_ctx) { put_packet("vCont;c;C;s;S"); @@ -2124,6 +2160,10 @@ static void handle_query_supported(GdbCmdContext *gdb_ctx, void *user_ctx) g_string_append(gdbserver_state.str_buf, ";qXfer:features:read+"); } + if (replay_mode == REPLAY_MODE_PLAY) { + g_string_append(gdbserver_state.str_buf, ";ReverseStep+"); + } + if (gdb_ctx->num_params && strstr(gdb_ctx->params[0].data, "multiprocess+")) { gdbserver_state.multiprocess = true; @@ -2460,6 +2500,17 @@ static int gdb_handle_packet(const char *line_buf) cmd_parser = &step_cmd_desc; } break; + case 'b': + { + static const GdbCmdParseEntry backward_cmd_desc = { + .handler = handle_backward, + .cmd = "b", + .cmd_startswith = 1, + .schema = "o0" + }; + cmd_parser = &backward_cmd_desc; + } + break; case 'F': { static const GdbCmdParseEntry file_io_cmd_desc = { diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index 239c01e7df..13a8123b09 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -75,6 +75,17 @@ void replay_finish(void); void replay_add_blocker(Error *reason); /* Returns name of the replay log file */ const char *replay_get_filename(void); +/* + * Start making one step in backward direction. + * Used by gdbstub for backwards debugging. + * Returns true on success. + */ +bool replay_reverse_step(void); +/* + * Returns true if replay module is processing + * reverse_continue or reverse_step request + */ +bool replay_running_debug(void); /* Processing the instructions */ diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c index cfd0221692..aa3ca040e2 100644 --- a/replay/replay-debugging.c +++ b/replay/replay-debugging.c @@ -22,6 +22,13 @@ #include "block/snapshot.h" #include "migration/snapshot.h" +static bool replay_is_debugging; + +bool replay_running_debug(void) +{ + return replay_is_debugging; +} + void hmp_info_replay(Monitor *mon, const QDict *qdict) { if (replay_mode == REPLAY_MODE_NONE) { @@ -219,3 +226,29 @@ void hmp_replay_seek(Monitor *mon, const QDict *qdict) return; } } + +static void replay_stop_vm_debug(void *opaque) +{ + replay_is_debugging = false; + vm_stop(RUN_STATE_DEBUG); + replay_delete_break(); +} + +bool replay_reverse_step(void) +{ + Error *err = NULL; + + assert(replay_mode == REPLAY_MODE_PLAY); + + if (replay_get_current_icount() != 0) { + replay_seek(replay_get_current_icount() - 1, replay_stop_vm_debug, &err); + if (err) { + error_free(err); + return false; + } + replay_is_debugging = true; + return true; + } + + return false; +} diff --git a/softmmu/cpus.c b/softmmu/cpus.c index a802e899ab..377fe3298c 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -1004,9 +1004,17 @@ static bool cpu_can_run(CPUState *cpu) static void cpu_handle_guest_debug(CPUState *cpu) { - gdb_set_stop_cpu(cpu); - qemu_system_debug_request(); - cpu->stopped = true; + if (!replay_running_debug()) { + gdb_set_stop_cpu(cpu); + qemu_system_debug_request(); + cpu->stopped = true; + } else { + if (!cpu->singlestep_enabled) { + cpu_single_step(cpu, SSTEP_ENABLE); + } else { + cpu_single_step(cpu, 0); + } + } } #ifdef CONFIG_LINUX diff --git a/stubs/replay.c b/stubs/replay.c index eacb366aa8..d5b52302e9 100644 --- a/stubs/replay.c +++ b/stubs/replay.c @@ -93,3 +93,8 @@ uint64_t replay_get_current_icount(void) { return 0; } + +bool replay_reverse_step(void) +{ + return false; +} From patchwork Tue Aug 11 11:02:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 11709075 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8C1D814E3 for ; Tue, 11 Aug 2020 11:08:41 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 6BA7D2075D for ; Tue, 11 Aug 2020 11:08:41 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 6BA7D2075D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=ispras.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:51214 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5S92-0008Dk-M6 for patchwork-qemu-devel@patchwork.kernel.org; Tue, 11 Aug 2020 07:08:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46366) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2h-00048s-SD for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:02:07 -0400 Received: from mail.ispras.ru ([83.149.199.84]:42454) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2e-0003Ot-Oa for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:02:07 -0400 Received: from [127.0.1.1] (unknown [62.118.151.149]) by mail.ispras.ru (Postfix) with ESMTPSA id 9799A4089EF7; Tue, 11 Aug 2020 11:02:02 +0000 (UTC) Subject: [PATCH v2 12/14] gdbstub: add reverse continue support in replay mode From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Tue, 11 Aug 2020 14:02:02 +0300 Message-ID: <159714372235.18946.899868890514386160.stgit@pasha-ThinkPad-X280> In-Reply-To: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> References: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Received-SPF: pass client-ip=83.149.199.84; envelope-from=pavel.dovgalyuk@ispras.ru; helo=mail.ispras.ru X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 07:00:54 X-ACL-Warn: Detected OS = Linux 3.11 and newer X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, wrampazz@redhat.com, pavel.dovgalyuk@ispras.ru, ehabkost@redhat.com, alex.bennee@linaro.org, mtosatti@redhat.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com, philmd@redhat.com, zhiwei_liu@c-sky.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Pavel Dovgalyuk This patch adds support of the reverse continue operation for gdbstub. Reverse continue finds the last breakpoint that would happen in normal execution from the beginning to the current moment. Implementation of the reverse continue replays the execution twice: to find the breakpoints that were hit and to seek to the last breakpoint. Reverse continue loads the previous snapshot and tries to find the breakpoint since that moment. If there are no such breakpoints, it proceeds to the earlier snapshot, and so on. When no breakpoints or watchpoints were hit at all, execution stops at the beginning of the replay log. Signed-off-by: Pavel Dovgalyuk --- exec.c | 1 + gdbstub.c | 10 ++++++ include/sysemu/replay.h | 8 +++++ replay/replay-debugging.c | 71 +++++++++++++++++++++++++++++++++++++++++++++ softmmu/cpus.c | 5 +++ stubs/replay.c | 5 +++ 6 files changed, 99 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 8bcc8180e4..ac9ebfdacc 100644 --- a/exec.c +++ b/exec.c @@ -2755,6 +2755,7 @@ void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len, * Don't process the watchpoints when we are * in a reverse debugging operation. */ + replay_breakpoint(); return; } if (flags == BP_MEM_READ) { diff --git a/gdbstub.c b/gdbstub.c index 03c8a491ed..61e986a303 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -1907,6 +1907,13 @@ static void handle_backward(GdbCmdContext *gdb_ctx, void *user_ctx) put_packet("E14"); } return; + case 'c': + if (replay_reverse_continue()) { + gdb_continue(); + } else { + put_packet("E14"); + } + return; } } @@ -2161,7 +2168,8 @@ static void handle_query_supported(GdbCmdContext *gdb_ctx, void *user_ctx) } if (replay_mode == REPLAY_MODE_PLAY) { - g_string_append(gdbserver_state.str_buf, ";ReverseStep+"); + g_string_append(gdbserver_state.str_buf, + ";ReverseStep+;ReverseContinue+"); } if (gdb_ctx->num_params && diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index 13a8123b09..b6cac175c4 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -81,11 +81,19 @@ const char *replay_get_filename(void); * Returns true on success. */ bool replay_reverse_step(void); +/* + * Start searching the last breakpoint/watchpoint. + * Used by gdbstub for backwards debugging. + * Returns true if the process successfully started. + */ +bool replay_reverse_continue(void); /* * Returns true if replay module is processing * reverse_continue or reverse_step request */ bool replay_running_debug(void); +/* Called in reverse debugging mode to collect breakpoint information */ +void replay_breakpoint(void); /* Processing the instructions */ diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c index aa3ca040e2..27af103118 100644 --- a/replay/replay-debugging.c +++ b/replay/replay-debugging.c @@ -23,6 +23,8 @@ #include "migration/snapshot.h" static bool replay_is_debugging; +static int64_t replay_last_breakpoint; +static int64_t replay_last_snapshot; bool replay_running_debug(void) { @@ -252,3 +254,72 @@ bool replay_reverse_step(void) return false; } + +static void replay_continue_end(void) +{ + replay_is_debugging = false; + vm_stop(RUN_STATE_DEBUG); + replay_delete_break(); +} + +static void replay_continue_stop(void *opaque) +{ + Error *err = NULL; + if (replay_last_breakpoint != -1LL) { + replay_seek(replay_last_breakpoint, replay_stop_vm_debug, &err); + if (err) { + error_free(err); + replay_continue_end(); + } + return; + } + /* + * No breakpoints since the last snapshot. + * Find previous snapshot and try again. + */ + if (replay_last_snapshot != 0) { + replay_seek(replay_last_snapshot - 1, replay_continue_stop, &err); + if (err) { + error_free(err); + replay_continue_end(); + } + replay_last_snapshot = replay_get_current_icount(); + return; + } else { + /* Seek to the very first step */ + replay_seek(0, replay_stop_vm_debug, &err); + if (err) { + error_free(err); + replay_continue_end(); + } + return; + } + replay_continue_end(); +} + +bool replay_reverse_continue(void) +{ + Error *err = NULL; + + assert(replay_mode == REPLAY_MODE_PLAY); + + if (replay_get_current_icount() != 0) { + replay_seek(replay_get_current_icount() - 1, replay_continue_stop, &err); + if (err) { + error_free(err); + return false; + } + replay_last_breakpoint = -1LL; + replay_is_debugging = true; + replay_last_snapshot = replay_get_current_icount(); + return true; + } + + return false; +} + +void replay_breakpoint(void) +{ + assert(replay_mode == REPLAY_MODE_PLAY); + replay_last_breakpoint = replay_get_current_icount(); +} diff --git a/softmmu/cpus.c b/softmmu/cpus.c index 377fe3298c..7714cb663c 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -1010,6 +1010,11 @@ static void cpu_handle_guest_debug(CPUState *cpu) cpu->stopped = true; } else { if (!cpu->singlestep_enabled) { + /* + * Report about the breakpoint and + * make a single step to skip it + */ + replay_breakpoint(); cpu_single_step(cpu, SSTEP_ENABLE); } else { cpu_single_step(cpu, 0); diff --git a/stubs/replay.c b/stubs/replay.c index d5b52302e9..45ebe77fb9 100644 --- a/stubs/replay.c +++ b/stubs/replay.c @@ -98,3 +98,8 @@ bool replay_reverse_step(void) { return false; } + +bool replay_reverse_continue(void) +{ + return false; +} From patchwork Tue Aug 11 11:02:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 11709065 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 14CE9109A for ; Tue, 11 Aug 2020 11:05:19 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E9C142075D for ; Tue, 11 Aug 2020 11:05:18 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E9C142075D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=ispras.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:36780 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5S5m-0002O5-5y for patchwork-qemu-devel@patchwork.kernel.org; Tue, 11 Aug 2020 07:05:18 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46378) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2l-0004CR-Og for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:02:11 -0400 Received: from mail.ispras.ru ([83.149.199.84]:42476) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2k-0003PE-1X for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:02:11 -0400 Received: from [127.0.1.1] (unknown [62.118.151.149]) by mail.ispras.ru (Postfix) with ESMTPSA id 47C754089EF7; Tue, 11 Aug 2020 11:02:08 +0000 (UTC) Subject: [PATCH v2 13/14] replay: describe reverse debugging in docs/replay.txt From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Tue, 11 Aug 2020 14:02:08 +0300 Message-ID: <159714372804.18946.9062781343195564152.stgit@pasha-ThinkPad-X280> In-Reply-To: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> References: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Received-SPF: pass client-ip=83.149.199.84; envelope-from=pavel.dovgalyuk@ispras.ru; helo=mail.ispras.ru X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 07:00:54 X-ACL-Warn: Detected OS = Linux 3.11 and newer X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, wrampazz@redhat.com, pavel.dovgalyuk@ispras.ru, ehabkost@redhat.com, alex.bennee@linaro.org, mtosatti@redhat.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com, philmd@redhat.com, zhiwei_liu@c-sky.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Pavel Dovgalyuk This patch updates the documentation and describes usage of the reverse debugging in QEMU+GDB. Signed-off-by: Pavel Dovgalyuk --- docs/replay.txt | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/replay.txt b/docs/replay.txt index 70c27edb36..18d6169f3b 100644 --- a/docs/replay.txt +++ b/docs/replay.txt @@ -294,6 +294,39 @@ for recording and replaying must contain identical number of ports in record and replay modes, but their backends may differ. E.g., '-serial stdio' in record mode, and '-serial null' in replay mode. +Reverse debugging +----------------- + +Reverse debugging allows "executing" the program in reverse direction. +GDB remote protocol supports "reverse step" and "reverse continue" +commands. The first one steps single instruction backwards in time, +and the second one finds the last breakpoint in the past. + +Recorded executions may be used to enable reverse debugging. QEMU can't +execute the code in backwards direction, but can load a snapshot and +replay forward to find the desired position or breakpoint. + +The following GDB commands are supported: + - reverse-stepi (or rsi) - step one instruction backwards + - reverse-continue (or rc) - find last breakpoint in the past + +Reverse step loads the nearest snapshot and replays the execution until +the required instruction is met. + +Reverse continue may include several passes of examining the execution +between the snapshots. Each of the passes include the following steps: + 1. loading the snapshot + 2. replaying to examine the breakpoints + 3. if breakpoint or watchpoint was met + - loading the snaphot again + - replaying to the required breakpoint + 4. else + - proceeding to the p.1 with the earlier snapshot + +Therefore usage of the reverse debugging requires at least one snapshot +created in advance. See the "Snapshotting" section to learn about running +record/replay and creating the snapshot in these modes. + Replay log format ----------------- From patchwork Tue Aug 11 11:02:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 11709069 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 456AC174A for ; Tue, 11 Aug 2020 11:05:48 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 26B8420771 for ; Tue, 11 Aug 2020 11:05:48 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 26B8420771 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=ispras.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:39768 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5S6F-0003dx-A4 for patchwork-qemu-devel@patchwork.kernel.org; Tue, 11 Aug 2020 07:05:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46434) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2t-0004Mf-0T for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:02:19 -0400 Received: from mail.ispras.ru ([83.149.199.84]:42498) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k5S2q-0003PQ-0B for qemu-devel@nongnu.org; Tue, 11 Aug 2020 07:02:18 -0400 Received: from [127.0.1.1] (unknown [62.118.151.149]) by mail.ispras.ru (Postfix) with ESMTPSA id 027664089F1B; Tue, 11 Aug 2020 11:02:13 +0000 (UTC) Subject: [PATCH v2 14/14] tests/acceptance: add reverse debugging test From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Tue, 11 Aug 2020 14:02:13 +0300 Message-ID: <159714373372.18946.438886339476597109.stgit@pasha-ThinkPad-X280> In-Reply-To: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> References: <159714365354.18946.2967871683340522027.stgit@pasha-ThinkPad-X280> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Received-SPF: pass client-ip=83.149.199.84; envelope-from=pavel.dovgalyuk@ispras.ru; helo=mail.ispras.ru X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/11 07:00:54 X-ACL-Warn: Detected OS = Linux 3.11 and newer X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, 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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, wrampazz@redhat.com, pavel.dovgalyuk@ispras.ru, ehabkost@redhat.com, alex.bennee@linaro.org, mtosatti@redhat.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com, crosa@redhat.com, pbonzini@redhat.com, philmd@redhat.com, zhiwei_liu@c-sky.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" From: Pavel Dovgalyuk This is a test for GDB reverse debugging commands: reverse step and reverse continue. Every test in this suite consists of two phases: record and replay. Recording saves the execution of some instructions and makes an initial VM snapshot to allow reverse execution. Replay saves the order of the first instructions and then checks that they are executed backwards in the correct order. After that the execution is replayed to the end, and reverse continue command is checked by setting several breakpoints, and asserting that the execution is stopped at the last of them. Signed-off-by: Pavel Dovgalyuk --- MAINTAINERS | 1 tests/acceptance/reverse_debugging.py | 203 +++++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 tests/acceptance/reverse_debugging.py diff --git a/MAINTAINERS b/MAINTAINERS index 50fc44680c..22d44c4857 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2643,6 +2643,7 @@ F: include/sysemu/replay.h F: docs/replay.txt F: stubs/replay.c F: tests/acceptance/replay_kernel.py +F: tests/acceptance/reverse_debugging.py F: qapi/replay.json IOVA Tree diff --git a/tests/acceptance/reverse_debugging.py b/tests/acceptance/reverse_debugging.py new file mode 100644 index 0000000000..dda42e1c1a --- /dev/null +++ b/tests/acceptance/reverse_debugging.py @@ -0,0 +1,203 @@ +# Reverse debugging test +# +# Copyright (c) 2020 ISP RAS +# +# Author: +# Pavel Dovgalyuk +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. +import os +import logging + +from avocado_qemu import BUILD_DIR +from avocado.utils import gdb +from avocado.utils import process +from avocado.utils.path import find_command +from boot_linux_console import LinuxKernelTest + +class ReverseDebugging(LinuxKernelTest): + """ + Test GDB reverse debugging commands: reverse step and reverse continue. + Recording saves the execution of some instructions and makes an initial + VM snapshot to allow reverse execution. + Replay saves the order of the first instructions and then checks that they + are executed backwards in the correct order. + After that the execution is replayed to the end, and reverse continue + command is checked by setting several breakpoints, and asserting + that the execution is stopped at the last of them. + """ + + timeout = 10 + STEPS = 10 + endian_is_le = True + + def run_vm(self, record, shift, args, replay_path, image_path): + logger = logging.getLogger('replay') + vm = self.get_vm() + vm.set_console() + if record: + logger.info('recording the execution...') + mode = 'record' + else: + logger.info('replaying the execution...') + mode = 'replay' + vm.add_args('-s', '-S') + vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s,rrsnapshot=init' % + (shift, mode, replay_path), + '-net', 'none') + vm.add_args('-drive', 'file=%s,if=none' % image_path) + if args: + vm.add_args(*args) + vm.launch() + return vm + + @staticmethod + def get_reg_le(g, reg): + res = g.cmd(b'p%x' % reg) + num = 0 + for i in range(len(res))[-2::-2]: + num = 0x100 * num + int(res[i:i + 2], 16) + return num + + @staticmethod + def get_reg_be(g, reg): + res = g.cmd(b'p%x' % reg) + return int(res, 16) + + def get_reg(self, g, reg): + # value may be encoded in BE or LE order + if self.endian_is_le: + return self.get_reg_le(g, reg) + else: + return self.get_reg_be(g, reg) + + def get_pc(self, g): + return self.get_reg(g, self.REG_PC) + + def check_pc(self, g, addr): + pc = self.get_pc(g) + if pc != addr: + self.fail('Invalid PC (read %x instead of %x)' % (pc, addr)) + + @staticmethod + def gdb_step(g): + g.cmd(b's', b'T05thread:01;') + + @staticmethod + def gdb_bstep(g): + g.cmd(b'bs', b'T05thread:01;') + + @staticmethod + def vm_get_icount(vm): + return vm.qmp('query-replay')['return']['icount'] + + def reverse_debugging(self, shift=7, args=None): + logger = logging.getLogger('replay') + + # create qcow2 for snapshots + logger.info('creating qcow2 image for VM snapshots') + image_path = os.path.join(self.workdir, 'disk.qcow2') + qemu_img = os.path.join(BUILD_DIR, 'qemu-img') + if not os.path.exists(qemu_img): + qemu_img = find_command('qemu-img', False) + if qemu_img is False: + self.cancel('Could not find "qemu-img", which is required to ' + 'create the temporary qcow2 image') + cmd = '%s create -f qcow2 %s 128M' % (qemu_img, image_path) + process.run(cmd) + + replay_path = os.path.join(self.workdir, 'replay.bin') + + # record the log + vm = self.run_vm(True, shift, args, replay_path, image_path) + while self.vm_get_icount(vm) <= self.STEPS: + pass + last_icount = self.vm_get_icount(vm) + vm.shutdown() + + logger.info("recorded log with %s+ steps" % last_icount) + + # replay and run debug commands + vm = self.run_vm(False, shift, args, replay_path, image_path) + logger.info('connecting to gdbstub') + g = gdb.GDBRemote('127.0.0.1', 1234, False, False) + g.connect() + r = g.cmd(b'qSupported') + if b'qXfer:features:read+' in r: + g.cmd(b'qXfer:features:read:target.xml:0,ffb') + if b'ReverseStep+' not in r: + self.fail('Reverse step is not supported by QEMU') + if b'ReverseContinue+' not in r: + self.fail('Reverse continue is not supported by QEMU') + + logger.info('stepping forward') + steps = [] + # record first instruction addresses + for _ in range(self.STEPS): + pc = self.get_pc(g) + logger.info('saving position %x' % pc) + steps.append(pc) + self.gdb_step(g) + + # visit the recorded instruction in reverse order + logger.info('stepping backward') + for addr in steps[::-1]: + self.gdb_bstep(g) + self.check_pc(g, addr) + logger.info('found position %x' % addr) + + logger.info('seeking to the end (icount %s)' % (last_icount - 1)) + vm.qmp('replay-break', icount=last_icount - 1) + # continue - will return after pausing + g.cmd(b'c', b'T02thread:01;') + + logger.info('setting breakpoints') + for addr in steps: + # hardware breakpoint at addr with len=1 + g.cmd(b'Z1,%x,1' % addr, b'OK') + + logger.info('running reverse continue to reach %x' % steps[-1]) + # reverse continue - will return after stopping at the breakpoint + g.cmd(b'bc', b'T05thread:01;') + + # assume that none of the first instructions is executed again + # breaking the order of the breakpoints + self.check_pc(g, steps[-1]) + logger.info('successfully reached %x' % steps[-1]) + + logger.info('exitting gdb and qemu') + vm.shutdown() + +class ReverseDebugging_X86_64(ReverseDebugging): + REG_PC = 0x10 + REG_CS = 0x12 + def get_pc(self, g): + return self.get_reg_le(g, self.REG_PC) \ + + self.get_reg_le(g, self.REG_CS) * 0x10 + + def test_x86_64_pc(self): + """ + :avocado: tags=arch:x86_64 + :avocado: tags=machine:pc + """ + # start with BIOS only + self.reverse_debugging() + +class ReverseDebugging_AArch64(ReverseDebugging): + REG_PC = 32 + + def test_aarch64_virt(self): + """ + :avocado: tags=arch:aarch64 + :avocado: tags=machine:virt + :avocado: tags=cpu:cortex-a53 + """ + kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' + '/linux/releases/29/Everything/aarch64/os/images/pxeboot' + '/vmlinuz') + kernel_hash = '8c73e469fc6ea06a58dc83a628fc695b693b8493' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + + self.reverse_debugging( + args=('-kernel', kernel_path, '-cpu', 'cortex-a53'))