replay.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. * replay.c
  3. *
  4. * Copyright (c) 2010-2015 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. #include "qemu/osdep.h"
  12. #include "qemu-common.h"
  13. #include "sysemu/replay.h"
  14. #include "replay-internal.h"
  15. #include "qemu/timer.h"
  16. #include "qemu/main-loop.h"
  17. #include "sysemu/sysemu.h"
  18. #include "qemu/error-report.h"
  19. /* Current version of the replay mechanism.
  20. Increase it when file format changes. */
  21. #define REPLAY_VERSION 0xe02002
  22. /* Size of replay log header */
  23. #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
  24. ReplayMode replay_mode = REPLAY_MODE_NONE;
  25. /* Name of replay file */
  26. static char *replay_filename;
  27. ReplayState replay_state;
  28. static GSList *replay_blockers;
  29. bool replay_next_event_is(int event)
  30. {
  31. bool res = false;
  32. /* nothing to skip - not all instructions used */
  33. if (replay_state.instructions_count != 0) {
  34. assert(replay_data_kind == EVENT_INSTRUCTION);
  35. return event == EVENT_INSTRUCTION;
  36. }
  37. while (true) {
  38. if (event == replay_data_kind) {
  39. res = true;
  40. }
  41. switch (replay_data_kind) {
  42. case EVENT_SHUTDOWN:
  43. replay_finish_event();
  44. qemu_system_shutdown_request();
  45. break;
  46. default:
  47. /* clock, time_t, checkpoint and other events */
  48. return res;
  49. }
  50. }
  51. return res;
  52. }
  53. uint64_t replay_get_current_step(void)
  54. {
  55. return cpu_get_icount_raw();
  56. }
  57. int replay_get_instructions(void)
  58. {
  59. int res = 0;
  60. replay_mutex_lock();
  61. if (replay_next_event_is(EVENT_INSTRUCTION)) {
  62. res = replay_state.instructions_count;
  63. }
  64. replay_mutex_unlock();
  65. return res;
  66. }
  67. void replay_account_executed_instructions(void)
  68. {
  69. if (replay_mode == REPLAY_MODE_PLAY) {
  70. replay_mutex_lock();
  71. if (replay_state.instructions_count > 0) {
  72. int count = (int)(replay_get_current_step()
  73. - replay_state.current_step);
  74. replay_state.instructions_count -= count;
  75. replay_state.current_step += count;
  76. if (replay_state.instructions_count == 0) {
  77. assert(replay_data_kind == EVENT_INSTRUCTION);
  78. replay_finish_event();
  79. /* Wake up iothread. This is required because
  80. timers will not expire until clock counters
  81. will be read from the log. */
  82. qemu_notify_event();
  83. }
  84. }
  85. replay_mutex_unlock();
  86. }
  87. }
  88. bool replay_exception(void)
  89. {
  90. if (replay_mode == REPLAY_MODE_RECORD) {
  91. replay_save_instructions();
  92. replay_mutex_lock();
  93. replay_put_event(EVENT_EXCEPTION);
  94. replay_mutex_unlock();
  95. return true;
  96. } else if (replay_mode == REPLAY_MODE_PLAY) {
  97. bool res = replay_has_exception();
  98. if (res) {
  99. replay_mutex_lock();
  100. replay_finish_event();
  101. replay_mutex_unlock();
  102. }
  103. return res;
  104. }
  105. return true;
  106. }
  107. bool replay_has_exception(void)
  108. {
  109. bool res = false;
  110. if (replay_mode == REPLAY_MODE_PLAY) {
  111. replay_account_executed_instructions();
  112. replay_mutex_lock();
  113. res = replay_next_event_is(EVENT_EXCEPTION);
  114. replay_mutex_unlock();
  115. }
  116. return res;
  117. }
  118. bool replay_interrupt(void)
  119. {
  120. if (replay_mode == REPLAY_MODE_RECORD) {
  121. replay_save_instructions();
  122. replay_mutex_lock();
  123. replay_put_event(EVENT_INTERRUPT);
  124. replay_mutex_unlock();
  125. return true;
  126. } else if (replay_mode == REPLAY_MODE_PLAY) {
  127. bool res = replay_has_interrupt();
  128. if (res) {
  129. replay_mutex_lock();
  130. replay_finish_event();
  131. replay_mutex_unlock();
  132. }
  133. return res;
  134. }
  135. return true;
  136. }
  137. bool replay_has_interrupt(void)
  138. {
  139. bool res = false;
  140. if (replay_mode == REPLAY_MODE_PLAY) {
  141. replay_account_executed_instructions();
  142. replay_mutex_lock();
  143. res = replay_next_event_is(EVENT_INTERRUPT);
  144. replay_mutex_unlock();
  145. }
  146. return res;
  147. }
  148. void replay_shutdown_request(void)
  149. {
  150. if (replay_mode == REPLAY_MODE_RECORD) {
  151. replay_mutex_lock();
  152. replay_put_event(EVENT_SHUTDOWN);
  153. replay_mutex_unlock();
  154. }
  155. }
  156. bool replay_checkpoint(ReplayCheckpoint checkpoint)
  157. {
  158. bool res = false;
  159. assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
  160. replay_save_instructions();
  161. if (!replay_file) {
  162. return true;
  163. }
  164. replay_mutex_lock();
  165. if (replay_mode == REPLAY_MODE_PLAY) {
  166. if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
  167. replay_finish_event();
  168. } else if (replay_data_kind != EVENT_ASYNC) {
  169. res = false;
  170. goto out;
  171. }
  172. replay_read_events(checkpoint);
  173. /* replay_read_events may leave some unread events.
  174. Return false if not all of the events associated with
  175. checkpoint were processed */
  176. res = replay_data_kind != EVENT_ASYNC;
  177. } else if (replay_mode == REPLAY_MODE_RECORD) {
  178. replay_put_event(EVENT_CHECKPOINT + checkpoint);
  179. replay_save_events(checkpoint);
  180. res = true;
  181. }
  182. out:
  183. replay_mutex_unlock();
  184. return res;
  185. }
  186. static void replay_enable(const char *fname, int mode)
  187. {
  188. const char *fmode = NULL;
  189. assert(!replay_file);
  190. switch (mode) {
  191. case REPLAY_MODE_RECORD:
  192. fmode = "wb";
  193. break;
  194. case REPLAY_MODE_PLAY:
  195. fmode = "rb";
  196. break;
  197. default:
  198. fprintf(stderr, "Replay: internal error: invalid replay mode\n");
  199. exit(1);
  200. }
  201. atexit(replay_finish);
  202. replay_mutex_init();
  203. replay_file = fopen(fname, fmode);
  204. if (replay_file == NULL) {
  205. fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno));
  206. exit(1);
  207. }
  208. replay_filename = g_strdup(fname);
  209. replay_mode = mode;
  210. replay_data_kind = -1;
  211. replay_state.instructions_count = 0;
  212. replay_state.current_step = 0;
  213. /* skip file header for RECORD and check it for PLAY */
  214. if (replay_mode == REPLAY_MODE_RECORD) {
  215. fseek(replay_file, HEADER_SIZE, SEEK_SET);
  216. } else if (replay_mode == REPLAY_MODE_PLAY) {
  217. unsigned int version = replay_get_dword();
  218. if (version != REPLAY_VERSION) {
  219. fprintf(stderr, "Replay: invalid input log file version\n");
  220. exit(1);
  221. }
  222. /* go to the beginning */
  223. fseek(replay_file, HEADER_SIZE, SEEK_SET);
  224. replay_fetch_data_kind();
  225. }
  226. replay_init_events();
  227. }
  228. void replay_configure(QemuOpts *opts)
  229. {
  230. const char *fname;
  231. const char *rr;
  232. ReplayMode mode = REPLAY_MODE_NONE;
  233. rr = qemu_opt_get(opts, "rr");
  234. if (!rr) {
  235. /* Just enabling icount */
  236. return;
  237. } else if (!strcmp(rr, "record")) {
  238. mode = REPLAY_MODE_RECORD;
  239. } else if (!strcmp(rr, "replay")) {
  240. mode = REPLAY_MODE_PLAY;
  241. } else {
  242. error_report("Invalid icount rr option: %s", rr);
  243. exit(1);
  244. }
  245. fname = qemu_opt_get(opts, "rrfile");
  246. if (!fname) {
  247. error_report("File name not specified for replay");
  248. exit(1);
  249. }
  250. replay_enable(fname, mode);
  251. }
  252. void replay_start(void)
  253. {
  254. if (replay_mode == REPLAY_MODE_NONE) {
  255. return;
  256. }
  257. if (replay_blockers) {
  258. error_reportf_err(replay_blockers->data, "Record/replay: ");
  259. exit(1);
  260. }
  261. if (!use_icount) {
  262. error_report("Please enable icount to use record/replay");
  263. exit(1);
  264. }
  265. /* Timer for snapshotting will be set up here. */
  266. replay_enable_events();
  267. }
  268. void replay_finish(void)
  269. {
  270. if (replay_mode == REPLAY_MODE_NONE) {
  271. return;
  272. }
  273. replay_save_instructions();
  274. /* finalize the file */
  275. if (replay_file) {
  276. if (replay_mode == REPLAY_MODE_RECORD) {
  277. /* write end event */
  278. replay_put_event(EVENT_END);
  279. /* write header */
  280. fseek(replay_file, 0, SEEK_SET);
  281. replay_put_dword(REPLAY_VERSION);
  282. }
  283. fclose(replay_file);
  284. replay_file = NULL;
  285. }
  286. if (replay_filename) {
  287. g_free(replay_filename);
  288. replay_filename = NULL;
  289. }
  290. replay_finish_events();
  291. replay_mutex_destroy();
  292. }
  293. void replay_add_blocker(Error *reason)
  294. {
  295. replay_blockers = g_slist_prepend(replay_blockers, reason);
  296. }