1 /* 2 * replay-char.c 3 * 4 * Copyright (c) 2010-2016 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 <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 16 #include "qemu/osdep.h" 17 #include "qemu/error-report.h" 18 #include "sysemu/replay.h" 19 #include "replay-internal.h" 20 #include "sysemu/sysemu.h" 21 #include "sysemu/char.h" 22 23 /* Char drivers that generate qemu_chr_be_write events 24 that should be saved into the log. */ 25 static CharDriverState **char_drivers; 26 static int drivers_count; 27 28 /* Char event attributes. */ 29 typedef struct CharEvent { 30 int id; 31 uint8_t *buf; 32 size_t len; 33 } CharEvent; 34 35 static int find_char_driver(CharDriverState *chr) 36 { 37 int i = 0; 38 for ( ; i < drivers_count ; ++i) { 39 if (char_drivers[i] == chr) { 40 return i; 41 } 42 } 43 return -1; 44 } 45 46 void replay_register_char_driver(CharDriverState *chr) 47 { 48 if (replay_mode == REPLAY_MODE_NONE) { 49 return; 50 } 51 char_drivers = g_realloc(char_drivers, 52 sizeof(*char_drivers) * (drivers_count + 1)); 53 char_drivers[drivers_count++] = chr; 54 } 55 56 void replay_chr_be_write(CharDriverState *s, uint8_t *buf, int len) 57 { 58 CharEvent *event = g_malloc0(sizeof(CharEvent)); 59 60 event->id = find_char_driver(s); 61 if (event->id < 0) { 62 fprintf(stderr, "Replay: cannot find char driver\n"); 63 exit(1); 64 } 65 event->buf = g_malloc(len); 66 memcpy(event->buf, buf, len); 67 event->len = len; 68 69 replay_add_event(REPLAY_ASYNC_EVENT_CHAR_READ, event, NULL, 0); 70 } 71 72 void replay_event_char_read_run(void *opaque) 73 { 74 CharEvent *event = (CharEvent *)opaque; 75 76 qemu_chr_be_write_impl(char_drivers[event->id], event->buf, 77 (int)event->len); 78 79 g_free(event->buf); 80 g_free(event); 81 } 82 83 void replay_event_char_read_save(void *opaque) 84 { 85 CharEvent *event = (CharEvent *)opaque; 86 87 replay_put_byte(event->id); 88 replay_put_array(event->buf, event->len); 89 } 90 91 void *replay_event_char_read_load(void) 92 { 93 CharEvent *event = g_malloc0(sizeof(CharEvent)); 94 95 event->id = replay_get_byte(); 96 replay_get_array_alloc(&event->buf, &event->len); 97 98 return event; 99 } 100 101 void replay_char_write_event_save(int res, int offset) 102 { 103 replay_save_instructions(); 104 replay_mutex_lock(); 105 replay_put_event(EVENT_CHAR_WRITE); 106 replay_put_dword(res); 107 replay_put_dword(offset); 108 replay_mutex_unlock(); 109 } 110 111 void replay_char_write_event_load(int *res, int *offset) 112 { 113 replay_account_executed_instructions(); 114 replay_mutex_lock(); 115 if (replay_next_event_is(EVENT_CHAR_WRITE)) { 116 *res = replay_get_dword(); 117 *offset = replay_get_dword(); 118 replay_finish_event(); 119 replay_mutex_unlock(); 120 } else { 121 replay_mutex_unlock(); 122 error_report("Missing character write event in the replay log"); 123 exit(1); 124 } 125 } 126 127 int replay_char_read_all_load(uint8_t *buf) 128 { 129 replay_mutex_lock(); 130 if (replay_next_event_is(EVENT_CHAR_READ_ALL)) { 131 size_t size; 132 int res; 133 replay_get_array(buf, &size); 134 replay_finish_event(); 135 replay_mutex_unlock(); 136 res = (int)size; 137 assert(res >= 0); 138 return res; 139 } else if (replay_next_event_is(EVENT_CHAR_READ_ALL_ERROR)) { 140 int res = replay_get_dword(); 141 replay_finish_event(); 142 replay_mutex_unlock(); 143 return res; 144 } else { 145 replay_mutex_unlock(); 146 error_report("Missing character read all event in the replay log"); 147 exit(1); 148 } 149 } 150 151 void replay_char_read_all_save_error(int res) 152 { 153 assert(res < 0); 154 replay_save_instructions(); 155 replay_mutex_lock(); 156 replay_put_event(EVENT_CHAR_READ_ALL_ERROR); 157 replay_put_dword(res); 158 replay_mutex_unlock(); 159 } 160 161 void replay_char_read_all_save_buf(uint8_t *buf, int offset) 162 { 163 replay_save_instructions(); 164 replay_mutex_lock(); 165 replay_put_event(EVENT_CHAR_READ_ALL); 166 replay_put_array(buf, offset); 167 replay_mutex_unlock(); 168 } 169