 982263ce71
			
		
	
	
		982263ce71
		
	
	
	
	
		
			
			If we find ourselves trying to add an event to the log where time has gone backwards it is because a vCPU event has occurred and the main-loop is not yet aware of time moving forward. This should not happen and if it does its better to fail early than generate a log that will have weird behaviour. Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
		
			
				
	
	
		
			210 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			210 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * replay-internal.c
 | |
|  *
 | |
|  * Copyright (c) 2010-2015 Institute for System Programming
 | |
|  *                         of the Russian Academy of Sciences.
 | |
|  *
 | |
|  * This work is licensed under the terms of the GNU GPL, version 2 or later.
 | |
|  * See the COPYING file in the top-level directory.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include "qemu/osdep.h"
 | |
| #include "qemu-common.h"
 | |
| #include "sysemu/replay.h"
 | |
| #include "replay-internal.h"
 | |
| #include "qemu/error-report.h"
 | |
| #include "sysemu/sysemu.h"
 | |
| 
 | |
| /* Mutex to protect reading and writing events to the log.
 | |
|    data_kind and has_unread_data are also protected
 | |
|    by this mutex.
 | |
|    It also protects replay events queue which stores events to be
 | |
|    written or read to the log. */
 | |
| static QemuMutex lock;
 | |
| 
 | |
| /* File for replay writing */
 | |
| FILE *replay_file;
 | |
| 
 | |
| void replay_put_byte(uint8_t byte)
 | |
| {
 | |
|     if (replay_file) {
 | |
|         putc(byte, replay_file);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void replay_put_event(uint8_t event)
 | |
| {
 | |
|     assert(event < EVENT_COUNT);
 | |
|     replay_put_byte(event);
 | |
| }
 | |
| 
 | |
| 
 | |
| void replay_put_word(uint16_t word)
 | |
| {
 | |
|     replay_put_byte(word >> 8);
 | |
|     replay_put_byte(word);
 | |
| }
 | |
| 
 | |
| void replay_put_dword(uint32_t dword)
 | |
| {
 | |
|     replay_put_word(dword >> 16);
 | |
|     replay_put_word(dword);
 | |
| }
 | |
| 
 | |
| void replay_put_qword(int64_t qword)
 | |
| {
 | |
|     replay_put_dword(qword >> 32);
 | |
|     replay_put_dword(qword);
 | |
| }
 | |
| 
 | |
| void replay_put_array(const uint8_t *buf, size_t size)
 | |
| {
 | |
|     if (replay_file) {
 | |
|         replay_put_dword(size);
 | |
|         fwrite(buf, 1, size, replay_file);
 | |
|     }
 | |
| }
 | |
| 
 | |
| uint8_t replay_get_byte(void)
 | |
| {
 | |
|     uint8_t byte = 0;
 | |
|     if (replay_file) {
 | |
|         byte = getc(replay_file);
 | |
|     }
 | |
|     return byte;
 | |
| }
 | |
| 
 | |
| uint16_t replay_get_word(void)
 | |
| {
 | |
|     uint16_t word = 0;
 | |
|     if (replay_file) {
 | |
|         word = replay_get_byte();
 | |
|         word = (word << 8) + replay_get_byte();
 | |
|     }
 | |
| 
 | |
|     return word;
 | |
| }
 | |
| 
 | |
| uint32_t replay_get_dword(void)
 | |
| {
 | |
|     uint32_t dword = 0;
 | |
|     if (replay_file) {
 | |
|         dword = replay_get_word();
 | |
|         dword = (dword << 16) + replay_get_word();
 | |
|     }
 | |
| 
 | |
|     return dword;
 | |
| }
 | |
| 
 | |
| int64_t replay_get_qword(void)
 | |
| {
 | |
|     int64_t qword = 0;
 | |
|     if (replay_file) {
 | |
|         qword = replay_get_dword();
 | |
|         qword = (qword << 32) + replay_get_dword();
 | |
|     }
 | |
| 
 | |
|     return qword;
 | |
| }
 | |
| 
 | |
| void replay_get_array(uint8_t *buf, size_t *size)
 | |
| {
 | |
|     if (replay_file) {
 | |
|         *size = replay_get_dword();
 | |
|         if (fread(buf, 1, *size, replay_file) != *size) {
 | |
|             error_report("replay read error");
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void replay_get_array_alloc(uint8_t **buf, size_t *size)
 | |
| {
 | |
|     if (replay_file) {
 | |
|         *size = replay_get_dword();
 | |
|         *buf = g_malloc(*size);
 | |
|         if (fread(*buf, 1, *size, replay_file) != *size) {
 | |
|             error_report("replay read error");
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void replay_check_error(void)
 | |
| {
 | |
|     if (replay_file) {
 | |
|         if (feof(replay_file)) {
 | |
|             error_report("replay file is over");
 | |
|             qemu_system_vmstop_request_prepare();
 | |
|             qemu_system_vmstop_request(RUN_STATE_PAUSED);
 | |
|         } else if (ferror(replay_file)) {
 | |
|             error_report("replay file is over or something goes wrong");
 | |
|             qemu_system_vmstop_request_prepare();
 | |
|             qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void replay_fetch_data_kind(void)
 | |
| {
 | |
|     if (replay_file) {
 | |
|         if (!replay_state.has_unread_data) {
 | |
|             replay_state.data_kind = replay_get_byte();
 | |
|             if (replay_state.data_kind == EVENT_INSTRUCTION) {
 | |
|                 replay_state.instructions_count = replay_get_dword();
 | |
|             }
 | |
|             replay_check_error();
 | |
|             replay_state.has_unread_data = 1;
 | |
|             if (replay_state.data_kind >= EVENT_COUNT) {
 | |
|                 error_report("Replay: unknown event kind %d",
 | |
|                              replay_state.data_kind);
 | |
|                 exit(1);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void replay_finish_event(void)
 | |
| {
 | |
|     replay_state.has_unread_data = 0;
 | |
|     replay_fetch_data_kind();
 | |
| }
 | |
| 
 | |
| void replay_mutex_init(void)
 | |
| {
 | |
|     qemu_mutex_init(&lock);
 | |
| }
 | |
| 
 | |
| void replay_mutex_destroy(void)
 | |
| {
 | |
|     qemu_mutex_destroy(&lock);
 | |
| }
 | |
| 
 | |
| void replay_mutex_lock(void)
 | |
| {
 | |
|     qemu_mutex_lock(&lock);
 | |
| }
 | |
| 
 | |
| void replay_mutex_unlock(void)
 | |
| {
 | |
|     qemu_mutex_unlock(&lock);
 | |
| }
 | |
| 
 | |
| /*! Saves cached instructions. */
 | |
| void replay_save_instructions(void)
 | |
| {
 | |
|     if (replay_file && replay_mode == REPLAY_MODE_RECORD) {
 | |
|         replay_mutex_lock();
 | |
|         int diff = (int)(replay_get_current_step() - replay_state.current_step);
 | |
| 
 | |
|         /* Time can only go forward */
 | |
|         assert(diff >= 0);
 | |
| 
 | |
|         if (diff > 0) {
 | |
|             replay_put_event(EVENT_INSTRUCTION);
 | |
|             replay_put_dword(diff);
 | |
|             replay_state.current_step += diff;
 | |
|         }
 | |
|         replay_mutex_unlock();
 | |
|     }
 | |
| }
 |