From 99d1328d6ede9d172cdd5588c26f4509588678b8 Mon Sep 17 00:00:00 2001 From: Cedric Roux <cedric.roux@eurecom.fr> Date: Fri, 17 Jun 2016 15:16:49 +0200 Subject: [PATCH] add a very basic replay tracer to be used in conjunction with another tracer so conceptually it's more a tracee than a tracer --- common/utils/T/tracer/Makefile | 7 +- common/utils/T/tracer/replay.c | 178 +++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 common/utils/T/tracer/replay.c diff --git a/common/utils/T/tracer/Makefile b/common/utils/T/tracer/Makefile index 59644e1b3..38a660562 100644 --- a/common/utils/T/tracer/Makefile +++ b/common/utils/T/tracer/Makefile @@ -5,11 +5,14 @@ CFLAGS=-Wall -g -pthread -DT_TRACER -I. LIBS=-lX11 -lm -lpng -lXft -all: record textlog enb vcd +all: record replay textlog enb vcd record: utils.o record.o database.o config.o $(CC) $(CFLAGS) -o record $^ $(LIBS) +replay: utils.o replay.o + $(CC) $(CFLAGS) -o replay $^ $(LIBS) + textlog: utils.o textlog.o database.o event.o handler.o config.o \ event_selector.o view/view.a gui/gui.a logger/logger.a \ filter/filter.a @@ -43,7 +46,7 @@ filter/filter.a: $(CC) $(CFLAGS) -c -o $@ $< clean: - rm -f *.o core tracer_remote textlog enb vcd record + rm -f *.o core tracer_remote textlog enb vcd record replay cd gui && make clean cd view && make clean cd logger && make clean diff --git a/common/utils/T/tracer/replay.c b/common/utils/T/tracer/replay.c new file mode 100644 index 000000000..a64342f39 --- /dev/null +++ b/common/utils/T/tracer/replay.c @@ -0,0 +1,178 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <pthread.h> +#include "utils.h" +#include "../T_defs.h" + +#define DEFAULT_REMOTE_PORT 2021 + +/* replay.c does not know anything about events - it just has the array + * is_on that grows each time replay.c sees a type that does not fit in + * there (the idea is to isolate replay.c as maximum by not using unneeded + * information) + */ +int *is_on; +int is_on_size; + +/* this lock is used to protect access to is_on/is_on_size */ +pthread_mutex_t biglock = PTHREAD_MUTEX_INITIALIZER; + +void set_is_on_size(int size) +{ + is_on = realloc(is_on, size * sizeof(int)); if (is_on == NULL) abort(); + memset(is_on + is_on_size, 0, (size - is_on_size) * sizeof(int)); + is_on_size = size; +} + +void lock(void) +{ + if (pthread_mutex_lock(&biglock)) abort(); +} + +void unlock(void) +{ + if (pthread_mutex_unlock(&biglock)) abort(); +} + +#define QUIT(x) do { printf("%s\n", x); exit(1); } while(0) + +void get_message(int s) +{ + char t; + int l; + int id; + int on; + + if (read(s, &t, 1) != 1) QUIT("get_message fails"); + lock(); + switch (t) { + case 0: + /* toggle all those IDs */ + if (read(s, &l, sizeof(int)) != sizeof(int)) QUIT("get_message fails"); + while (l) { + if (read(s, &id, sizeof(int)) != sizeof(int)) QUIT("get_message fails"); + if (id > is_on_size - 1) set_is_on_size(id + 1); + is_on[id] = 1 - is_on[id]; + l--; + } + break; + case 1: + /* set IDs as given */ + /* optimize? */ + if (read(s, &l, sizeof(int)) != sizeof(int)) QUIT("get_message fails"); + if (l > is_on_size) set_is_on_size(l); + id = 0; + while (l) { + if (read(s, &on, sizeof(int)) != sizeof(int)) + QUIT("get_message fails"); + is_on[id] = on; + id++; + l--; + } + break; + case 2: break; /* do nothing, this message is to wait for local tracer */ + default: abort(); + } + unlock(); +} + +void *get_message_thread(void *_socket) +{ + int socket = *(int *)_socket; + + while (1) get_message(socket); + + return NULL; +} + +void usage(void) +{ + printf( +"options:\n" +" -i <input file> this option is mandatory\n" +" -p <port> wait connection on given port (default %d)\n", + DEFAULT_REMOTE_PORT + ); + exit(1); +} + +#define ERR printf("ERROR: read file %s failed\n", input_filename) + +int main(int n, char **v) +{ + int port = DEFAULT_REMOTE_PORT; + char *input_filename = NULL; + int i; + int socket; + FILE *in; + int do_send; + + for (i = 1; i < n; i++) { + if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage(); + if (!strcmp(v[i], "-i")) + { if (i > n-2) usage(); input_filename = v[++i]; continue; } + if (!strcmp(v[i], "-p")) + { if (i > n-2) usage(); port = atoi(v[++i]); continue; } + usage(); + } + + if (input_filename == NULL) { + printf("ERROR: provide an input file (-i)\n"); + exit(1); + } + + in = fopen(input_filename, "r"); + if (in == NULL) { perror(input_filename); abort(); } + + socket = get_connection("0.0.0.0", port); + + /* get first message to activate selected traces */ + get_message(socket); + + new_thread(get_message_thread, &socket); + + while (1) { + int type; + int32_t length; + char v[T_BUFFER_MAX]; + int vpos = 0; + + /* read event from file */ + if (fread(&length, 4, 1, in) != 1) break; + memcpy(v+vpos, &length, 4); + vpos += 4; +#ifdef T_SEND_TIME + if (length < sizeof(struct timespec)) { ERR; break; } + if (fread(v+vpos, sizeof(struct timespec), 1, in) != 1) { ERR; break; } + vpos += sizeof(struct timespec); + length -= sizeof(struct timespec); +#endif + if (length < sizeof(int)) { ERR; break; } + if (fread(&type, sizeof(int), 1, in) != 1) { ERR; break; } + memcpy(v+vpos, &type, sizeof(int)); + vpos += sizeof(int); + length -= sizeof(int); + if (length) if (fread(v+vpos, length, 1, in) != 1) { ERR; break; } + vpos += length; + + /* only send if configured to do so */ + lock(); + if (type < 0) do_send = 1; + else { + if (type > is_on_size - 1) set_is_on_size(type+1); + do_send = is_on[type]; + } + unlock(); + + if (do_send) + if (socket_send(socket, v, vpos) != 0) + { printf("ERROR: socket writing failed\n"); abort(); } + } + + fclose(in); + close(socket); + + return 0; +} -- GitLab