loader based trace using musl
authorSzabolcs Nagy <nsz@port70.net>
Sun, 19 Jan 2014 17:58:31 +0000 (18:58 +0100)
committerSzabolcs Nagy <nsz@port70.net>
Sun, 19 Jan 2014 17:58:31 +0000 (18:58 +0100)
loader/config.mak [new file with mode: 0644]
loader/run.sh [new file with mode: 0755]
loader/w/dump.c [new file with mode: 0644]
loader/w/stub.h [new file with mode: 0644]
loader/w/wrap.c [new file with mode: 0644]

diff --git a/loader/config.mak b/loader/config.mak
new file mode 100644 (file)
index 0000000..888cea8
--- /dev/null
@@ -0,0 +1,22 @@
+# add at the end of musl config.mak
+
+all: lib/libw.so w/dump
+
+w/dump: w/dump.o
+       $(CC) -o $@ $^
+
+w/redef: lib/libc.so
+       nm -D lib/libc.so |awk '/^[0-9a-f]* [T|W]/{print $$3 " __real_" $$3}' >$@
+
+w/tab.h: w/redef
+       awk 'BEGIN{n=0} {print "T(" n++ "," $$1 ")"}' $< >$@
+
+%.wo: %.lo
+       objcopy --redefine-syms w/redef $< $@
+
+w/wrap.lo: w/tab.h w/stub.h
+
+lib/libw.so: w/wrap.lo $(LOBJS:%.lo=%.wo)
+       $(CC) $(CFLAGS_ALL_SHARED) $(LDFLAGS) -nostdlib -shared \
+       -Wl,-e,__real__start -Wl,-Bsymbolic-functions \
+       -o $@ $^ $(LIBCC)
diff --git a/loader/run.sh b/loader/run.sh
new file mode 100755 (executable)
index 0000000..b38bd4d
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+LD_PRELOAD=lib/libw.so "$@"
+w/dump
diff --git a/loader/w/dump.c b/loader/w/dump.c
new file mode 100644 (file)
index 0000000..f3ce32e
--- /dev/null
@@ -0,0 +1,37 @@
+#define _XOPEN_SOURCE 700
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+static struct {
+       uint64_t c;
+       uint64_t t;
+} *tab;
+
+static char *names[] = {
+#define T(i,f) [i] = #f,
+#include "tab.h"
+#undef T
+};
+
+int main()
+{
+       int i;
+       int fd = open("/tmp/wrap", O_RDONLY);
+       if (fd == -1) {
+               dprintf(2, "open /tmp/wrap failed: %m\n");
+               return 1;
+       }
+       tab = mmap(0, 2000 * sizeof *tab, PROT_READ, MAP_PRIVATE, fd, 0);
+       if (tab == MAP_FAILED) {
+               dprintf(2, "mmap: %m\n");
+               return 1;
+       }
+       for (i = 0; i < sizeof names/sizeof *names; i++)
+               if (tab[i].c)
+                       dprintf(1, "%s: %llu calls %llu ns %f us/call\n",
+                         names[i], tab[i].c, tab[i].t, (double)tab[i].t/(1000*tab[i].c));
+       return 0;
+}
diff --git a/loader/w/stub.h b/loader/w/stub.h
new file mode 100644 (file)
index 0000000..5d20a7d
--- /dev/null
@@ -0,0 +1,25 @@
+__asm__(
+#define T(i,f) "\n" \
+".global " #f "\n" \
+".type " #f ",@function\n" \
+#f ":\n" \
+"      pushl %esp\n" \
+"      pushl $" #i "\n" \
+"      call enter\n" \
+"      pop %eax\n" \
+"      pop %eax\n" \
+"      jmp __real_" #f "\n"
+
+#include "tab.h"
+#undef T
+"\n"
+"after:\n"
+"      push %eax\n"
+"      push %edx\n"
+"      call leave\n"
+"      mov %eax,%ecx\n"
+"      pop %edx\n"
+"      pop %eax\n"
+"      push %ecx\n"
+"      ret\n"
+);
diff --git a/loader/w/wrap.c b/loader/w/wrap.c
new file mode 100644 (file)
index 0000000..19a50ba
--- /dev/null
@@ -0,0 +1,98 @@
+#define clock_gettime __real_clock_gettime
+#define open __real_open
+#define __syscall __real___syscall
+#define mmap __real_mmap
+#define ftruncate __real_ftruncate
+#define dprintf __real_dprintf
+#define _exit __real__exit
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+#include <time.h>
+
+#include "stub.h"
+
+static struct {
+       char *s;
+       size_t len;
+} nametab[] = {
+#define T(i,f) {#f "\n", sizeof #f},
+#include "tab.h"
+#undef T
+};
+
+static struct {
+       uint64_t c;
+       uint64_t t;
+} *tab;
+
+static void tab_init(void)
+{
+       // todo: argv[0] ".ldtrace"
+       int fd = open("/tmp/wrap", O_CREAT|O_TRUNC|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NONBLOCK, 0666);
+       if (fd == -1) {
+               dprintf(2, "open /tmp/wrap failed: %m\n");
+               _exit(127);
+       }
+       if (ftruncate(fd, 2000 * sizeof *tab)) {
+               dprintf(2, "ftruncate: %m\n");
+               _exit(127);
+       }
+       tab = mmap(0, 2000 * sizeof *tab, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+       if (tab == MAP_FAILED) {
+               dprintf(2, "mmap: %m\n");
+               _exit(127);
+       }
+}
+
+static int show_trace=1;
+static int log_time=1;
+
+// todo: tls
+static struct entry {
+       void *ret;
+       uint64_t t;
+       int n;
+} stack[100];
+static struct entry *sp;
+
+long __syscall(long,...);
+static void after(void);
+
+__attribute__((used))
+static void enter(int n, void **retaddr)
+{
+       if (!tab) {
+               tab_init();
+               sp = stack;
+       }
+       if (show_trace)
+               __syscall(SYS_write, 2, nametab[n].s, nametab[n].len);
+       tab[n].c++;
+       sp->n = n;
+       sp->ret = *retaddr;
+       *retaddr = after;
+       if (log_time) {
+               struct timespec ts;
+               clock_gettime(CLOCK_REALTIME, &ts);
+               sp->t = ts.tv_sec*1000000000ULL + ts.tv_nsec;
+       }
+       sp++;
+}
+
+__attribute__((used))
+static void *leave(void)
+{
+       sp--;
+       if (log_time) {
+               struct timespec ts;
+               clock_gettime(CLOCK_REALTIME, &ts);
+               tab[sp->n].t += ts.tv_sec*1000000000ULL + ts.tv_nsec - sp->t;
+       }
+       return sp->ret;
+}