qemu/replay/replay-debugging.c
<<
>>
Prefs
   1/*
   2 * replay-debugging.c
   3 *
   4 * Copyright (c) 2010-2020 Institute for System Programming
   5 *                         of the Russian Academy of Sciences.
   6 *
   7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   8 * See the COPYING file in the top-level directory.
   9 *
  10 */
  11
  12#include "qemu/osdep.h"
  13#include "qapi/error.h"
  14#include "sysemu/replay.h"
  15#include "sysemu/runstate.h"
  16#include "replay-internal.h"
  17#include "monitor/hmp.h"
  18#include "monitor/monitor.h"
  19#include "qapi/qapi-commands-replay.h"
  20#include "qapi/qmp/qdict.h"
  21#include "qemu/timer.h"
  22#include "block/snapshot.h"
  23#include "migration/snapshot.h"
  24
  25static bool replay_is_debugging;
  26static int64_t replay_last_breakpoint;
  27static int64_t replay_last_snapshot;
  28
  29bool replay_running_debug(void)
  30{
  31    return replay_is_debugging;
  32}
  33
  34void hmp_info_replay(Monitor *mon, const QDict *qdict)
  35{
  36    if (replay_mode == REPLAY_MODE_NONE) {
  37        monitor_printf(mon, "Record/replay is not active\n");
  38    } else {
  39        monitor_printf(mon,
  40            "%s execution '%s': instruction count = %"PRId64"\n",
  41            replay_mode == REPLAY_MODE_RECORD ? "Recording" : "Replaying",
  42            replay_get_filename(), replay_get_current_icount());
  43    }
  44}
  45
  46ReplayInfo *qmp_query_replay(Error **errp)
  47{
  48    ReplayInfo *retval = g_new0(ReplayInfo, 1);
  49
  50    retval->mode = replay_mode;
  51    if (replay_get_filename()) {
  52        retval->filename = g_strdup(replay_get_filename());
  53    }
  54    retval->icount = replay_get_current_icount();
  55    return retval;
  56}
  57
  58static void replay_break(uint64_t icount, QEMUTimerCB callback, void *opaque)
  59{
  60    assert(replay_mode == REPLAY_MODE_PLAY);
  61    assert(replay_mutex_locked());
  62    assert(replay_break_icount >= replay_get_current_icount());
  63    assert(callback);
  64
  65    replay_break_icount = icount;
  66
  67    if (replay_break_timer) {
  68        timer_del(replay_break_timer);
  69    }
  70    replay_break_timer = timer_new_ns(QEMU_CLOCK_REALTIME,
  71                                      callback, opaque);
  72}
  73
  74static void replay_delete_break(void)
  75{
  76    assert(replay_mode == REPLAY_MODE_PLAY);
  77    assert(replay_mutex_locked());
  78
  79    if (replay_break_timer) {
  80        timer_free(replay_break_timer);
  81        replay_break_timer = NULL;
  82    }
  83    replay_break_icount = -1ULL;
  84}
  85
  86static void replay_stop_vm(void *opaque)
  87{
  88    vm_stop(RUN_STATE_PAUSED);
  89    replay_delete_break();
  90}
  91
  92void qmp_replay_break(int64_t icount, Error **errp)
  93{
  94    if (replay_mode == REPLAY_MODE_PLAY) {
  95        if (icount >= replay_get_current_icount()) {
  96            replay_break(icount, replay_stop_vm, NULL);
  97        } else {
  98            error_setg(errp,
  99                "cannot set breakpoint at the instruction in the past");
 100        }
 101    } else {
 102        error_setg(errp, "setting the breakpoint is allowed only in play mode");
 103    }
 104}
 105
 106void hmp_replay_break(Monitor *mon, const QDict *qdict)
 107{
 108    int64_t icount = qdict_get_try_int(qdict, "icount", -1LL);
 109    Error *err = NULL;
 110
 111    qmp_replay_break(icount, &err);
 112    if (err) {
 113        error_report_err(err);
 114        return;
 115    }
 116}
 117
 118void qmp_replay_delete_break(Error **errp)
 119{
 120    if (replay_mode == REPLAY_MODE_PLAY) {
 121        replay_delete_break();
 122    } else {
 123        error_setg(errp, "replay breakpoints are allowed only in play mode");
 124    }
 125}
 126
 127void hmp_replay_delete_break(Monitor *mon, const QDict *qdict)
 128{
 129    Error *err = NULL;
 130
 131    qmp_replay_delete_break(&err);
 132    if (err) {
 133        error_report_err(err);
 134        return;
 135    }
 136}
 137
 138static char *replay_find_nearest_snapshot(int64_t icount,
 139                                          int64_t *snapshot_icount)
 140{
 141    BlockDriverState *bs;
 142    QEMUSnapshotInfo *sn_tab;
 143    QEMUSnapshotInfo *nearest = NULL;
 144    char *ret = NULL;
 145    int rv;
 146    int nb_sns, i;
 147    AioContext *aio_context;
 148
 149    *snapshot_icount = -1;
 150
 151    bs = bdrv_all_find_vmstate_bs(NULL, false, NULL, NULL);
 152    if (!bs) {
 153        goto fail;
 154    }
 155    aio_context = bdrv_get_aio_context(bs);
 156
 157    aio_context_acquire(aio_context);
 158    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
 159    aio_context_release(aio_context);
 160
 161    for (i = 0; i < nb_sns; i++) {
 162        rv = bdrv_all_has_snapshot(sn_tab[i].name, false, NULL, NULL);
 163        if (rv < 0)
 164            goto fail;
 165        if (rv == 1) {
 166            if (sn_tab[i].icount != -1ULL
 167                && sn_tab[i].icount <= icount
 168                && (!nearest || nearest->icount < sn_tab[i].icount)) {
 169                nearest = &sn_tab[i];
 170            }
 171        }
 172    }
 173    if (nearest) {
 174        ret = g_strdup(nearest->name);
 175        *snapshot_icount = nearest->icount;
 176    }
 177    g_free(sn_tab);
 178
 179fail:
 180    return ret;
 181}
 182
 183static void replay_seek(int64_t icount, QEMUTimerCB callback, Error **errp)
 184{
 185    char *snapshot = NULL;
 186    int64_t snapshot_icount;
 187
 188    if (replay_mode != REPLAY_MODE_PLAY) {
 189        error_setg(errp, "replay must be enabled to seek");
 190        return;
 191    }
 192
 193    snapshot = replay_find_nearest_snapshot(icount, &snapshot_icount);
 194    if (snapshot) {
 195        if (icount < replay_get_current_icount()
 196            || replay_get_current_icount() < snapshot_icount) {
 197            vm_stop(RUN_STATE_RESTORE_VM);
 198            load_snapshot(snapshot, NULL, false, NULL, errp);
 199        }
 200        g_free(snapshot);
 201    }
 202    if (replay_get_current_icount() <= icount) {
 203        replay_break(icount, callback, NULL);
 204        vm_start();
 205    } else {
 206        error_setg(errp, "cannot seek to the specified instruction count");
 207    }
 208}
 209
 210void qmp_replay_seek(int64_t icount, Error **errp)
 211{
 212    replay_seek(icount, replay_stop_vm, errp);
 213}
 214
 215void hmp_replay_seek(Monitor *mon, const QDict *qdict)
 216{
 217    int64_t icount = qdict_get_try_int(qdict, "icount", -1LL);
 218    Error *err = NULL;
 219
 220    qmp_replay_seek(icount, &err);
 221    if (err) {
 222        error_report_err(err);
 223        return;
 224    }
 225}
 226
 227static void replay_stop_vm_debug(void *opaque)
 228{
 229    replay_is_debugging = false;
 230    vm_stop(RUN_STATE_DEBUG);
 231    replay_delete_break();
 232}
 233
 234bool replay_reverse_step(void)
 235{
 236    Error *err = NULL;
 237
 238    assert(replay_mode == REPLAY_MODE_PLAY);
 239
 240    if (replay_get_current_icount() != 0) {
 241        replay_seek(replay_get_current_icount() - 1,
 242                    replay_stop_vm_debug, &err);
 243        if (err) {
 244            error_free(err);
 245            return false;
 246        }
 247        replay_is_debugging = true;
 248        return true;
 249    }
 250
 251    return false;
 252}
 253
 254static void replay_continue_end(void)
 255{
 256    replay_is_debugging = false;
 257    vm_stop(RUN_STATE_DEBUG);
 258    replay_delete_break();
 259}
 260
 261static void replay_continue_stop(void *opaque)
 262{
 263    Error *err = NULL;
 264    if (replay_last_breakpoint != -1LL) {
 265        replay_seek(replay_last_breakpoint, replay_stop_vm_debug, &err);
 266        if (err) {
 267            error_free(err);
 268            replay_continue_end();
 269        }
 270        return;
 271    }
 272    /*
 273     * No breakpoints since the last snapshot.
 274     * Find previous snapshot and try again.
 275     */
 276    if (replay_last_snapshot != 0) {
 277        replay_seek(replay_last_snapshot - 1, replay_continue_stop, &err);
 278        if (err) {
 279            error_free(err);
 280            replay_continue_end();
 281        }
 282        replay_last_snapshot = replay_get_current_icount();
 283    } else {
 284        /* Seek to the very first step */
 285        replay_seek(0, replay_stop_vm_debug, &err);
 286        if (err) {
 287            error_free(err);
 288            replay_continue_end();
 289        }
 290    }
 291}
 292
 293bool replay_reverse_continue(void)
 294{
 295    Error *err = NULL;
 296
 297    assert(replay_mode == REPLAY_MODE_PLAY);
 298
 299    if (replay_get_current_icount() != 0) {
 300        replay_seek(replay_get_current_icount() - 1,
 301                    replay_continue_stop, &err);
 302        if (err) {
 303            error_free(err);
 304            return false;
 305        }
 306        replay_last_breakpoint = -1LL;
 307        replay_is_debugging = true;
 308        replay_last_snapshot = replay_get_current_icount();
 309        return true;
 310    }
 311
 312    return false;
 313}
 314
 315void replay_breakpoint(void)
 316{
 317    assert(replay_mode == REPLAY_MODE_PLAY);
 318    replay_last_breakpoint = replay_get_current_icount();
 319}
 320
 321void replay_gdb_attached(void)
 322{
 323    /*
 324     * Create VM snapshot on temporary overlay to allow reverse
 325     * debugging even if snapshots were not enabled.
 326     */
 327    if (replay_mode == REPLAY_MODE_PLAY
 328        && !replay_snapshot) {
 329        if (!save_snapshot("start_debugging", true, NULL, false, NULL, NULL)) {
 330            /* Can't create the snapshot. Continue conventional debugging. */
 331        }
 332    }
 333}
 334