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}