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        retval->has_filename = true;
  54    }
  55    retval->icount = replay_get_current_icount();
  56    return retval;
  57}
  58
  59static void replay_break(uint64_t icount, QEMUTimerCB callback, void *opaque)
  60{
  61    assert(replay_mode == REPLAY_MODE_PLAY);
  62    assert(replay_mutex_locked());
  63    assert(replay_break_icount >= replay_get_current_icount());
  64    assert(callback);
  65
  66    replay_break_icount = icount;
  67
  68    if (replay_break_timer) {
  69        timer_del(replay_break_timer);
  70    }
  71    replay_break_timer = timer_new_ns(QEMU_CLOCK_REALTIME,
  72                                      callback, opaque);
  73}
  74
  75static void replay_delete_break(void)
  76{
  77    assert(replay_mode == REPLAY_MODE_PLAY);
  78    assert(replay_mutex_locked());
  79
  80    if (replay_break_timer) {
  81        timer_free(replay_break_timer);
  82        replay_break_timer = NULL;
  83    }
  84    replay_break_icount = -1ULL;
  85}
  86
  87static void replay_stop_vm(void *opaque)
  88{
  89    vm_stop(RUN_STATE_PAUSED);
  90    replay_delete_break();
  91}
  92
  93void qmp_replay_break(int64_t icount, Error **errp)
  94{
  95    if (replay_mode == REPLAY_MODE_PLAY) {
  96        if (icount >= replay_get_current_icount()) {
  97            replay_break(icount, replay_stop_vm, NULL);
  98        } else {
  99            error_setg(errp,
 100                "cannot set breakpoint at the instruction in the past");
 101        }
 102    } else {
 103        error_setg(errp, "setting the breakpoint is allowed only in play mode");
 104    }
 105}
 106
 107void hmp_replay_break(Monitor *mon, const QDict *qdict)
 108{
 109    int64_t icount = qdict_get_try_int(qdict, "icount", -1LL);
 110    Error *err = NULL;
 111
 112    qmp_replay_break(icount, &err);
 113    if (err) {
 114        error_report_err(err);
 115        return;
 116    }
 117}
 118
 119void qmp_replay_delete_break(Error **errp)
 120{
 121    if (replay_mode == REPLAY_MODE_PLAY) {
 122        replay_delete_break();
 123    } else {
 124        error_setg(errp, "replay breakpoints are allowed only in play mode");
 125    }
 126}
 127
 128void hmp_replay_delete_break(Monitor *mon, const QDict *qdict)
 129{
 130    Error *err = NULL;
 131
 132    qmp_replay_delete_break(&err);
 133    if (err) {
 134        error_report_err(err);
 135        return;
 136    }
 137}
 138
 139static char *replay_find_nearest_snapshot(int64_t icount,
 140                                          int64_t *snapshot_icount)
 141{
 142    BlockDriverState *bs;
 143    QEMUSnapshotInfo *sn_tab;
 144    QEMUSnapshotInfo *nearest = NULL;
 145    char *ret = NULL;
 146    int rv;
 147    int nb_sns, i;
 148    AioContext *aio_context;
 149
 150    *snapshot_icount = -1;
 151
 152    bs = bdrv_all_find_vmstate_bs(NULL, false, NULL, NULL);
 153    if (!bs) {
 154        goto fail;
 155    }
 156    aio_context = bdrv_get_aio_context(bs);
 157
 158    aio_context_acquire(aio_context);
 159    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
 160    aio_context_release(aio_context);
 161
 162    for (i = 0; i < nb_sns; i++) {
 163        rv = bdrv_all_has_snapshot(sn_tab[i].name, false, NULL, NULL);
 164        if (rv < 0)
 165            goto fail;
 166        if (rv == 1) {
 167            if (sn_tab[i].icount != -1ULL
 168                && sn_tab[i].icount <= icount
 169                && (!nearest || nearest->icount < sn_tab[i].icount)) {
 170                nearest = &sn_tab[i];
 171            }
 172        }
 173    }
 174    if (nearest) {
 175        ret = g_strdup(nearest->name);
 176        *snapshot_icount = nearest->icount;
 177    }
 178    g_free(sn_tab);
 179
 180fail:
 181    return ret;
 182}
 183
 184static void replay_seek(int64_t icount, QEMUTimerCB callback, Error **errp)
 185{
 186    char *snapshot = NULL;
 187    int64_t snapshot_icount;
 188
 189    if (replay_mode != REPLAY_MODE_PLAY) {
 190        error_setg(errp, "replay must be enabled to seek");
 191        return;
 192    }
 193
 194    snapshot = replay_find_nearest_snapshot(icount, &snapshot_icount);
 195    if (snapshot) {
 196        if (icount < replay_get_current_icount()
 197            || replay_get_current_icount() < snapshot_icount) {
 198            vm_stop(RUN_STATE_RESTORE_VM);
 199            load_snapshot(snapshot, NULL, false, NULL, errp);
 200        }
 201        g_free(snapshot);
 202    }
 203    if (replay_get_current_icount() <= icount) {
 204        replay_break(icount, callback, NULL);
 205        vm_start();
 206    } else {
 207        error_setg(errp, "cannot seek to the specified instruction count");
 208    }
 209}
 210
 211void qmp_replay_seek(int64_t icount, Error **errp)
 212{
 213    replay_seek(icount, replay_stop_vm, errp);
 214}
 215
 216void hmp_replay_seek(Monitor *mon, const QDict *qdict)
 217{
 218    int64_t icount = qdict_get_try_int(qdict, "icount", -1LL);
 219    Error *err = NULL;
 220
 221    qmp_replay_seek(icount, &err);
 222    if (err) {
 223        error_report_err(err);
 224        return;
 225    }
 226}
 227
 228static void replay_stop_vm_debug(void *opaque)
 229{
 230    replay_is_debugging = false;
 231    vm_stop(RUN_STATE_DEBUG);
 232    replay_delete_break();
 233}
 234
 235bool replay_reverse_step(void)
 236{
 237    Error *err = NULL;
 238
 239    assert(replay_mode == REPLAY_MODE_PLAY);
 240
 241    if (replay_get_current_icount() != 0) {
 242        replay_seek(replay_get_current_icount() - 1,
 243                    replay_stop_vm_debug, &err);
 244        if (err) {
 245            error_free(err);
 246            return false;
 247        }
 248        replay_is_debugging = true;
 249        return true;
 250    }
 251
 252    return false;
 253}
 254
 255static void replay_continue_end(void)
 256{
 257    replay_is_debugging = false;
 258    vm_stop(RUN_STATE_DEBUG);
 259    replay_delete_break();
 260}
 261
 262static void replay_continue_stop(void *opaque)
 263{
 264    Error *err = NULL;
 265    if (replay_last_breakpoint != -1LL) {
 266        replay_seek(replay_last_breakpoint, replay_stop_vm_debug, &err);
 267        if (err) {
 268            error_free(err);
 269            replay_continue_end();
 270        }
 271        return;
 272    }
 273    /*
 274     * No breakpoints since the last snapshot.
 275     * Find previous snapshot and try again.
 276     */
 277    if (replay_last_snapshot != 0) {
 278        replay_seek(replay_last_snapshot - 1, replay_continue_stop, &err);
 279        if (err) {
 280            error_free(err);
 281            replay_continue_end();
 282        }
 283        replay_last_snapshot = replay_get_current_icount();
 284    } else {
 285        /* Seek to the very first step */
 286        replay_seek(0, replay_stop_vm_debug, &err);
 287        if (err) {
 288            error_free(err);
 289            replay_continue_end();
 290        }
 291    }
 292}
 293
 294bool replay_reverse_continue(void)
 295{
 296    Error *err = NULL;
 297
 298    assert(replay_mode == REPLAY_MODE_PLAY);
 299
 300    if (replay_get_current_icount() != 0) {
 301        replay_seek(replay_get_current_icount() - 1,
 302                    replay_continue_stop, &err);
 303        if (err) {
 304            error_free(err);
 305            return false;
 306        }
 307        replay_last_breakpoint = -1LL;
 308        replay_is_debugging = true;
 309        replay_last_snapshot = replay_get_current_icount();
 310        return true;
 311    }
 312
 313    return false;
 314}
 315
 316void replay_breakpoint(void)
 317{
 318    assert(replay_mode == REPLAY_MODE_PLAY);
 319    replay_last_breakpoint = replay_get_current_icount();
 320}
 321
 322void replay_gdb_attached(void)
 323{
 324    /*
 325     * Create VM snapshot on temporary overlay to allow reverse
 326     * debugging even if snapshots were not enabled.
 327     */
 328    if (replay_mode == REPLAY_MODE_PLAY
 329        && !replay_snapshot) {
 330        if (!save_snapshot("start_debugging", true, NULL, false, NULL, NULL)) {
 331            /* Can't create the snapshot. Continue conventional debugging. */
 332        }
 333    }
 334}
 335