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