-finstrument-functions && elfutils-libs based functions tracer; no args printed.
authorlace <>
Sun, 23 Nov 2008 10:43:59 +0000 (10:43 +0000)
committerlace <>
Sun, 23 Nov 2008 10:43:59 +0000 (10:43 +0000)
src/itrace.c [new file with mode: 0644]

diff --git a/src/itrace.c b/src/itrace.c
new file mode 100644 (file)
index 0000000..224d7ee
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+gcc -o itrace.so -shared -fPIC -Wall -ggdb2 itrace.c -ldw
+-finstrument-functions
+LD_PRELOAD=./itrace.so
+*/
+
+#include <stdio.h>
+#include <elfutils/libdwfl.h>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define PREFIX "itrace: "
+#define INDENT_MAX 20
+
+static Dwfl *
+dwfl_get (void)
+{
+  static char *debuginfo_path;
+  static Dwfl *dwfl;
+
+  static const Dwfl_Callbacks proc_callbacks =
+   {
+     .find_debuginfo = dwfl_standard_find_debuginfo,
+     .debuginfo_path = &debuginfo_path,
+
+     .find_elf = dwfl_linux_proc_find_elf,
+   };
+
+  if (dwfl == NULL)
+    {
+      dwfl = dwfl_begin (&proc_callbacks);
+      assert (dwfl != NULL);
+
+      errno = 0;
+      if (dwfl_linux_proc_report (dwfl, getpid ()) != 0
+        || dwfl_report_end (dwfl, NULL, NULL) != 0)
+       {
+         fprintf (stderr, "dwfl reporting: %m\n");
+         dwfl_end (dwfl);
+         dwfl = NULL;
+         abort ();
+       }
+    }
+  return dwfl;
+}
+
+struct getmodules_callback_arg
+  {
+    void *addr;
+    const char *name;
+  };
+
+static int getmodules_callback (Dwfl_Module *module,
+                               void **module_userdata_pointer,
+                               const char *module_name,
+                               Dwarf_Addr module_low_addr, void *arg_voidp)
+{
+  struct getmodules_callback_arg *arg = arg_voidp;
+
+  arg->name = dwfl_module_addrname (module, (GElf_Addr) arg->addr);
+  return arg->name ? DWARF_CB_ABORT : DWARF_CB_OK;
+}
+
+static const char *
+addr_lookup (void *addr)
+{
+  Dwfl *dwfl = dwfl_get ();
+  struct getmodules_callback_arg arg;
+
+  arg.name = NULL;
+  arg.addr = addr;
+  dwfl_getmodules (dwfl, getmodules_callback, &arg, 0);
+
+  return arg.name;
+}
+
+static const char *
+addr_print (void *addr)
+{
+  const char *name;
+
+  name = addr_lookup (addr);
+  if (!name)
+    {
+      static char buf[20];
+
+      sprintf (buf, "%p", addr);
+      name = buf;
+    }
+  return name;
+}
+
+struct stack
+  {
+    void *this_fn;
+    void *call_site;
+  };
+static struct stack *stack;
+static unsigned stack_at, stack_size;
+
+void __cyg_profile_func_enter (void *this_fn, void *call_site)
+{
+  int indent;
+
+  if (stack_at == stack_size)
+    {
+      unsigned size_new = stack_size ? stack_size * 2 : 0x100;
+      struct stack *stack_new;
+
+      stack_new = realloc (stack, sizeof (*stack) * size_new);
+      if (!stack_new)
+       {
+         fprintf (stderr, PREFIX "stack size %u allocation failure!\n",
+                  size_new);
+         return;
+       }
+      stack = stack_new;
+      stack_size = size_new;
+    }
+  stack[stack_at].this_fn = this_fn;
+  stack[stack_at].call_site = call_site;
+  stack_at++;
+
+  indent = stack_at - 1 <= INDENT_MAX ? stack_at - 1 : INDENT_MAX;
+
+  fprintf (stderr, PREFIX "%*s->%s", indent, "", addr_print (this_fn));
+  fprintf (stderr, " (%s)\n", addr_print (call_site));
+}
+
+void __cyg_profile_func_exit  (void *this_fn, void *call_site)
+{
+  int indent;
+
+  indent = stack_at - 1 <= INDENT_MAX ? stack_at - 1 : INDENT_MAX;
+
+  fprintf (stderr, PREFIX "%*s<-%s", indent, "", addr_print (this_fn));
+  fprintf (stderr, " (%s)\n", addr_print (call_site));
+
+  if (!stack_at)
+    {
+      fprintf (stderr, PREFIX "stack empty!\n");
+      return;
+    }
+  if (stack[stack_at - 1].this_fn != this_fn
+      || stack[stack_at - 1].call_site != call_site)
+    {
+      fprintf (stderr, PREFIX "Unexpected function leave, resetting the stack\n");
+      stack_at = 0;
+      return;
+    }
+  stack_at--;
+}