diff --git a/common/utils/T/.gitignore b/common/utils/T/.gitignore
index f5724e6ff8c25fd4bf1fc8701f7ca881de58194a..85ff166c1ab4a1c217d22a0d1038f9a9955092da 100644
--- a/common/utils/T/.gitignore
+++ b/common/utils/T/.gitignore
@@ -10,4 +10,8 @@ tracer/replay
 tracer/textlog
 tracer/vcd
 tracer/macpdu2wireshark
+tracer/ue
+tracer/to_vcd
+tracer/extract_input_subframe
+tracer/extract_output_subframe
 tracee/tracee
diff --git a/common/utils/T/tracer/Makefile b/common/utils/T/tracer/Makefile
index 6546345968637809eeed85e630e393035dcf0589..c1b0c682a0601f65172269459d10edde32f10661 100644
--- a/common/utils/T/tracer/Makefile
+++ b/common/utils/T/tracer/Makefile
@@ -3,10 +3,11 @@ CFLAGS=-Wall -g -pthread -DT_TRACER -I.
 
 #CFLAGS += -O3 -ffast-math -fomit-frame-pointer
 
-LIBS=-lX11 -lm -lpng -lXft
+LIBS=-lm
+XLIBS=-lX11 -lpng -lXft
 
 all: record replay extract_config textlog enb ue vcd macpdu2wireshark \
-     extract_input_subframe
+     extract_input_subframe extract_output_subframe to_vcd
 
 record: utils.o record.o database.o config.o
 	$(CC) $(CFLAGS) -o record $^ $(LIBS)
@@ -21,25 +22,33 @@ extract_input_subframe: extract_input_subframe.o database.o event.o utils.o \
     config.o
 	$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
 
