mirror of
https://github.com/mii443/qemu.git
synced 2025-12-16 17:18:49 +00:00
replay: introduce breakpoint at the specified step
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 <Pavel.Dovgalyuk@ispras.ru> Acked-by: Markus Armbruster <armbru@redhat.com> -- v4 changes: - removed useless error_free call Message-Id: <160174520606.12451.7056879546045599378.stgit@pasha-ThinkPad-X280> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
committed by
Paolo Bonzini
parent
e3b09ad2b6
commit
e751067179
@@ -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,84 @@ 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);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user