diff --git a/babl/babl-memory.c b/babl/babl-memory.c
index 6ceca90..154dd21 100644
--- a/babl/babl-memory.c
+++ b/babl/babl-memory.c
@@ -16,6 +16,8 @@
* .
*/
+#define _GNU_SOURCE 1
+
#include "config.h"
#include
#include
@@ -23,6 +25,17 @@
#include
#include "babl-internal.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
static BablMallocFunc malloc_f = malloc;
static BablFreeFunc free_f = free;
@@ -32,12 +45,24 @@ static void *first_free_used = NULL;
void
babl_set_malloc (BablMallocFunc malloc_function)
{
+ fprintf (stderr,
+ "babl_set_malloc:\n"
+ " first_malloc_used: %p\n"
+ " old malloc_f: %p\n"
+ " malloc_function: %p\n",
+ first_malloc_used, malloc_f, malloc_function);
malloc_f = malloc_function;
}
void
babl_set_free (BablFreeFunc free_function)
{
+ fprintf (stderr,
+ "babl_set_free:\n"
+ " first_free_used: %p\n"
+ " old free_f: %p\n"
+ " free_function: %p\n",
+ first_free_used, free_f, free_function);
free_f = free_function;
}
@@ -78,6 +103,68 @@ mem_stats (void)
#endif
+static void set_watchpoint(void* addr) {
+ /* Thanks to jankratochvil in #gdb@freenode who pointed this out:
+ http://sources.redhat.com/cgi-bin/cvsweb.cgi/~checkout~/tests/ptrace-tests/tests/watchpoint.c?cvsroot=systemtap
+ */
+
+ pid_t child;
+ int status;
+ unsigned long dr7;
+ long l;
+
+ child = fork ();
+ switch (child)
+ {
+ case -1:
+ assert (0);
+ case 0:
+ assert (ptrace (PTRACE_TRACEME, 0, NULL, NULL) == 0);
+ assert (raise (SIGTRAP) == 0);
+
+ return;
+ default:
+ break;
+ }
+
+ assert (waitpid (child, &status, 0) == child);
+ assert (WIFSTOPPED (status));
+ assert (WSTOPSIG (status) == SIGTRAP);
+
+ errno = 0;
+ l = ptrace (PTRACE_POKEUSER, child,
+ offsetof (struct user, u_debugreg[0]), (unsigned long) addr);
+ assert_perror (errno);
+ assert (l == 0);
+
+ dr7 = (DR_RW_WRITE << DR_CONTROL_SHIFT);
+
+#ifdef DR_LEN_8
+ /*
+ * For a 32-bit build, DR_LEN_8 might be defined by the header.
+ * On a 64-bit kernel, we might even be able to use it.
+ * But we can't tell, and we don't really need it, so just use DR_LEN_4.
+ */
+ if (sizeof (long) > 4)
+ dr7 |= (DR_LEN_8 << DR_CONTROL_SHIFT);
+ else
+#endif
+ dr7 |= (DR_LEN_4 << DR_CONTROL_SHIFT);
+ dr7 |= (1UL << DR_LOCAL_ENABLE_SHIFT);
+ dr7 |= (1UL << DR_GLOBAL_ENABLE_SHIFT);
+
+ l = ptrace (PTRACE_POKEUSER, child, offsetof (struct user, u_debugreg[7]), dr7);
+ assert_perror (errno);
+ assert (l == 0);
+
+ errno = 0;
+ l = ptrace (PTRACE_CONT, child, 0l, 0l);
+ assert_perror (errno);
+ assert (l == 0);
+
+ exit(0);
+}
+
static void
functions_sanity (void)
{
@@ -86,11 +173,36 @@ functions_sanity (void)
{
if (first_malloc_used == NULL)
{
+ fprintf (stderr,
+ "First use of malloc:\n"
+ " first_malloc_used: %p\n"
+ " malloc_f: %p\n"
+ " first_free_used: %p\n"
+ " free_f: %p\n",
+ first_malloc_used, malloc_f, first_free_used, free_f);
+ /*
+ fprintf (stderr, "Please attach debugger to pid %lu and press enter",
+ (unsigned long)getpid());
+ {
+ char buf[30];
+ fgets(buf, sizeof(buf), stdin);
+ }
+ */
first_malloc_used = malloc_f;
first_free_used = free_f;
+ fprintf (stderr, "Watching for writes to %p\n", &malloc_f);
+ set_watchpoint(&malloc_f);
}
else
{
+ fprintf (stderr,
+ "babl memory function(s) attempted switched on the fly:\n"
+ " first_malloc_used: %p\n"
+ " malloc_f: %p\n"
+ " first_free_used: %p\n"
+ " free_f: %p\n",
+ first_malloc_used, malloc_f, first_free_used, free_f);
+ abort ();
babl_fatal ("babl memory function(s) attempted switched on the fly");
}
}