+extract_output_subframe: extract_output_subframe.o database.o event.o utils.o \
+    config.o
+	$(CC) $(CFLAGS) -o $@ $^ $(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
-	$(CC) $(CFLAGS) -o textlog $^ $(LIBS)
+	$(CC) $(CFLAGS) -o textlog $^ $(LIBS) $(XLIBS)
 
 enb: utils.o enb.o database.o event.o handler.o config.o \
          event_selector.o view/view.a gui/gui.a logger/logger.a \
          filter/filter.a
-	$(CC) $(CFLAGS) -o enb $^ $(LIBS)
+	$(CC) $(CFLAGS) -o enb $^ $(LIBS) $(XLIBS)
 
 ue: utils.o ue.o database.o event.o handler.o config.o \
          event_selector.o view/view.a gui/gui.a logger/logger.a \
          filter/filter.a
-	$(CC) $(CFLAGS) -o ue $^ $(LIBS)
+	$(CC) $(CFLAGS) -o ue $^ $(LIBS) $(XLIBS)
 
 vcd: utils.o vcd.o database.o event.o handler.o config.o \
          event_selector.o view/view.a gui/gui.a logger/logger.a \
          filter/filter.a
-	$(CC) $(CFLAGS) -o vcd $^ $(LIBS)
+	$(CC) $(CFLAGS) -o vcd $^ $(LIBS) $(XLIBS)
+
+to_vcd: to_vcd.o database.o event.o handler.o utils.o config.o \
+         logger/logger.a filter/filter.a
+	$(CC) $(CFLAGS) -o to_vcd $^ $(LIBS)
 
 macpdu2wireshark: macpdu2wireshark.o database.o utils.o handler.o event.o \
                   config.o
@@ -65,6 +74,7 @@ filter/filter.a:
 clean:
 	rm -f *.o core tracer_remote textlog enb ue vcd record replay
 	rm -f extract_config macpdu2wireshark extract_input_subframe
+	rm -f extract_output_subframe to_vcd
 	cd gui && make clean
 	cd view && make clean
 	cd logger && make clean
diff --git a/common/utils/T/tracer/extract_output_subframe.c b/common/utils/T/tracer/extract_output_subframe.c
new file mode 100644
index 0000000000000000000000000000000000000000..b82ad0e7665d259358e08b27f7c1816659ca3b3b
--- /dev/null
+++ b/common/utils/T/tracer/extract_output_subframe.c
@@ -0,0 +1,158 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include "database.h"
+#include "event.h"
+#include "config.h"
+
+void usage(void)
+{
+  printf(
+"usage: [options] <file> <frame> <subframe> <number of subframes>\n"
+"    the program dumps 'number of subframes' subframes starting\n"
+"    at 'frame:suubframe'\n"
+"options:\n"
+"    -d <database file>        this option is mandatory\n"
+"    -o <output file>          output to file (default: stdout)\n"
+"    -v                        verbose\n"
+  );
+  exit(1);
+}
+
+int main(int n, char **v)
+{
+  char *database_filename = NULL;
+  void *database;
+  int i;
+  int output_event_id;
+  database_event_format f;
+  char *file = NULL;
+  int fd;
+  int frame = -1, subframe = -1;
+  int number_of_subframes = -1;
+  int frame_arg, subframe_arg, buffer_arg;
+  int verbose = 0;
+  char *out_filename = NULL;
+  FILE *out;
+
+  for (i = 1; i < n; i++) {
+    if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
+    if (!strcmp(v[i], "-d"))
+      { if (i > n-2) usage(); database_filename = v[++i]; continue; }
+    if (!strcmp(v[i], "-o"))
+      { if (i > n-2) usage(); out_filename = v[++i]; continue; }
+    if (!strcmp(v[i], "-v")) { verbose = 1; continue; }
+    if (file == NULL)              { file = v[i]; continue; }
+    if (frame == -1)               { frame = atoi(v[i]); continue; }
+    if (subframe == -1)            { subframe = atoi(v[i]); continue; }
+    if (number_of_subframes == -1) {number_of_subframes=atoi(v[i]);continue;}
+    usage();
+  }
+  if (file == NULL || frame == -1 || subframe == -1 ||
+      number_of_subframes == -1) usage();
+
+  if (database_filename == NULL) {
+    printf("ERROR: provide a database file (-d)\n");
+    exit(1);
+  }
+
+  if (out_filename == NULL) out = stdout;
+  else {
+    out = fopen(out_filename, "w");
+    if (out == NULL) { perror(out_filename); exit(1); }
+  }
+
+  database = parse_database(database_filename);
+
+  load_config_file(database_filename);
+
+  output_event_id = event_id_from_name(database, "ENB_PHY_OUTPUT_SIGNAL");
+  f = get_format(database, output_event_id);
+
+  frame_arg = subframe_arg = buffer_arg = -1;
+  for (i = 0; i < f.count; i++) {
+    if (!strcmp(f.name[i], "frame")) {
+      if (frame_arg != -1) goto err;
+      if (strcmp(f.type[i], "int")) goto err;
+      frame_arg = i;
+    }
+    if (!strcmp(f.name[i], "subframe")) {
+      if (subframe_arg != -1) goto err;
+      if (strcmp(f.type[i], "int")) goto err;
+      subframe_arg = i;
+    }
+    if (!strcmp(f.name[i], "txdata")) {
+      if (buffer_arg != -1) goto err;
+      if (strcmp(f.type[i], "buffer")) goto err;
+      buffer_arg = i;
+    }
+    continue;
+err:
+    printf("cannot deal with ENB_PHY_OUTPUT_SIGNAL from database file\n");
+    exit(1);
+  }
+  if (frame_arg == -1 || subframe_arg == -1 || buffer_arg == -1) goto err;
+
+  fd = open(file, O_RDONLY);
+  if (fd == -1) { perror(file); exit(1); }
+
+  int last_frame = -1;
+  int last_subframe = -1;
+  int subframe_written = 0;
+  while (1) {
+    char v[T_BUFFER_MAX];
+    event e;
+    e = get_event(fd, v, database);
+    if (e.type == -1) break;
+    if (e.type != output_event_id) continue;
+    if (verbose)
+      printf("found output frame %d subframe %d size %d\n",
+             e.e[frame_arg].i, e.e[subframe_arg].i, e.e[buffer_arg].bsize);
+    if (!(last_frame != -1 ||
+          (frame == e.e[frame_arg].i && subframe == e.e[subframe_arg].i)))
+      continue;
+    frame = e.e[frame_arg].i;
+    subframe = e.e[subframe_arg].i;
+    if (last_frame != -1) {
+      if (frame*10+subframe != (last_frame*10+last_subframe + 1) % 10240) {
+        printf("error: discontinuity, not what you want...\n");
+        exit(1);
+      }
+    }
+    last_frame = frame;
+    last_subframe = subframe;
+#if 0
+for (i = 0; i < e.e[buffer_arg].bsize/2; i++) {
+short *x = e.e[buffer_arg].b;
+x[i] *= 14;
+}
+#endif
+    if (verbose)
+      printf("save output frame %d subframe %d size %d\n",
+             e.e[frame_arg].i, e.e[subframe_arg].i, e.e[buffer_arg].bsize);
+    if (fwrite(e.e[buffer_arg].b, e.e[buffer_arg].bsize, 1, out) != 1) {
+      perror(out_filename);
+      exit(1);
+    }
+    subframe_written++;
+    if (subframe_written != number_of_subframes)
+      continue;
+
+    /* done */
+    fflush(out);
+    if (out_filename != NULL) {
+      if (fclose(out)) perror(out_filename);
+    }
+    if (verbose)
+      printf("%d subframes written\n", subframe_written);
+    return 0;
+  }
+
+  printf("error with input file, %d subframe written\n", subframe_written);
+  fflush(out);
+  if (out_filename != NULL) {
+    if (fclose(out)) perror(out_filename);
+  }
+  return 1;
+}
diff --git a/common/utils/T/tracer/to_vcd.c b/common/utils/T/tracer/to_vcd.c
new file mode 100644
index 0000000000000000000000000000000000000000..82cd3393d7e9e26e59305cb3928a209d879bfdc4
--- /dev/null
+++ b/common/utils/T/tracer/to_vcd.c
@@ -0,0 +1,302 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <unistd.h>
+#include "database.h"
+#include "utils.h"
+#include "handler.h"
+#include "config.h"
+#include "logger/logger.h"
+#include "view/view.h"
+
+typedef struct {
+  char *event;
+  char *arg;
+  char *vcd_name;
+  int boolean;
+} vcd_vars;
+
+/****************************************************************************/
+/* VCD file handling begin                                                  */
+/****************************************************************************/
+
+FILE *out;
+
+uint64_t start_time;
+int start_time_inited;
+
+void vcd_init(char *file)
+{
+  out = fopen(file, "w"); if (out == NULL) { perror(file); exit(1); }
+}
+
+void vcd_write_header(vcd_vars *v, int n)
+{
+  int i;
+
+  if (fprintf(out,
+"$date\n"
+"  January, 1, 1970.\n"
+"$end\n"
+"$version\n"
+"  to_vcd\n"
+"$end\n"
+"$timescale 1ns $end\n"
+"$scope module logic $end\n") <= 0) abort();
+
+  for (i = 0; i < n; i++)
+    if (fprintf(out, "$var wire %d %s %s $end\n",
+           v[i].boolean ? 1 : 64,
+           v[i].vcd_name, v[i].vcd_name) <= 0) abort();
+
+  if (fprintf(out,
+"$upscope $end\n"
+"$enddefinitions $end\n"
+"$dumpvars\n") <= 0) abort();
+
+  for (i = 0; i < n; i++)
+    if (v[i].boolean) {
+      if (fprintf(out, "0%s\n", v[i].vcd_name) <= 0) abort();
+    } else {
+      if (fprintf(out, "b0 %s\n", v[i].vcd_name) <= 0) abort();
+    }
+
+  if (fprintf(out,
+"$end\n") <= 0) abort();
+
+}
+
+void vcd_end(void)
+{
+  if (fclose(out)) { perror("error closing VCD file"); exit(1); }
+}
+
+char *b64(uint64_t val)
+{
+  static char v[65];
+  char *s = &v[64];
+  *s = 0;
+  if (val == 0) { s--; *s = '0'; return s; }
+  while (val) {
+    s--;
+    *s = val&1 ? '1' : '0';
+    val >>= 1;
+  }
+  return s;
+}
+
+void vcd_dump(char *v)
+{
+  uint64_t h, m, s, ns;
+  char t;
+  uint64_t val;
+  uint64_t time;
+  char var[256];
+  if (sscanf(v, "%"SCNu64":%"SCNu64":%"SCNu64".%"SCNu64": %c %"SCNu64" %s",
+      &h, &m, &s, &ns, &t, &val, var) != 7)
+    goto err;
+  time = h*60*60*1000000000 +
+            m*60*1000000000 +
+               s*1000000000 +
+                         ns;
+  if (!start_time_inited) {
+    start_time = time;
+    start_time_inited = 1;
+  }
+  if (fprintf(out, "#%"PRIu64"\n", time - start_time) <= 0) abort();
+  switch (t) {
+  case 'b': if (fprintf(out, "%d%s\n", val!=0, var) <= 0) abort(); break;
+  case 'l': if (fprintf(out, "b%s %s\n", b64(val), var) <= 0) abort(); break;
+  default: goto err;
+  }
+
+  return;
+
+err:
+  printf("bad vcd_dump line '%s'\n", v);
+  exit(1);
+}
+
+/****************************************************************************/
+/* VCD file handling end                                                    */
+/****************************************************************************/
+
+
+/****************************************************************************/
+/* vcd view start                                                           */
+/****************************************************************************/
+
+struct vcd_view {
+  view common;
+};
+
+static void vcd_view_clear(view *this)
+{
+  /* nothing */
+}
+
+static void vcd_view_append(view *_this, char *s)
+{
+  vcd_dump(s);
+}
+
+static view *new_view_vcd(void)
+{
+  struct vcd_view *ret = calloc(1, sizeof(struct vcd_view));
+  if (ret == NULL) abort();
+  ret->common.clear = vcd_view_clear;
+  ret->common.append = (void (*)(view *, ...))vcd_view_append;
+  return (view *)ret;
+}
+
+/****************************************************************************/
+/* vcd view end                                                             */
+/****************************************************************************/
+
+void activate_traces(int socket, int number_of_events, int *is_on)
+{
+  char t = 1;
+  if (socket_send(socket, &t, 1) == -1 ||
+      socket_send(socket, &number_of_events, sizeof(int)) == -1 ||
+      socket_send(socket, is_on, number_of_events * sizeof(int)) == -1)
+    abort();
+}
+
+void usage(void)
+{
+  printf(
+"options:\n"
+"    -d <database file>           this option is mandatory\n"
+"    -o <output file>             this option is mandatory\n"
+"    -ip <host>                   connect to given IP address (default %s)\n"
+"    -p <port>                    connect to given port (default %d)\n"
+"    -b <event> <arg> <vcd name>  trace as binary (0 off, anything else on)\n"
+"    -l <event> <arg> <vcd name>  trace as uint64_t\n",
+  DEFAULT_REMOTE_IP,
+  DEFAULT_REMOTE_PORT
+  );
+  exit(1);
+}
+
+int run = 1;
+static int socket = -1;
+
+void force_stop(int x)
+{
+  printf("\ngently quit...\n");
+  close(socket);
+  socket = -1;
+  run = 0;
+}
+
+int main(int n, char **v)
+{
+  char *output_filename = NULL;
+  char *database_filename = NULL;
+  void *database;
+  char *ip = DEFAULT_REMOTE_IP;
+  int port = DEFAULT_REMOTE_PORT;
+  int *is_on;
+  int number_of_events;
+  int i;
+  vcd_vars vars[n];
+  int nvars = 0;
+  view *vcd_view;
+  event_handler *h;
+  logger *textlog;
+
+  /* write on a socket fails if the other end is closed and we get SIGPIPE */
+  if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) abort();
+
+  for (i = 1; i < n; i++) {
+    if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
+    if (!strcmp(v[i], "-d"))
+      { if (i > n-2) usage(); database_filename = v[++i]; continue; }
+    if (!strcmp(v[i], "-o"))
+      { if (i > n-2) usage(); output_filename = v[++i]; continue; }
+    if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; }
+    if (!strcmp(v[i], "-p"))
+      { if (i > n-2) usage(); port = atoi(v[++i]); continue; }
+    if (!strcmp(v[i], "-b")) { if(i>n-4)usage();
+      vars[nvars].event     = v[++i];
+      vars[nvars].arg       = v[++i];
+      vars[nvars].vcd_name  = v[++i];
+      vars[nvars++].boolean = 1;
+      continue;
+    }
+    if (!strcmp(v[i], "-l")) { if(i>n-4)usage();
+      vars[nvars].event     = v[++i];
+      vars[nvars].arg       = v[++i];
+      vars[nvars].vcd_name  = v[++i];
+      vars[nvars++].boolean = 0;
+      continue;
+    }
+    usage();
+  }
+
+  if (output_filename == NULL) {
+    printf("ERROR; provide an output file (-o)\n");
+    exit(1);
+  }
+
+  if (database_filename == NULL) {
+    printf("ERROR: provide a database file (-d)\n");
+    exit(1);
+  }
+
+  database = parse_database(database_filename);
+
+  load_config_file(database_filename);
+
+  number_of_events = number_of_ids(database);
+  is_on = calloc(number_of_events, sizeof(int));
+  if (is_on == NULL) abort();
+
+  h = new_handler(database);
+
+  /* create the view */
+  vcd_view = new_view_vcd();
+
+  /* setup traces */
+  for (i = 0; i < nvars; i++) {
+    char format[256];
+    if (strlen(vars[i].arg) > 256-3) abort();
+    if (strlen(vars[i].vcd_name) > 256-1) abort();
+    sprintf(format, "%c [%s] %s",
+        vars[i].boolean ? 'b' : 'l',
+        vars[i].arg,
+        vars[i].vcd_name);
+    textlog = new_textlog(h, database, vars[i].event, format);
+    logger_add_view(textlog, vcd_view);
+    on_off(database, vars[i].event, is_on, 1);
+  }
+
+  socket = connect_to(ip, port);
+
+  /* activate selected traces */
+  activate_traces(socket, number_of_events, is_on);
+
+  vcd_init(output_filename);
+  vcd_write_header(vars, nvars);
+
+  /* exit on ctrl+c and ctrl+z */
+  if (signal(SIGQUIT, force_stop) == SIG_ERR) abort();
+  if (signal(SIGINT, force_stop) == SIG_ERR) abort();
+  if (signal(SIGTSTP, force_stop) == SIG_ERR) abort();
+
+  /* read messages */
+  while (run) {
+    char v[T_BUFFER_MAX];
+    event e;
+    e = get_event(socket, v, database);
+    if (e.type == -1) { printf("disconnected? let's quit gently\n"); break; }
+    handle_event(h, e);
+  }
+
+  vcd_end();
+
+  return 0;
+}