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 23 void hmp_info_replay(Monitor *mon, const QDict *qdict) 24 { 25 if (replay_mode == REPLAY_MODE_NONE) { 26 monitor_printf(mon, "Record/replay is not active\n"); 27 } else { 28 monitor_printf(mon, 29 "%s execution '%s': instruction count = %"PRId64"\n", 30 replay_mode == REPLAY_MODE_RECORD ? "Recording" : "Replaying", 31 replay_get_filename(), replay_get_current_icount()); 32 } 33 } 34 35 ReplayInfo *qmp_query_replay(Error **errp) 36 { 37 ReplayInfo *retval = g_new0(ReplayInfo, 1); 38 39 retval->mode = replay_mode; 40 if (replay_get_filename()) { 41 retval->filename = g_strdup(replay_get_filename()); 42 retval->has_filename = true; 43 } 44 retval->icount = replay_get_current_icount(); 45 return retval; 46 } 47 48 static void replay_break(uint64_t icount, QEMUTimerCB callback, void *opaque) 49 { 50 assert(replay_mode == REPLAY_MODE_PLAY); 51 assert(replay_mutex_locked()); 52 assert(replay_break_icount >= replay_get_current_icount()); 53 assert(callback); 54 55 replay_break_icount = icount; 56 57 if (replay_break_timer) { 58 timer_del(replay_break_timer); 59 } 60 replay_break_timer = timer_new_ns(QEMU_CLOCK_REALTIME, 61 callback, opaque); 62 } 63 64 static void replay_delete_break(void) 65 { 66 assert(replay_mode == REPLAY_MODE_PLAY); 67 assert(replay_mutex_locked()); 68 69 if (replay_break_timer) { 70 timer_del(replay_break_timer); 71 timer_free(replay_break_timer); 72 replay_break_timer = NULL; 73 } 74 replay_break_icount = -1ULL; 75 } 76 77 static void replay_stop_vm(void *opaque) 78 { 79 vm_stop(RUN_STATE_PAUSED); 80 replay_delete_break(); 81 } 82 83 void qmp_replay_break(int64_t icount, Error **errp) 84 { 85 if (replay_mode == REPLAY_MODE_PLAY) { 86 if (icount >= replay_get_current_icount()) { 87 replay_break(icount, replay_stop_vm, NULL); 88 } else { 89 error_setg(errp, 90 "cannot set breakpoint at the instruction in the past"); 91 } 92 } else { 93 error_setg(errp, "setting the breakpoint is allowed only in play mode"); 94 } 95 } 96 97 void hmp_replay_break(Monitor *mon, const QDict *qdict) 98 { 99 int64_t icount = qdict_get_try_int(qdict, "icount", -1LL); 100 Error *err = NULL; 101 102 qmp_replay_break(icount, &err); 103 if (err) { 104 error_report_err(err); 105 return; 106 } 107 } 108 109 void qmp_replay_delete_break(Error **errp) 110 { 111 if (replay_mode == REPLAY_MODE_PLAY) { 112 replay_delete_break(); 113 } else { 114 error_setg(errp, "replay breakpoints are allowed only in play mode"); 115 } 116 } 117 118 void hmp_replay_delete_break(Monitor *mon, const QDict *qdict) 119 { 120 Error *err = NULL; 121 122 qmp_replay_delete_break(&err); 123 if (err) { 124 error_report_err(err); 125 return; 126 } 127 } 128