--- /dev/null
+# 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)
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}