From patchwork Mon May 28 07:14:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 921339 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ispras.ru Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40vSvY6kg9z9s08 for ; Mon, 28 May 2018 17:21:13 +1000 (AEST) Received: from localhost ([::1]:54565 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fNCSt-0001LX-F7 for incoming@patchwork.ozlabs.org; Mon, 28 May 2018 03:21:11 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34523) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fNCMM-0004oe-6k for qemu-devel@nongnu.org; Mon, 28 May 2018 03:14:27 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fNCMK-0007YN-S9 for qemu-devel@nongnu.org; Mon, 28 May 2018 03:14:26 -0400 Received: from mail.ispras.ru ([83.149.199.45]:46816) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fNCMK-0007Xf-EP for qemu-devel@nongnu.org; Mon, 28 May 2018 03:14:24 -0400 Received: from [127.0.1.1] (unknown [85.142.117.226]) by mail.ispras.ru (Postfix) with ESMTPSA id 8B7B75400E3; Mon, 28 May 2018 10:14:23 +0300 (MSK) From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Mon, 28 May 2018 10:14:24 +0300 Message-ID: <20180528071424.9424.51699.stgit@pasha-VirtualBox> In-Reply-To: <20180528071332.9424.27343.stgit@pasha-VirtualBox> References: <20180528071332.9424.27343.stgit@pasha-VirtualBox> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 83.149.199.45 Subject: [Qemu-devel] [PATCH v4 09/19] replay: introduce breakpoint at the specified step X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, peter.maydell@linaro.org, war2jordan@live.com, pavel.dovgaluk@ispras.ru, pbonzini@redhat.com, quintela@redhat.com, ciro.santilli@gmail.com, jasowang@redhat.com, crosthwaite.peter@gmail.com, zuban32s@gmail.com, armbru@redhat.com, maria.klimushenkova@ispras.ru, mst@redhat.com, kraxel@redhat.com, boost.lists@gmail.com, thomas.dullien@googlemail.com, dovgaluk@ispras.ru, mreitz@redhat.com, alex.bennee@linaro.org, dgilbert@redhat.com, rth@twiddle.net Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This patch introduces replay_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. The commands have one argument - number of instructions executed since the start of the replay. Signed-off-by: Pavel Dovgalyuk --- v2: - renamed replay_break qmp command into replay-break (suggested by Eric Blake) --- hmp-commands.hx | 15 ++++++++++++ hmp.h | 1 + include/sysemu/replay.h | 3 ++ qapi/misc.json | 17 ++++++++++++++ replay/replay-debugging.c | 55 +++++++++++++++++++++++++++++++++++++++++++++ replay/replay-internal.h | 4 +++ replay/replay.c | 17 ++++++++++++++ 7 files changed, 112 insertions(+) diff --git a/hmp-commands.hx b/hmp-commands.hx index 0734fea..a6d3f12 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1849,6 +1849,21 @@ Set QOM property @var{property} of object at location @var{path} to value @var{v ETEXI { + .name = "replay_break", + .args_type = "step:i", + .params = "step", + .help = "sets breakpoint on the specified step of the replay", + .cmd = hmp_replay_break, + }, + +STEXI +@item replay_break @var{step} +@findex replay_break +Set breakpoint on the specified step of the replay. +Execution stops when the specified step is reached. +ETEXI + + { .name = "info", .args_type = "item:s?", .params = "[subcommand]", diff --git a/hmp.h b/hmp.h index aeec705..c6b8e37 100644 --- a/hmp.h +++ b/hmp.h @@ -147,5 +147,6 @@ 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); #endif diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index 3ced6bc..98d709c 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -71,6 +71,9 @@ void replay_start(void); void replay_finish(void); /*! Adds replay blocker with the specified error description */ void replay_add_blocker(Error *reason); +/*! Sets breakpoint at the specified step. + If step = -1LL the existing breakpoint is removed. */ +void replay_break(int64_t step, QEMUTimerCB callback, void *opaque); /* Processing the instructions */ diff --git a/qapi/misc.json b/qapi/misc.json index 50029b7..b02e776 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -3133,6 +3133,23 @@ 'returns': 'ReplayInfo' } ## +# @replay-break: +# +# Set breakpoint on the specified step of the replay. +# Execution stops when the specified step is reached. +# +# @step: execution step to stop at +# +# Since: 3.0 +# +# Example: +# +# -> { "execute": "replay-break", "data": { "step": 220414 } } +# +## +{ 'command': 'replay-break', 'data': { 'step': 'int' } } + +## # @xen-load-devices-state: # # Load the state of all devices from file. The RAM and the block devices diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c index 03e7db8..819017e 100644 --- a/replay/replay-debugging.c +++ b/replay/replay-debugging.c @@ -16,6 +16,8 @@ #include "hmp.h" #include "monitor/monitor.h" #include "qapi/qapi-commands-misc.h" +#include "qapi/qmp/qdict.h" +#include "qemu/timer.h" void hmp_info_replay(Monitor *mon, const QDict *qdict) { @@ -39,3 +41,56 @@ ReplayInfo *qmp_query_replay(Error **errp) retval->step = replay_get_current_step(); return retval; } + +void replay_break(int64_t step, QEMUTimerCB callback, void *opaque) +{ + assert(replay_mode == REPLAY_MODE_PLAY); + assert(replay_mutex_locked()); + + replay_break_step = step; + if (replay_break_timer) { + timer_del(replay_break_timer); + timer_free(replay_break_timer); + replay_break_timer = NULL; + } + + if (replay_break_step == -1LL) { + return; + } + assert(replay_break_step >= replay_get_current_step()); + assert(callback); + + replay_break_timer = timer_new_ns(QEMU_CLOCK_REALTIME, callback, opaque); +} + +static void replay_stop_vm(void *opaque) +{ + vm_stop(RUN_STATE_PAUSED); + replay_break(-1LL, NULL, NULL); +} + +void qmp_replay_break(int64_t step, Error **errp) +{ + if (replay_mode == REPLAY_MODE_PLAY) { + if (step >= replay_get_current_step()) { + replay_break(step, replay_stop_vm, NULL); + } else { + error_setg(errp, "cannot set break at the step in the past"); + } + } else { + error_setg(errp, "setting the break is allowed only in play mode"); + } +} + +void hmp_replay_break(Monitor *mon, const QDict *qdict) +{ + int64_t step = qdict_get_try_int(qdict, "step", -1LL); + Error *err = NULL; + + qmp_replay_break(step, &err); + if (err) { + monitor_printf(mon, "replay_break error: %s\n", error_get_pretty(err)); + error_free(err); + return; + } +} diff --git a/replay/replay-internal.h b/replay/replay-internal.h index ef82b5e..34d19eb 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -93,6 +93,10 @@ extern ReplayState replay_state; extern FILE *replay_file; /*! Name of replay file */ extern char *replay_filename; +/*! Step of the replay breakpoint */ +extern int64_t replay_break_step; +/*! 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 8b70d7d..dcce902 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -33,6 +33,10 @@ char *replay_filename; ReplayState replay_state; static GSList *replay_blockers; +/* Replay breakpoints */ +int64_t replay_break_step = -1LL; +QEMUTimer *replay_break_timer; + bool replay_next_event_is(int event) { bool res = false; @@ -72,6 +76,13 @@ int replay_get_instructions(void) replay_mutex_lock(); if (replay_next_event_is(EVENT_INSTRUCTION)) { res = replay_state.instructions_count; + if (replay_break_step != -1LL) { + uint64_t current = replay_get_current_step(); + assert(replay_break_step >= current); + if (current + res > replay_break_step) { + res = replay_break_step - current; + } + } } replay_mutex_unlock(); return res; @@ -98,6 +109,12 @@ void replay_account_executed_instructions(void) will be read from the log. */ qemu_notify_event(); } + /* Execution reached the break step */ + if (replay_break_step == replay_state.current_step) { + /* Cannot make callback directly from the vCPU thread */ + timer_mod_ns(replay_break_timer, + qemu_clock_get_ns(QEMU_CLOCK_REALTIME)); + } } } }