2015-09-17 19:23:37 +03:00
/*
* replay . 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 .
*
*/
2016-01-29 20:50:05 +03:00
# include "qemu/osdep.h"
include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef. Since then, we've moved to include qemu/osdep.h
everywhere. Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h. That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h. Include qapi/error.h in .c files that need it and don't
get it now. Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly. Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h. Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third. Unfortunately, the number depending on
qapi-types.h shrinks only a little. More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-03-14 11:01:28 +03:00
# include "qapi/error.h"
2020-08-19 14:17:19 +03:00
# include "sysemu/cpu-timers.h"
2015-09-17 19:23:37 +03:00
# include "sysemu/replay.h"
2019-08-12 08:23:59 +03:00
# include "sysemu/runstate.h"
2015-09-17 19:23:54 +03:00
# include "replay-internal.h"
2015-09-17 19:24:05 +03:00
# include "qemu/main-loop.h"
2018-02-01 14:18:46 +03:00
# include "qemu/option.h"
2017-03-03 14:01:16 +03:00
# include "sysemu/cpus.h"
2015-09-17 19:25:07 +03:00
# include "qemu/error-report.h"
/* Current version of the replay mechanism.
Increase it when file format changes . */
2022-05-27 13:46:23 +03:00
# define REPLAY_VERSION 0xe0200c
2015-09-17 19:25:07 +03:00
/* Size of replay log header */
# define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
2015-09-17 19:23:37 +03:00
ReplayMode replay_mode = REPLAY_MODE_NONE ;
2017-01-24 10:17:47 +03:00
char * replay_snapshot ;
2015-09-17 19:23:54 +03:00
2015-09-17 19:25:07 +03:00
/* Name of replay file */
static char * replay_filename ;
2015-09-17 19:23:54 +03:00
ReplayState replay_state ;
2015-09-17 19:25:13 +03:00
static GSList * replay_blockers ;
2015-09-17 19:23:54 +03:00
2020-10-03 20:13:26 +03:00
/* Replay breakpoints */
uint64_t replay_break_icount = - 1ULL ;
QEMUTimer * replay_break_timer ;
2023-12-11 12:13:38 +03:00
/* Pretty print event names */
static const char * replay_async_event_name ( ReplayAsyncEventKind event )
{
switch ( event ) {
# define ASYNC_EVENT(_x) case REPLAY_ASYNC_EVENT_ ## _x: return "ASYNC_EVENT_"#_x
ASYNC_EVENT ( BH ) ;
ASYNC_EVENT ( BH_ONESHOT ) ;
ASYNC_EVENT ( INPUT ) ;
ASYNC_EVENT ( INPUT_SYNC ) ;
ASYNC_EVENT ( CHAR_READ ) ;
ASYNC_EVENT ( BLOCK ) ;
ASYNC_EVENT ( NET ) ;
# undef ASYNC_EVENT
default :
g_assert_not_reached ( ) ;
}
}
static const char * replay_clock_event_name ( ReplayClockKind clock )
{
switch ( clock ) {
# define CLOCK_EVENT(_x) case REPLAY_CLOCK_ ## _x: return "CLOCK_" #_x
CLOCK_EVENT ( HOST ) ;
CLOCK_EVENT ( VIRTUAL_RT ) ;
# undef CLOCK_EVENT
default :
g_assert_not_reached ( ) ;
}
}
/* Pretty print shutdown event names */
static const char * replay_shutdown_event_name ( ShutdownCause cause )
{
switch ( cause ) {
# define SHUTDOWN_EVENT(_x) case SHUTDOWN_CAUSE_ ## _x: return "SHUTDOWN_CAUSE_" #_x
SHUTDOWN_EVENT ( NONE ) ;
SHUTDOWN_EVENT ( HOST_ERROR ) ;
SHUTDOWN_EVENT ( HOST_QMP_QUIT ) ;
SHUTDOWN_EVENT ( HOST_QMP_SYSTEM_RESET ) ;
SHUTDOWN_EVENT ( HOST_SIGNAL ) ;
SHUTDOWN_EVENT ( HOST_UI ) ;
SHUTDOWN_EVENT ( GUEST_SHUTDOWN ) ;
SHUTDOWN_EVENT ( GUEST_RESET ) ;
SHUTDOWN_EVENT ( GUEST_PANIC ) ;
SHUTDOWN_EVENT ( SUBSYSTEM_RESET ) ;
SHUTDOWN_EVENT ( SNAPSHOT_LOAD ) ;
# undef SHUTDOWN_EVENT
default :
g_assert_not_reached ( ) ;
}
}
static const char * replay_checkpoint_event_name ( enum ReplayCheckpoint checkpoint )
{
switch ( checkpoint ) {
# define CHECKPOINT_EVENT(_x) case CHECKPOINT_ ## _x: return "CHECKPOINT_" #_x
CHECKPOINT_EVENT ( CLOCK_WARP_START ) ;
CHECKPOINT_EVENT ( CLOCK_WARP_ACCOUNT ) ;
CHECKPOINT_EVENT ( RESET_REQUESTED ) ;
CHECKPOINT_EVENT ( SUSPEND_REQUESTED ) ;
CHECKPOINT_EVENT ( CLOCK_VIRTUAL ) ;
CHECKPOINT_EVENT ( CLOCK_HOST ) ;
CHECKPOINT_EVENT ( CLOCK_VIRTUAL_RT ) ;
CHECKPOINT_EVENT ( INIT ) ;
CHECKPOINT_EVENT ( RESET ) ;
# undef CHECKPOINT_EVENT
default :
g_assert_not_reached ( ) ;
}
}
static const char * replay_event_name ( enum ReplayEvents event )
{
/* First deal with the simple ones */
switch ( event ) {
# define EVENT(_x) case EVENT_ ## _x: return "EVENT_"#_x
EVENT ( INSTRUCTION ) ;
EVENT ( INTERRUPT ) ;
EVENT ( EXCEPTION ) ;
EVENT ( CHAR_WRITE ) ;
EVENT ( CHAR_READ_ALL ) ;
EVENT ( AUDIO_OUT ) ;
EVENT ( AUDIO_IN ) ;
EVENT ( RANDOM ) ;
# undef EVENT
default :
if ( event > = EVENT_ASYNC & & event < = EVENT_ASYNC_LAST ) {
return replay_async_event_name ( event - EVENT_ASYNC ) ;
} else if ( event > = EVENT_SHUTDOWN & & event < = EVENT_SHUTDOWN_LAST ) {
return replay_shutdown_event_name ( event - EVENT_SHUTDOWN ) ;
} else if ( event > = EVENT_CLOCK & & event < = EVENT_CLOCK_LAST ) {
return replay_clock_event_name ( event - EVENT_CLOCK ) ;
} else if ( event > = EVENT_CHECKPOINT & & event < = EVENT_CHECKPOINT_LAST ) {
return replay_checkpoint_event_name ( event - EVENT_CHECKPOINT ) ;
}
}
g_assert_not_reached ( ) ;
}
2015-09-17 19:23:54 +03:00
bool replay_next_event_is ( int event )
{
bool res = false ;
/* nothing to skip - not all instructions used */
2019-07-25 11:44:43 +03:00
if ( replay_state . instruction_count ! = 0 ) {
2016-09-26 11:08:04 +03:00
assert ( replay_state . data_kind = = EVENT_INSTRUCTION ) ;
2015-09-17 19:23:54 +03:00
return event = = EVENT_INSTRUCTION ;
}
while ( true ) {
2019-07-25 11:44:32 +03:00
unsigned int data_kind = replay_state . data_kind ;
if ( event = = data_kind ) {
2015-09-17 19:23:54 +03:00
res = true ;
}
2019-07-25 11:44:32 +03:00
switch ( data_kind ) {
2017-05-16 00:41:12 +03:00
case EVENT_SHUTDOWN . . . EVENT_SHUTDOWN_LAST :
2015-09-17 19:24:33 +03:00
replay_finish_event ( ) ;
2019-07-25 11:44:32 +03:00
qemu_system_shutdown_request ( data_kind - EVENT_SHUTDOWN ) ;
2015-09-17 19:24:33 +03:00
break ;
2015-09-17 19:23:54 +03:00
default :
/* clock, time_t, checkpoint and other events */
return res ;
}
}
return res ;
}
2019-07-25 11:44:43 +03:00
uint64_t replay_get_current_icount ( void )
2015-09-17 19:23:54 +03:00
{
2020-08-31 17:18:34 +03:00
return icount_get_raw ( ) ;
2015-09-17 19:23:54 +03:00
}
2015-09-17 19:24:05 +03:00
int replay_get_instructions ( void )
{
int res = 0 ;
2023-04-27 05:09:25 +03:00
g_assert ( replay_mutex_locked ( ) ) ;
2015-09-17 19:24:05 +03:00
if ( replay_next_event_is ( EVENT_INSTRUCTION ) ) {
2019-07-25 11:44:43 +03:00
res = replay_state . instruction_count ;
2020-10-03 20:13:26 +03:00
if ( replay_break_icount ! = - 1LL ) {
uint64_t current = replay_get_current_icount ( ) ;
assert ( replay_break_icount > = current ) ;
if ( current + res > replay_break_icount ) {
res = replay_break_icount - current ;
}
}
2015-09-17 19:24:05 +03:00
}
return res ;
}
void replay_account_executed_instructions ( void )
{
if ( replay_mode = = REPLAY_MODE_PLAY ) {
2018-02-27 12:52:48 +03:00
g_assert ( replay_mutex_locked ( ) ) ;
2019-07-25 11:44:43 +03:00
if ( replay_state . instruction_count > 0 ) {
2021-02-16 15:51:44 +03:00
replay_advance_current_icount ( replay_get_current_icount ( ) ) ;
2015-09-17 19:24:05 +03:00
}
}
}
2015-09-17 19:24:16 +03:00
bool replay_exception ( void )
{
2018-02-27 12:52:48 +03:00
2015-09-17 19:24:16 +03:00
if ( replay_mode = = REPLAY_MODE_RECORD ) {
2018-02-27 12:52:48 +03:00
g_assert ( replay_mutex_locked ( ) ) ;
2015-09-17 19:24:16 +03:00
replay_save_instructions ( ) ;
replay_put_event ( EVENT_EXCEPTION ) ;
return true ;
} else if ( replay_mode = = REPLAY_MODE_PLAY ) {
2018-02-27 12:52:48 +03:00
g_assert ( replay_mutex_locked ( ) ) ;
2015-09-17 19:24:16 +03:00
bool res = replay_has_exception ( ) ;
if ( res ) {
replay_finish_event ( ) ;
}
return res ;
}
return true ;
}
bool replay_has_exception ( void )
{
bool res = false ;
if ( replay_mode = = REPLAY_MODE_PLAY ) {
2018-02-27 12:52:48 +03:00
g_assert ( replay_mutex_locked ( ) ) ;
2015-09-17 19:24:16 +03:00
replay_account_executed_instructions ( ) ;
res = replay_next_event_is ( EVENT_EXCEPTION ) ;
}
return res ;
}
bool replay_interrupt ( void )
{
if ( replay_mode = = REPLAY_MODE_RECORD ) {
2018-02-27 12:52:48 +03:00
g_assert ( replay_mutex_locked ( ) ) ;
2015-09-17 19:24:16 +03:00
replay_save_instructions ( ) ;
replay_put_event ( EVENT_INTERRUPT ) ;
return true ;
} else if ( replay_mode = = REPLAY_MODE_PLAY ) {
2018-02-27 12:52:48 +03:00
g_assert ( replay_mutex_locked ( ) ) ;
2015-09-17 19:24:16 +03:00
bool res = replay_has_interrupt ( ) ;
if ( res ) {
replay_finish_event ( ) ;
}
return res ;
}
return true ;
}
bool replay_has_interrupt ( void )
{
bool res = false ;
if ( replay_mode = = REPLAY_MODE_PLAY ) {
2018-02-27 12:52:48 +03:00
g_assert ( replay_mutex_locked ( ) ) ;
2015-09-17 19:24:16 +03:00
replay_account_executed_instructions ( ) ;
res = replay_next_event_is ( EVENT_INTERRUPT ) ;
}
return res ;
}
2015-09-17 19:24:33 +03:00
2017-05-16 00:41:12 +03:00
void replay_shutdown_request ( ShutdownCause cause )
2015-09-17 19:24:33 +03:00
{
if ( replay_mode = = REPLAY_MODE_RECORD ) {
2018-02-27 12:52:48 +03:00
g_assert ( replay_mutex_locked ( ) ) ;
2017-05-16 00:41:12 +03:00
replay_put_event ( EVENT_SHUTDOWN + cause ) ;
2015-09-17 19:24:33 +03:00
}
}
2015-09-17 19:24:44 +03:00
bool replay_checkpoint ( ReplayCheckpoint checkpoint )
{
assert ( EVENT_CHECKPOINT + checkpoint < = EVENT_CHECKPOINT_LAST ) ;
2018-02-27 12:53:05 +03:00
replay_save_instructions ( ) ;
2015-09-17 19:24:44 +03:00
if ( replay_mode = = REPLAY_MODE_PLAY ) {
2018-02-27 12:52:48 +03:00
g_assert ( replay_mutex_locked ( ) ) ;
2015-09-17 19:24:44 +03:00
if ( replay_next_event_is ( EVENT_CHECKPOINT + checkpoint ) ) {
replay_finish_event ( ) ;
2022-05-27 13:46:18 +03:00
} else {
return false ;
2015-09-17 19:24:44 +03:00
}
} else if ( replay_mode = = REPLAY_MODE_RECORD ) {
2018-02-27 12:52:48 +03:00
g_assert ( replay_mutex_locked ( ) ) ;
2015-09-17 19:24:44 +03:00
replay_put_event ( EVENT_CHECKPOINT + checkpoint ) ;
}
2022-05-27 13:46:18 +03:00
return true ;
}
void replay_async_events ( void )
{
static bool processing = false ;
/*
* If we are already processing the events , recursion may occur
* in case of incorrect implementation when HW event modifies timers .
* Timer modification may invoke the icount warp , event processing ,
* and cause the recursion .
*/
g_assert ( ! processing ) ;
processing = true ;
replay_save_instructions ( ) ;
if ( replay_mode = = REPLAY_MODE_PLAY ) {
g_assert ( replay_mutex_locked ( ) ) ;
replay_read_events ( ) ;
} else if ( replay_mode = = REPLAY_MODE_RECORD ) {
g_assert ( replay_mutex_locked ( ) ) ;
replay_save_events ( ) ;
}
processing = false ;
2015-09-17 19:24:44 +03:00
}
2015-09-17 19:25:07 +03:00
2022-05-27 13:46:18 +03:00
bool replay_has_event ( void )
2018-09-12 11:19:45 +03:00
{
bool res = false ;
if ( replay_mode = = REPLAY_MODE_PLAY ) {
g_assert ( replay_mutex_locked ( ) ) ;
replay_account_executed_instructions ( ) ;
res = EVENT_CHECKPOINT < = replay_state . data_kind
& & replay_state . data_kind < = EVENT_CHECKPOINT_LAST ;
2022-05-27 13:46:23 +03:00
res = res | | ( EVENT_ASYNC < = replay_state . data_kind
& & replay_state . data_kind < = EVENT_ASYNC_LAST ) ;
2018-09-12 11:19:45 +03:00
}
return res ;
}
2023-12-11 12:13:38 +03:00
G_NORETURN void replay_sync_error ( const char * error )
{
error_report ( " %s (insn total % " PRId64 " /%d left, event %d is %s) " , error ,
replay_state . current_icount , replay_state . instruction_count ,
replay_state . current_event ,
replay_event_name ( replay_state . data_kind ) ) ;
abort ( ) ;
}
2015-09-17 19:25:07 +03:00
static void replay_enable ( const char * fname , int mode )
{
const char * fmode = NULL ;
assert ( ! replay_file ) ;
switch ( mode ) {
case REPLAY_MODE_RECORD :
fmode = " wb " ;
break ;
case REPLAY_MODE_PLAY :
fmode = " rb " ;
break ;
default :
fprintf ( stderr , " Replay: internal error: invalid replay mode \n " ) ;
exit ( 1 ) ;
}
atexit ( replay_finish ) ;
replay_file = fopen ( fname , fmode ) ;
if ( replay_file = = NULL ) {
fprintf ( stderr , " Replay: open %s: %s \n " , fname , strerror ( errno ) ) ;
exit ( 1 ) ;
}
replay_filename = g_strdup ( fname ) ;
replay_mode = mode ;
2018-02-27 12:52:48 +03:00
replay_mutex_init ( ) ;
2016-09-26 11:08:04 +03:00
replay_state . data_kind = - 1 ;
2019-07-25 11:44:43 +03:00
replay_state . instruction_count = 0 ;
replay_state . current_icount = 0 ;
2023-12-11 12:13:38 +03:00
replay_state . current_event = 0 ;
2016-09-26 11:08:04 +03:00
replay_state . has_unread_data = 0 ;
2015-09-17 19:25:07 +03:00
/* skip file header for RECORD and check it for PLAY */
if ( replay_mode = = REPLAY_MODE_RECORD ) {
fseek ( replay_file , HEADER_SIZE , SEEK_SET ) ;
} else if ( replay_mode = = REPLAY_MODE_PLAY ) {
unsigned int version = replay_get_dword ( ) ;
if ( version ! = REPLAY_VERSION ) {
fprintf ( stderr , " Replay: invalid input log file version \n " ) ;
exit ( 1 ) ;
}
/* go to the beginning */
fseek ( replay_file , HEADER_SIZE , SEEK_SET ) ;
replay_fetch_data_kind ( ) ;
}
2024-08-13 23:23:20 +03:00
runstate_replay_enable ( ) ;
2015-09-17 19:25:07 +03:00
replay_init_events ( ) ;
}
void replay_configure ( QemuOpts * opts )
{
const char * fname ;
const char * rr ;
ReplayMode mode = REPLAY_MODE_NONE ;
2016-02-12 22:02:26 +03:00
Location loc ;
if ( ! opts ) {
return ;
}
loc_push_none ( & loc ) ;
qemu_opts_loc_restore ( opts ) ;
2015-09-17 19:25:07 +03:00
rr = qemu_opt_get ( opts , " rr " ) ;
if ( ! rr ) {
/* Just enabling icount */
2016-04-27 17:29:08 +03:00
goto out ;
2015-09-17 19:25:07 +03:00
} else if ( ! strcmp ( rr , " record " ) ) {
mode = REPLAY_MODE_RECORD ;
} else if ( ! strcmp ( rr , " replay " ) ) {
mode = REPLAY_MODE_PLAY ;
} else {
error_report ( " Invalid icount rr option: %s " , rr ) ;
exit ( 1 ) ;
}
fname = qemu_opt_get ( opts , " rrfile " ) ;
if ( ! fname ) {
error_report ( " File name not specified for replay " ) ;
exit ( 1 ) ;
}
2017-01-24 10:17:47 +03:00
replay_snapshot = g_strdup ( qemu_opt_get ( opts , " rrsnapshot " ) ) ;
2016-09-26 11:08:10 +03:00
replay_vmstate_register ( ) ;
2015-09-17 19:25:07 +03:00
replay_enable ( fname , mode ) ;
2016-02-12 22:02:26 +03:00
2016-04-27 17:29:08 +03:00
out :
2016-02-12 22:02:26 +03:00
loc_pop ( & loc ) ;
2015-09-17 19:25:07 +03:00
}
void replay_start ( void )
{
if ( replay_mode = = REPLAY_MODE_NONE ) {
return ;
}
2015-09-17 19:25:13 +03:00
if ( replay_blockers ) {
2015-12-18 18:35:14 +03:00
error_reportf_err ( replay_blockers - > data , " Record/replay: " ) ;
2015-09-17 19:25:13 +03:00
exit ( 1 ) ;
}
2020-08-19 14:17:19 +03:00
if ( ! icount_enabled ( ) ) {
2015-09-17 19:25:18 +03:00
error_report ( " Please enable icount to use record/replay " ) ;
exit ( 1 ) ;
}
2015-09-17 19:25:13 +03:00
2015-09-17 19:25:07 +03:00
/* Timer for snapshotting will be set up here. */
replay_enable_events ( ) ;
}
void replay_finish ( void )
{
if ( replay_mode = = REPLAY_MODE_NONE ) {
return ;
}
replay_save_instructions ( ) ;
/* finalize the file */
if ( replay_file ) {
if ( replay_mode = = REPLAY_MODE_RECORD ) {
2020-05-22 09:45:54 +03:00
/*
* Can ' t do it in the signal handler , therefore
* add shutdown event here for the case of Ctrl - C .
*/
replay_shutdown_request ( SHUTDOWN_CAUSE_HOST_SIGNAL ) ;
2015-09-17 19:25:07 +03:00
/* write end event */
replay_put_event ( EVENT_END ) ;
/* write header */
fseek ( replay_file , 0 , SEEK_SET ) ;
replay_put_dword ( REPLAY_VERSION ) ;
}
fclose ( replay_file ) ;
replay_file = NULL ;
}
2022-09-23 12:04:28 +03:00
g_free ( replay_filename ) ;
replay_filename = NULL ;
2015-09-17 19:25:07 +03:00
2017-01-24 10:17:47 +03:00
g_free ( replay_snapshot ) ;
replay_snapshot = NULL ;
2015-09-17 19:25:07 +03:00
replay_finish_events ( ) ;
2022-05-27 13:46:07 +03:00
replay_mode = REPLAY_MODE_NONE ;
2015-09-17 19:25:07 +03:00
}
2015-09-17 19:25:13 +03:00
2023-02-07 10:51:12 +03:00
void replay_add_blocker ( const char * feature )
2015-09-17 19:25:13 +03:00
{
2023-02-07 10:51:12 +03:00
Error * reason = NULL ;
2024-03-01 15:06:41 +03:00
error_setg ( & reason , " Record/replay is not supported with %s " ,
2023-02-07 10:51:12 +03:00
feature ) ;
2015-09-17 19:25:13 +03:00
replay_blockers = g_slist_prepend ( replay_blockers , reason ) ;
}
2020-10-03 20:12:57 +03:00
const char * replay_get_filename ( void )
{
return replay_filename ;
}