cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

replay-debugging.c (8491B)


      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}