1 /* 2 * Simple trace backend 3 * 4 * Copyright IBM, Corp. 2010 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2. See 7 * the COPYING file in the top-level directory. 8 * 9 */ 10 11 #include <stdlib.h> 12 #include <stdint.h> 13 #include <stdio.h> 14 #include <time.h> 15 #ifndef _WIN32 16 #include <signal.h> 17 #include <pthread.h> 18 #endif 19 #include "qemu/timer.h" 20 #include "trace.h" 21 #include "trace/control.h" 22 #include "trace/simple.h" 23 24 /** Trace file header event ID */ 25 #define HEADER_EVENT_ID (~(uint64_t)0) /* avoids conflicting with TraceEventIDs */ 26 27 /** Trace file magic number */ 28 #define HEADER_MAGIC 0xf2b177cb0aa429b4ULL 29 30 /** Trace file version number, bump if format changes */ 31 #define HEADER_VERSION 3 32 33 /** Records were dropped event ID */ 34 #define DROPPED_EVENT_ID (~(uint64_t)0 - 1) 35 36 /** Trace record is valid */ 37 #define TRACE_RECORD_VALID ((uint64_t)1 << 63) 38 39 /* 40 * Trace records are written out by a dedicated thread. The thread waits for 41 * records to become available, writes them out, and then waits again. 42 */ 43 static CompatGMutex trace_lock; 44 static CompatGCond trace_available_cond; 45 static CompatGCond trace_empty_cond; 46 47 static bool trace_available; 48 static bool trace_writeout_enabled; 49 50 enum { 51 TRACE_BUF_LEN = 4096 * 64, 52 TRACE_BUF_FLUSH_THRESHOLD = TRACE_BUF_LEN / 4, 53 }; 54 55 uint8_t trace_buf[TRACE_BUF_LEN]; 56 static volatile gint trace_idx; 57 static unsigned int writeout_idx; 58 static volatile gint dropped_events; 59 static uint32_t trace_pid; 60 static FILE *trace_fp; 61 static char *trace_file_name; 62 63 /* * Trace buffer entry */ 64 typedef struct { 65 uint64_t event; /* TraceEventID */ 66 uint64_t timestamp_ns; 67 uint32_t length; /* in bytes */ 68 uint32_t pid; 69 uint64_t arguments[]; 70 } TraceRecord; 71 72 typedef struct { 73 uint64_t header_event_id; /* HEADER_EVENT_ID */ 74 uint64_t header_magic; /* HEADER_MAGIC */ 75 uint64_t header_version; /* HEADER_VERSION */ 76 } TraceLogHeader; 77 78 79 static void read_from_buffer(unsigned int idx, void *dataptr, size_t size); 80 static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size); 81 82 static void clear_buffer_range(unsigned int idx, size_t len) 83 { 84 uint32_t num = 0; 85 while (num < len) { 86 if (idx >= TRACE_BUF_LEN) { 87 idx = idx % TRACE_BUF_LEN; 88 } 89 trace_buf[idx++] = 0; 90 num++; 91 } 92 } 93 /** 94 * Read a trace record from the trace buffer 95 * 96 * @idx Trace buffer index 97 * @record Trace record to fill 98 * 99 * Returns false if the record is not valid. 100 */ 101 static bool get_trace_record(unsigned int idx, TraceRecord **recordptr) 102 { 103 uint64_t event_flag = 0; 104 TraceRecord record; 105 /* read the event flag to see if its a valid record */ 106 read_from_buffer(idx, &record, sizeof(event_flag)); 107 108 if (!(record.event & TRACE_RECORD_VALID)) { 109 return false; 110 } 111 112 smp_rmb(); /* read memory barrier before accessing record */ 113 /* read the record header to know record length */ 114 read_from_buffer(idx, &record, sizeof(TraceRecord)); 115 *recordptr = malloc(record.length); /* dont use g_malloc, can deadlock when traced */ 116 /* make a copy of record to avoid being overwritten */ 117 read_from_buffer(idx, *recordptr, record.length); 118 smp_rmb(); /* memory barrier before clearing valid flag */ 119 (*recordptr)->event &= ~TRACE_RECORD_VALID; 120 /* clear the trace buffer range for consumed record otherwise any byte 121 * with its MSB set may be considered as a valid event id when the writer 122 * thread crosses this range of buffer again. 123 */ 124 clear_buffer_range(idx, record.length); 125 return true; 126 } 127 128 /** 129 * Kick writeout thread 130 * 131 * @wait Whether to wait for writeout thread to complete 132 */ 133 static void flush_trace_file(bool wait) 134 { 135 g_mutex_lock(&trace_lock); 136 trace_available = true; 137 g_cond_signal(&trace_available_cond); 138 139 if (wait) { 140 g_cond_wait(&trace_empty_cond, &trace_lock); 141 } 142 143 g_mutex_unlock(&trace_lock); 144 } 145 146 static void wait_for_trace_records_available(void) 147 { 148 g_mutex_lock(&trace_lock); 149 while (!(trace_available && trace_writeout_enabled)) { 150 g_cond_signal(&trace_empty_cond); 151 g_cond_wait(&trace_available_cond, &trace_lock); 152 } 153 trace_available = false; 154 g_mutex_unlock(&trace_lock); 155 } 156 157 static gpointer writeout_thread(gpointer opaque) 158 { 159 TraceRecord *recordptr; 160 union { 161 TraceRecord rec; 162 uint8_t bytes[sizeof(TraceRecord) + sizeof(uint64_t)]; 163 } dropped; 164 unsigned int idx = 0; 165 int dropped_count; 166 size_t unused __attribute__ ((unused)); 167 168 for (;;) { 169 wait_for_trace_records_available(); 170 171 if (g_atomic_int_get(&dropped_events)) { 172 dropped.rec.event = DROPPED_EVENT_ID, 173 dropped.rec.timestamp_ns = get_clock(); 174 dropped.rec.length = sizeof(TraceRecord) + sizeof(uint64_t), 175 dropped.rec.pid = trace_pid; 176 do { 177 dropped_count = g_atomic_int_get(&dropped_events); 178 } while (!g_atomic_int_compare_and_exchange(&dropped_events, 179 dropped_count, 0)); 180 dropped.rec.arguments[0] = dropped_count; 181 unused = fwrite(&dropped.rec, dropped.rec.length, 1, trace_fp); 182 } 183 184 while (get_trace_record(idx, &recordptr)) { 185 unused = fwrite(recordptr, recordptr->length, 1, trace_fp); 186 writeout_idx += recordptr->length; 187 free(recordptr); /* dont use g_free, can deadlock when traced */ 188 idx = writeout_idx % TRACE_BUF_LEN; 189 } 190 191 fflush(trace_fp); 192 } 193 return NULL; 194 } 195 196 void trace_record_write_u64(TraceBufferRecord *rec, uint64_t val) 197 { 198 rec->rec_off = write_to_buffer(rec->rec_off, &val, sizeof(uint64_t)); 199 } 200 201 void trace_record_write_str(TraceBufferRecord *rec, const char *s, uint32_t slen) 202 { 203 /* Write string length first */ 204 rec->rec_off = write_to_buffer(rec->rec_off, &slen, sizeof(slen)); 205 /* Write actual string now */ 206 rec->rec_off = write_to_buffer(rec->rec_off, (void*)s, slen); 207 } 208 209 int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasize) 210 { 211 unsigned int idx, rec_off, old_idx, new_idx; 212 uint32_t rec_len = sizeof(TraceRecord) + datasize; 213 uint64_t event_u64 = event; 214 uint64_t timestamp_ns = get_clock(); 215 216 do { 217 old_idx = g_atomic_int_get(&trace_idx); 218 smp_rmb(); 219 new_idx = old_idx + rec_len; 220 221 if (new_idx - writeout_idx > TRACE_BUF_LEN) { 222 /* Trace Buffer Full, Event dropped ! */ 223 g_atomic_int_inc(&dropped_events); 224 return -ENOSPC; 225 } 226 } while (!g_atomic_int_compare_and_exchange(&trace_idx, old_idx, new_idx)); 227 228 idx = old_idx % TRACE_BUF_LEN; 229 230 rec_off = idx; 231 rec_off = write_to_buffer(rec_off, &event_u64, sizeof(event_u64)); 232 rec_off = write_to_buffer(rec_off, ×tamp_ns, sizeof(timestamp_ns)); 233 rec_off = write_to_buffer(rec_off, &rec_len, sizeof(rec_len)); 234 rec_off = write_to_buffer(rec_off, &trace_pid, sizeof(trace_pid)); 235 236 rec->tbuf_idx = idx; 237 rec->rec_off = (idx + sizeof(TraceRecord)) % TRACE_BUF_LEN; 238 return 0; 239 } 240 241 static void read_from_buffer(unsigned int idx, void *dataptr, size_t size) 242 { 243 uint8_t *data_ptr = dataptr; 244 uint32_t x = 0; 245 while (x < size) { 246 if (idx >= TRACE_BUF_LEN) { 247 idx = idx % TRACE_BUF_LEN; 248 } 249 data_ptr[x++] = trace_buf[idx++]; 250 } 251 } 252 253 static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size) 254 { 255 uint8_t *data_ptr = dataptr; 256 uint32_t x = 0; 257 while (x < size) { 258 if (idx >= TRACE_BUF_LEN) { 259 idx = idx % TRACE_BUF_LEN; 260 } 261 trace_buf[idx++] = data_ptr[x++]; 262 } 263 return idx; /* most callers wants to know where to write next */ 264 } 265 266 void trace_record_finish(TraceBufferRecord *rec) 267 { 268 TraceRecord record; 269 read_from_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord)); 270 smp_wmb(); /* write barrier before marking as valid */ 271 record.event |= TRACE_RECORD_VALID; 272 write_to_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord)); 273 274 if (((unsigned int)g_atomic_int_get(&trace_idx) - writeout_idx) 275 > TRACE_BUF_FLUSH_THRESHOLD) { 276 flush_trace_file(false); 277 } 278 } 279 280 void st_set_trace_file_enabled(bool enable) 281 { 282 if (enable == !!trace_fp) { 283 return; /* no change */ 284 } 285 286 /* Halt trace writeout */ 287 flush_trace_file(true); 288 trace_writeout_enabled = false; 289 flush_trace_file(true); 290 291 if (enable) { 292 static const TraceLogHeader header = { 293 .header_event_id = HEADER_EVENT_ID, 294 .header_magic = HEADER_MAGIC, 295 /* Older log readers will check for version at next location */ 296 .header_version = HEADER_VERSION, 297 }; 298 299 trace_fp = fopen(trace_file_name, "wb"); 300 if (!trace_fp) { 301 return; 302 } 303 304 if (fwrite(&header, sizeof header, 1, trace_fp) != 1) { 305 fclose(trace_fp); 306 trace_fp = NULL; 307 return; 308 } 309 310 /* Resume trace writeout */ 311 trace_writeout_enabled = true; 312 flush_trace_file(false); 313 } else { 314 fclose(trace_fp); 315 trace_fp = NULL; 316 } 317 } 318 319 /** 320 * Set the name of a trace file 321 * 322 * @file The trace file name or NULL for the default name-<pid> set at 323 * config time 324 */ 325 bool st_set_trace_file(const char *file) 326 { 327 st_set_trace_file_enabled(false); 328 329 g_free(trace_file_name); 330 331 if (!file) { 332 /* Type cast needed for Windows where getpid() returns an int. */ 333 trace_file_name = g_strdup_printf(CONFIG_TRACE_FILE, (pid_t)getpid()); 334 } else { 335 trace_file_name = g_strdup_printf("%s", file); 336 } 337 338 st_set_trace_file_enabled(true); 339 return true; 340 } 341 342 void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...)) 343 { 344 stream_printf(stream, "Trace file \"%s\" %s.\n", 345 trace_file_name, trace_fp ? "on" : "off"); 346 } 347 348 void st_flush_trace_buffer(void) 349 { 350 flush_trace_file(true); 351 } 352 353 /* Helper function to create a thread with signals blocked. Use glib's 354 * portable threads since QEMU abstractions cannot be used due to reentrancy in 355 * the tracer. Also note the signal masking on POSIX hosts so that the thread 356 * does not steal signals when the rest of the program wants them blocked. 357 */ 358 static GThread *trace_thread_create(GThreadFunc fn) 359 { 360 GThread *thread; 361 #ifndef _WIN32 362 sigset_t set, oldset; 363 364 sigfillset(&set); 365 pthread_sigmask(SIG_SETMASK, &set, &oldset); 366 #endif 367 368 thread = g_thread_new("trace-thread", fn, NULL); 369 370 #ifndef _WIN32 371 pthread_sigmask(SIG_SETMASK, &oldset, NULL); 372 #endif 373 374 return thread; 375 } 376 377 bool st_init(const char *file) 378 { 379 GThread *thread; 380 381 trace_pid = getpid(); 382 383 thread = trace_thread_create(writeout_thread); 384 if (!thread) { 385 fprintf(stderr, "warning: unable to initialize simple trace backend\n"); 386 return false; 387 } 388 389 atexit(st_flush_trace_buffer); 390 st_set_trace_file(file); 391 return true; 392 } 393