1376 lines
38 KiB
C
1376 lines
38 KiB
C
/*
|
|
gcc -O2 mtrack.c -shared -o mtrack.so -ldl -pthread
|
|
*/
|
|
#ifndef _GNU_SOURCE
|
|
# define _GNU_SOURCE
|
|
#endif
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <dlfcn.h>
|
|
#include <execinfo.h>
|
|
#include <pthread.h>
|
|
|
|
#ifdef __GNUC__
|
|
# if __GNUC__ >= 4
|
|
# define EAPI __attribute__ ((visibility("default")))
|
|
# else
|
|
# define EAPI
|
|
# endif
|
|
#else
|
|
# define EAPI
|
|
#endif
|
|
|
|
static void _mhook_do_init(void);
|
|
|
|
/*============================================================================*
|
|
* Local *
|
|
*============================================================================*/
|
|
|
|
enum {
|
|
MHOOK_NONE = 0,
|
|
MHOOK_FILL = 1,
|
|
MHOOK_TRACE = 2,
|
|
MHOOK_TRACK = 3,
|
|
MHOOK_DEBUG = 4
|
|
};
|
|
|
|
/**
|
|
* @cond LOCAL
|
|
*/
|
|
|
|
#define MHOOK_CANARY_MAGIC 0xf0
|
|
|
|
static int _mhook_mode = MHOOK_NONE;
|
|
|
|
static unsigned char _mhook_fill_pat_malloc = 0xaa;
|
|
static unsigned char _mhook_fill_pat_free = 0xbb;
|
|
|
|
static unsigned char _mhook_canary_size = 0x00;
|
|
static unsigned char _mhook_canary = 0xfe;
|
|
|
|
static int _mhook_trace_fd = -1;
|
|
static int _mhook_track_fd = -1;
|
|
|
|
static unsigned char _mhook_buf[256];
|
|
static int _mhook_first = 1;
|
|
|
|
static void *(*_mhook_orig_malloc) (size_t) = NULL;
|
|
static void (*_mhook_orig_free) (void *) = NULL;
|
|
static void *(*_mhook_orig_realloc) (void *, size_t) = NULL;
|
|
static void *(*_mhook_orig_memalign) (size_t, size_t) = NULL;
|
|
static void *(*_mhook_orig_calloc) (size_t, size_t) = NULL;
|
|
|
|
static pthread_mutex_t lk;
|
|
|
|
/**
|
|
* @endcond
|
|
*/
|
|
|
|
/*============================================================================*
|
|
* Global *
|
|
*============================================================================*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* memory null implementation */
|
|
|
|
static void *
|
|
_mhook_null_malloc(size_t size)
|
|
{
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (!_mhook_orig_malloc) return _mhook_buf;
|
|
result = _mhook_orig_malloc(size);
|
|
return result;
|
|
}
|
|
|
|
static void
|
|
_mhook_null_free(void *ptr)
|
|
{
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (ptr == _mhook_buf) return;
|
|
_mhook_orig_free(ptr);
|
|
}
|
|
|
|
static void *
|
|
_mhook_null_realloc(void *ptr, size_t size)
|
|
{
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (ptr == _mhook_buf)
|
|
{
|
|
fprintf(stderr, "mtrack: realloc()ing initial _mhook_buf\n");
|
|
abort();
|
|
}
|
|
result = _mhook_orig_realloc(ptr, size);
|
|
return result;
|
|
}
|
|
|
|
static void *
|
|
_mhook_null_memalign(size_t alignment, size_t size)
|
|
{
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (!_mhook_orig_memalign) return _mhook_buf;
|
|
result = _mhook_orig_memalign(alignment, size);
|
|
return result;
|
|
}
|
|
|
|
static void *
|
|
_mhook_null_calloc(size_t nmemb, size_t size)
|
|
{
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (!_mhook_orig_malloc)
|
|
{
|
|
memset(_mhook_buf, 0, nmemb * size);
|
|
return _mhook_buf;
|
|
}
|
|
result = _mhook_orig_calloc(nmemb, size);
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* memory filler implementation */
|
|
#define MHOOK_FILL_HEADER_SPACE (sizeof(void *) * 2)
|
|
typedef struct _Mhook_Mem_Fill
|
|
{
|
|
size_t size;
|
|
void *magic;
|
|
} Mhook_Mem_Fill;
|
|
|
|
static void *
|
|
_mhook_fill_malloc(size_t size)
|
|
{
|
|
Mhook_Mem_Fill *m;
|
|
size_t ms = size + MHOOK_FILL_HEADER_SPACE;
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (!_mhook_orig_malloc) return _mhook_buf;
|
|
m = _mhook_orig_malloc(ms);
|
|
if (m)
|
|
{
|
|
memset(m, _mhook_fill_pat_malloc, MHOOK_FILL_HEADER_SPACE);
|
|
result = ((unsigned char *)m) + MHOOK_FILL_HEADER_SPACE;
|
|
m->size = size;
|
|
memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
|
|
memset(result, _mhook_fill_pat_malloc, size);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static void
|
|
_mhook_fill_free(void *ptr)
|
|
{
|
|
Mhook_Mem_Fill *m;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (ptr == _mhook_buf) return;
|
|
if (ptr)
|
|
{
|
|
m = (Mhook_Mem_Fill *)(((unsigned char *)ptr) - MHOOK_FILL_HEADER_SPACE);
|
|
memset(ptr, _mhook_fill_pat_free, m->size);
|
|
memset(m, _mhook_fill_pat_free, MHOOK_FILL_HEADER_SPACE);
|
|
_mhook_orig_free(m);
|
|
}
|
|
}
|
|
|
|
static void *
|
|
_mhook_fill_realloc(void *ptr, size_t size)
|
|
{
|
|
Mhook_Mem_Fill *m, *mold;
|
|
void *result = NULL;
|
|
size_t ms = size + MHOOK_FILL_HEADER_SPACE;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (ptr == _mhook_buf)
|
|
{
|
|
fprintf(stderr, "mtrack: realloc()ing initial _mhook_buf\n");
|
|
abort();
|
|
}
|
|
if (size == 0)
|
|
{
|
|
if (ptr)
|
|
{
|
|
m = (Mhook_Mem_Fill *)(((unsigned char *)ptr) - MHOOK_FILL_HEADER_SPACE);
|
|
memset(ptr, _mhook_fill_pat_free, m->size);
|
|
memset(m, _mhook_fill_pat_free, MHOOK_FILL_HEADER_SPACE);
|
|
_mhook_orig_free(m);
|
|
}
|
|
}
|
|
else if (ptr)
|
|
{
|
|
m = _mhook_orig_malloc(ms);
|
|
if (m)
|
|
{
|
|
mold = (Mhook_Mem_Fill *)(((unsigned char *)ptr) - MHOOK_FILL_HEADER_SPACE);
|
|
|
|
memset(m, _mhook_fill_pat_malloc, MHOOK_FILL_HEADER_SPACE);
|
|
result = ((unsigned char *)m) + MHOOK_FILL_HEADER_SPACE;
|
|
m->size = size;
|
|
memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
|
|
if (mold->size < m->size)
|
|
{
|
|
memcpy(result, ptr, mold->size);
|
|
memset(((unsigned char *)result) + mold->size,
|
|
_mhook_fill_pat_malloc, m->size - mold->size);
|
|
}
|
|
else
|
|
memcpy(result, ptr, m->size);
|
|
|
|
memset(ptr, _mhook_fill_pat_free, mold->size);
|
|
memset(mold, _mhook_fill_pat_free, MHOOK_FILL_HEADER_SPACE);
|
|
_mhook_orig_free(mold);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m = _mhook_orig_malloc(ms);
|
|
if (m)
|
|
{
|
|
result = ((unsigned char *)m) + MHOOK_FILL_HEADER_SPACE;
|
|
m->size = size;
|
|
memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
|
|
memset(result, _mhook_fill_pat_malloc, size);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static void *
|
|
_mhook_fill_memalign(size_t alignment, size_t size)
|
|
{
|
|
Mhook_Mem_Fill *m;
|
|
size_t ms = size + MHOOK_FILL_HEADER_SPACE + alignment;
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (!_mhook_orig_memalign) return _mhook_buf;
|
|
m = _mhook_orig_malloc(ms);
|
|
if (m)
|
|
{
|
|
unsigned char *p = ((unsigned char *)m) + MHOOK_FILL_HEADER_SPACE;
|
|
unsigned char *palign;
|
|
size_t align, mask = ~(alignment - 1);
|
|
|
|
palign = (unsigned char *)((unsigned long)((p + (alignment - 1))) & mask);
|
|
align = palign - p;
|
|
memset(m, _mhook_fill_pat_malloc, align);
|
|
result = ((unsigned char *)m) + align;
|
|
m->size = size;
|
|
memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
|
|
memset(result, _mhook_fill_pat_malloc, size);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static void *
|
|
_mhook_fill_calloc(size_t nmemb, size_t size)
|
|
{
|
|
Mhook_Mem_Fill *m;
|
|
size_t ms = (size * nmemb) + MHOOK_FILL_HEADER_SPACE;
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (!_mhook_orig_malloc)
|
|
{
|
|
memset(_mhook_buf, 0, nmemb * size);
|
|
return _mhook_buf;
|
|
}
|
|
m = _mhook_orig_malloc(ms);
|
|
if (m)
|
|
{
|
|
memset(m, _mhook_fill_pat_malloc, MHOOK_FILL_HEADER_SPACE);
|
|
result = ((unsigned char *)m) + MHOOK_FILL_HEADER_SPACE;
|
|
m->size = nmemb * size;
|
|
memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
|
|
memset(result, 0, nmemb * size);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* memory trace implementation */
|
|
|
|
static void
|
|
_mhook_trace_log(const char *str)
|
|
{
|
|
void *bt[256];
|
|
char buf[16384], *p;
|
|
int n, skip, i, tot;
|
|
static int inside = 0;
|
|
|
|
if (inside)
|
|
{
|
|
if (write(_mhook_trace_fd, str, strlen(str)) < 0) perror("write");
|
|
if (write(_mhook_trace_fd, " XX\n", 4) < 0) perror("write");
|
|
return;
|
|
}
|
|
inside = 1;
|
|
tot = sizeof(buf);
|
|
strcpy(buf, str);
|
|
p = buf + strlen(str); tot -= p - buf;
|
|
n = backtrace(bt, 250);
|
|
strcpy(p, " =="); p += 3; tot -= 3;
|
|
if (n > 0)
|
|
{
|
|
skip = 3;
|
|
|
|
for (i = skip; i < n; i++)
|
|
{
|
|
int len = 0;
|
|
Dl_info info;
|
|
|
|
if (dladdr(bt[i], &info))
|
|
{
|
|
if (info.dli_sname)
|
|
{
|
|
len = strlen(info.dli_sname);
|
|
p[0] = ' ';
|
|
strcpy(p + 1, info.dli_sname);
|
|
len = 1 + len;
|
|
}
|
|
else
|
|
{
|
|
strcpy(p, " #");
|
|
len = 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strcpy(p, " ?");
|
|
len = 2;
|
|
}
|
|
p += len; tot -= len;
|
|
}
|
|
}
|
|
p[0] = '\n'; p += 1; tot -= 1;
|
|
if (write(_mhook_trace_fd, buf, p - buf) < 0) perror("write");
|
|
inside = 0;
|
|
}
|
|
|
|
static void
|
|
intstr(unsigned long value, char *str, int radix)
|
|
{
|
|
static char dig[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
int n = 0, neg = 0;
|
|
unsigned long v;
|
|
char *p, *q;
|
|
char c;
|
|
|
|
if ((radix == 10) && (value < 0))
|
|
{
|
|
value = -value;
|
|
neg = 1;
|
|
}
|
|
v = value;
|
|
do
|
|
{
|
|
str[n++] = dig[v % radix];
|
|
v /= radix;
|
|
}
|
|
while (v);
|
|
if (neg) str[n++] = '-';
|
|
str[n] = 0;
|
|
for (p = str, q = p + (n - 1); p < q; p++, q--)
|
|
{
|
|
c = *p; *p = *q; *q = c;
|
|
}
|
|
}
|
|
static void *
|
|
_mhook_trace_malloc(size_t size)
|
|
{
|
|
char buf[256], b[64];
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (!_mhook_orig_malloc) return _mhook_buf;
|
|
result = _mhook_orig_malloc(size);
|
|
strcpy(buf, "M ");
|
|
intstr((unsigned long)size, b, 16);
|
|
strcat(buf, b);
|
|
strcat(buf, " > ");
|
|
intstr((unsigned long)result, b, 16);
|
|
strcat(buf, b);
|
|
_mhook_trace_log(buf);
|
|
return result;
|
|
}
|
|
|
|
static void
|
|
_mhook_trace_free(void *ptr)
|
|
{
|
|
char buf[256], b[64];
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (ptr == _mhook_buf) return;
|
|
_mhook_orig_free(ptr);
|
|
strcpy(buf, "F ");
|
|
intstr((unsigned long)ptr, b, 16);
|
|
strcat(buf, b);
|
|
_mhook_trace_log(buf);
|
|
}
|
|
|
|
static void *
|
|
_mhook_trace_realloc(void *ptr, size_t size)
|
|
{
|
|
char buf[256], b[64];
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (ptr == _mhook_buf)
|
|
{
|
|
fprintf(stderr, "mtrack: realloc()ing initial _mhook_buf\n");
|
|
abort();
|
|
}
|
|
result = _mhook_orig_realloc(ptr, size);
|
|
strcpy(buf, "R ");
|
|
intstr((unsigned long)ptr, b, 16);
|
|
strcat(buf, b);
|
|
strcat(buf, " ");
|
|
intstr((unsigned long)size, b, 16);
|
|
strcat(buf, b);
|
|
strcat(buf, " > ");
|
|
intstr((unsigned long)result, b, 16);
|
|
strcat(buf, b);
|
|
_mhook_trace_log(buf);
|
|
return result;
|
|
}
|
|
|
|
static void *
|
|
_mhook_trace_memalign(size_t alignment, size_t size)
|
|
{
|
|
char buf[256], b[64];
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (!_mhook_orig_memalign) return _mhook_buf;
|
|
result = _mhook_orig_memalign(alignment, size);
|
|
strcpy(buf, "A ");
|
|
intstr((unsigned long)alignment, b, 16);
|
|
strcat(buf, b);
|
|
strcat(buf, " ");
|
|
intstr((unsigned long)size, b, 16);
|
|
strcat(buf, b);
|
|
strcat(buf, " > ");
|
|
intstr((unsigned long)result, b, 16);
|
|
strcat(buf, b);
|
|
_mhook_trace_log(buf);
|
|
return result;
|
|
}
|
|
|
|
static void *
|
|
_mhook_trace_calloc(size_t nmemb, size_t size)
|
|
{
|
|
char buf[256], b[64];
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (!_mhook_orig_malloc)
|
|
{
|
|
memset(_mhook_buf, 0, nmemb * size);
|
|
return _mhook_buf;
|
|
}
|
|
result = _mhook_orig_calloc(nmemb, size);
|
|
strcpy(buf, "C ");
|
|
intstr((unsigned long)(nmemb * size), b, 16);
|
|
strcat(buf, b);
|
|
strcat(buf, " > ");
|
|
intstr((unsigned long)result, b, 16);
|
|
strcat(buf, b);
|
|
_mhook_trace_log(buf);
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* memory tracker implementation */
|
|
#define MALLOC (void *)0
|
|
#define REALLOC (void *)1
|
|
#define CALLOC (void *)2
|
|
#define MEMALIGN (void *)3
|
|
|
|
#define MHOOK_TRACK_HEADER_SPACE (sizeof(void *) * 80)
|
|
typedef struct _Mhook_Mem_Track Mhook_Mem_Track;
|
|
|
|
struct _Mhook_Mem_Track
|
|
{
|
|
size_t size;
|
|
void *type;
|
|
void *magic;
|
|
void *bt[64];
|
|
int btnum;
|
|
time_t alloctime;
|
|
Mhook_Mem_Track *prev, *next;
|
|
};
|
|
|
|
static Mhook_Mem_Track *mems = NULL;
|
|
static int allocs = 0;
|
|
static int frees = 0;
|
|
static int recurse = 0;
|
|
|
|
#define BAD_CANARY \
|
|
fprintf(stderr, "BAD CANARY for %p\n", ptr); \
|
|
if (getenv("MTRACK_CANARY_ABORT")) abort(); \
|
|
return
|
|
|
|
static void
|
|
_mhook_track_dump(void)
|
|
{
|
|
Mhook_Mem_Track *m;
|
|
|
|
if (ftruncate(_mhook_track_fd, 0) < 0) perror("truncate");
|
|
for (m = mems; m; m = m->next)
|
|
{
|
|
char buf[512];
|
|
int i;
|
|
|
|
char *type[] = { "MALLOC", "REALLOC", "CALLOC", "MEMALIGN" };
|
|
snprintf(buf, sizeof(buf), "== %s %lu @ %lu\n",
|
|
type[(unsigned long)m->type],
|
|
(unsigned long)m->size,
|
|
(unsigned long)m->alloctime);
|
|
if (write(_mhook_track_fd, buf, strlen(buf)) < 0)
|
|
perror("write");
|
|
if (m->btnum > 0)
|
|
backtrace_symbols_fd(m->bt, m->btnum, _mhook_track_fd);
|
|
}
|
|
}
|
|
|
|
static void *
|
|
_mhook_track_malloc(size_t size)
|
|
{
|
|
Mhook_Mem_Track *m;
|
|
size_t ms = size + MHOOK_TRACK_HEADER_SPACE;
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (!_mhook_orig_malloc) return _mhook_buf;
|
|
recurse++;
|
|
m = _mhook_orig_malloc(ms);
|
|
if (m)
|
|
{
|
|
memset(m, _mhook_fill_pat_malloc, MHOOK_TRACK_HEADER_SPACE);
|
|
result = ((unsigned char *)m) + MHOOK_TRACK_HEADER_SPACE;
|
|
m->size = size;
|
|
memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
|
|
memset(result, _mhook_fill_pat_malloc, size);
|
|
memset(m->bt, 0, sizeof(m->bt));
|
|
if (recurse < 2)
|
|
{
|
|
m->btnum = backtrace
|
|
(m->bt, sizeof(m->bt) / sizeof(void *));
|
|
m->alloctime = time(NULL);
|
|
}
|
|
m->next = m->prev = NULL;
|
|
m->type = MALLOC;
|
|
m->next = mems;
|
|
if (mems) mems->prev = m;
|
|
mems = m;
|
|
allocs++;
|
|
}
|
|
recurse--;
|
|
// printf("MALLOC %p\n", result);fflush(stdout);
|
|
return result;
|
|
}
|
|
|
|
static void
|
|
_mhook_track_free(void *ptr)
|
|
{
|
|
Mhook_Mem_Track *m;
|
|
|
|
if (ptr == _mhook_buf) return;
|
|
recurse++;
|
|
if (ptr)
|
|
{
|
|
void *magic;
|
|
memset(&(magic), MHOOK_CANARY_MAGIC, sizeof(void *));
|
|
m = (Mhook_Mem_Track *)(((unsigned char *)ptr) - MHOOK_TRACK_HEADER_SPACE);
|
|
if (memcmp(&magic, &m->magic, sizeof(void *)))
|
|
{
|
|
BAD_CANARY;
|
|
}
|
|
if (m->prev) m->prev->next = m->next;
|
|
else mems = m->next;
|
|
if (m->next) m->next->prev = m->prev;
|
|
memset(ptr, _mhook_fill_pat_free, m->size);
|
|
memset(m, _mhook_fill_pat_free, MHOOK_TRACK_HEADER_SPACE);
|
|
_mhook_orig_free(m);
|
|
frees++;
|
|
}
|
|
// printf("FREE %p\n", ptr);fflush(stdout);
|
|
recurse--;
|
|
}
|
|
|
|
static void *
|
|
_mhook_track_realloc(void *ptr, size_t size)
|
|
{
|
|
Mhook_Mem_Track *m, *mold;
|
|
void *result = NULL;
|
|
size_t ms = size + MHOOK_TRACK_HEADER_SPACE;
|
|
|
|
if (ptr == _mhook_buf)
|
|
{
|
|
fprintf(stderr, "mtrack: realloc()ing initial _mhook_buf\n");
|
|
abort();
|
|
}
|
|
recurse++;
|
|
if (size == 0)
|
|
{
|
|
if (ptr)
|
|
{
|
|
void *magic;
|
|
memset(&(magic), MHOOK_CANARY_MAGIC, sizeof(void *));
|
|
m = (Mhook_Mem_Track *)(((unsigned char *)ptr) - MHOOK_TRACK_HEADER_SPACE);
|
|
if (memcmp(&magic, &m->magic, sizeof(void *)))
|
|
{
|
|
BAD_CANARY NULL;
|
|
}
|
|
if (m->prev) m->prev->next = m->next;
|
|
else mems = m->next;
|
|
if (m->next) m->next->prev = m->prev;
|
|
memset(ptr, _mhook_fill_pat_free, m->size);
|
|
memset(m, _mhook_fill_pat_free, MHOOK_TRACK_HEADER_SPACE);
|
|
_mhook_orig_free(m);
|
|
frees++;
|
|
// printf("R1:FREE %p\n", ptr);fflush(stdout);
|
|
}
|
|
}
|
|
else if (ptr)
|
|
{
|
|
m = _mhook_orig_malloc(ms);
|
|
if (m)
|
|
{
|
|
void *magic;
|
|
mold = (Mhook_Mem_Track *)(((unsigned char *)ptr) - MHOOK_TRACK_HEADER_SPACE);
|
|
memset(&(magic), MHOOK_CANARY_MAGIC, sizeof(void *));
|
|
if (memcmp(&magic, &mold->magic, sizeof(void *)))
|
|
{
|
|
BAD_CANARY NULL;
|
|
}
|
|
|
|
memset(m, _mhook_fill_pat_malloc, MHOOK_TRACK_HEADER_SPACE);
|
|
result = ((unsigned char *)m) + MHOOK_TRACK_HEADER_SPACE;
|
|
m->size = size;
|
|
memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
|
|
if (mold->size < m->size)
|
|
{
|
|
memcpy(result, ptr, mold->size);
|
|
memset(((unsigned char *)result) + mold->size, _mhook_fill_pat_malloc, m->size - mold->size);
|
|
}
|
|
else
|
|
memcpy(result, ptr, m->size);
|
|
|
|
memset(m->bt, 0, sizeof(m->bt));
|
|
if (recurse < 2)
|
|
{
|
|
m->btnum = backtrace
|
|
(m->bt, sizeof(m->bt) / sizeof(void *));
|
|
m->alloctime = time(NULL);
|
|
}
|
|
m->type = REALLOC;
|
|
|
|
m->next = m->prev = NULL;
|
|
m->next = mems;
|
|
if (mems) mems->prev = m;
|
|
mems = m;
|
|
|
|
if (mold->prev) mold->prev->next = mold->next;
|
|
else mems = mold->next;
|
|
if (mold->next) mold->next->prev = mold->prev;
|
|
memset(ptr, _mhook_fill_pat_free, mold->size);
|
|
memset(mold, _mhook_fill_pat_free, MHOOK_TRACK_HEADER_SPACE);
|
|
_mhook_orig_free(mold);
|
|
allocs++;
|
|
frees++;
|
|
// printf("R2:FREE %p\n", ptr);fflush(stdout);
|
|
// printf("R2:MALLOC %p\n", result);fflush(stdout);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m = _mhook_orig_malloc(ms);
|
|
if (m)
|
|
{
|
|
result = ((unsigned char *)m) + MHOOK_TRACK_HEADER_SPACE;
|
|
m->size = size;
|
|
memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
|
|
memset(result, _mhook_fill_pat_malloc, size);
|
|
memset(m->bt, 0, sizeof(m->bt));
|
|
if (recurse < 2)
|
|
{
|
|
m->btnum = backtrace
|
|
(m->bt, sizeof(m->bt) / sizeof(void *));
|
|
m->alloctime = time(NULL);
|
|
}
|
|
m->type = REALLOC;
|
|
m->next = m->prev = NULL;
|
|
m->next = mems;
|
|
if (mems) mems->prev = m;
|
|
mems = m;
|
|
allocs++;
|
|
// printf("R3:MALLOC %p\n", result);fflush(stdout);
|
|
}
|
|
}
|
|
recurse--;
|
|
return result;
|
|
}
|
|
|
|
static void *
|
|
_mhook_track_memalign(size_t alignment, size_t size)
|
|
{
|
|
Mhook_Mem_Track *m;
|
|
size_t ms;
|
|
void *result = NULL;
|
|
|
|
if (alignment < 1) alignment = 1;
|
|
ms = size + MHOOK_TRACK_HEADER_SPACE + alignment;
|
|
if (!_mhook_orig_memalign) return _mhook_buf;
|
|
recurse++;
|
|
m = _mhook_orig_malloc(ms);
|
|
if (m)
|
|
{
|
|
// unsigned char *p = ((unsigned char *)m) + MHOOK_TRACK_HEADER_SPACE;
|
|
// unsigned char *palign;
|
|
// size_t align, mask = ~(alignment - 1);
|
|
|
|
// align = MHOOK_TRACK_HEADER_SPACE;
|
|
// for now lets never align as asked
|
|
// palign = (unsigned char *)((unsigned long)((p + (alignment - 1))) & mask);
|
|
// align = palign - p;
|
|
// memset(m, _mhook_fill_pat_malloc, align);
|
|
// result = ((unsigned char *)m) + align;
|
|
memset(m, _mhook_fill_pat_malloc, MHOOK_TRACK_HEADER_SPACE);
|
|
result = ((unsigned char *)m) + MHOOK_TRACK_HEADER_SPACE;
|
|
m->size = size;
|
|
memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
|
|
memset(result, _mhook_fill_pat_malloc, size);
|
|
memset(m->bt, 0, sizeof(m->bt));
|
|
if (recurse < 2)
|
|
{
|
|
m->btnum = backtrace
|
|
(m->bt, sizeof(m->bt) / sizeof(void *));
|
|
m->alloctime = time(NULL);
|
|
}
|
|
m->type = MEMALIGN;
|
|
m->next = m->prev = NULL;
|
|
m->next = mems;
|
|
if (mems) mems->prev = m;
|
|
mems = m;
|
|
allocs++;
|
|
}
|
|
recurse--;
|
|
// printf("MEMALIGN %p\n", result);fflush(stdout);
|
|
return result;
|
|
}
|
|
|
|
static void *
|
|
_mhook_track_calloc(size_t nmemb, size_t size)
|
|
{
|
|
Mhook_Mem_Track *m;
|
|
size_t ms = (size * nmemb) + MHOOK_TRACK_HEADER_SPACE;
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (!_mhook_orig_malloc)
|
|
{
|
|
memset(_mhook_buf, 0, nmemb * size);
|
|
return _mhook_buf;
|
|
}
|
|
recurse++;
|
|
m = _mhook_orig_malloc(ms);
|
|
if (m)
|
|
{
|
|
memset(m, _mhook_fill_pat_malloc, MHOOK_TRACK_HEADER_SPACE);
|
|
result = ((unsigned char *)m) + MHOOK_TRACK_HEADER_SPACE;
|
|
m->size = nmemb * size;
|
|
memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
|
|
memset(result, 0, nmemb * size);
|
|
memset(m->bt, 0, sizeof(m->bt));
|
|
if (recurse < 2)
|
|
{
|
|
m->btnum = backtrace
|
|
(m->bt, sizeof(m->bt) / sizeof(void *));
|
|
m->alloctime = time(NULL);
|
|
}
|
|
m->type = CALLOC;
|
|
m->next = m->prev = NULL;
|
|
m->next = mems;
|
|
if (mems) mems->prev = m;
|
|
mems = m;
|
|
allocs++;
|
|
}
|
|
recurse--;
|
|
// printf("CALLOC %p\n", result);fflush(stdout);
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* memory debug implementation */
|
|
#define MHOOK_DEBUG_CANARY_SPACE (_mhook_canary_size * 8)
|
|
#define MHOOK_DEBUG_HEADER_SPACE ((sizeof(void *) * 4) + MHOOK_DEBUG_CANARY_SPACE)
|
|
typedef struct _Mhook_Mem_Debug
|
|
{
|
|
size_t size;
|
|
unsigned char *realptr;
|
|
void *magic;
|
|
void *blah;
|
|
} Mhook_Mem_Debug;
|
|
|
|
#define MHOOK_DEBUG_FREEBUF_SIZE (1024 * 256)
|
|
//#define MHOOK_DEBUG_FREEBUF_SIZE (1)
|
|
|
|
static unsigned int _mhook_debug_freebuf_slot = 0;
|
|
static void *_mhook_debug_freebuf[MHOOK_DEBUG_FREEBUF_SIZE] = { NULL };
|
|
|
|
static void
|
|
_mhook_debug_canary_check(Mhook_Mem_Debug *m)
|
|
{
|
|
unsigned char *head = ((unsigned char *)m) + (sizeof(void *) * 4);
|
|
unsigned char *tail = head + MHOOK_DEBUG_CANARY_SPACE + m->size;
|
|
int i;
|
|
|
|
for (i = 0; i < (_mhook_canary_size * 8); i++)
|
|
{
|
|
if (head[i] != _mhook_canary)
|
|
{
|
|
fprintf(stderr, "CANARY ERROR HEAD @ %p = %x\n",
|
|
head + MHOOK_DEBUG_CANARY_SPACE, head[i]);
|
|
abort();
|
|
}
|
|
}
|
|
for (i = 0; i < (_mhook_canary_size * 8); i++)
|
|
{
|
|
if (tail[i] != _mhook_canary)
|
|
{
|
|
fprintf(stderr, "CANARY ERROR TAIL @ %p = %x\n",
|
|
head + MHOOK_DEBUG_CANARY_SPACE, tail[i]);
|
|
abort();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
_mhook_debug_canary_fill(void *ptr, size_t size)
|
|
{
|
|
unsigned char *head = ptr;
|
|
unsigned char *tail = ptr;
|
|
head -= MHOOK_DEBUG_CANARY_SPACE;
|
|
tail += size;
|
|
|
|
memset(head, _mhook_canary, MHOOK_DEBUG_CANARY_SPACE);
|
|
memset(tail, _mhook_canary, MHOOK_DEBUG_CANARY_SPACE);
|
|
}
|
|
|
|
static void
|
|
_mhook_debug_free_check(void *ptr, size_t size)
|
|
{
|
|
size_t i;
|
|
unsigned char *p = ptr;
|
|
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
if (p[i] != _mhook_fill_pat_free)
|
|
{
|
|
fprintf(stderr, "CANARY ERROR BODY @ %p = %x\n",
|
|
ptr, p[i]);
|
|
abort();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
_mhook_debug_magic_fill(Mhook_Mem_Debug *m)
|
|
{
|
|
m->blah = (void *)0xf0f0f0f0;
|
|
memset(&(m->magic), MHOOK_CANARY_MAGIC, sizeof(void *));
|
|
}
|
|
|
|
static void
|
|
_mhook_debug_real_free(void *ptr)
|
|
{
|
|
Mhook_Mem_Debug *m;
|
|
unsigned char *realptr;
|
|
size_t psize;
|
|
|
|
m = (Mhook_Mem_Debug *)(((unsigned char *)ptr) - MHOOK_DEBUG_HEADER_SPACE);
|
|
realptr = m->realptr;
|
|
psize = m->size;
|
|
// fprintf(stderr, "real free %p size %lu @ slot %i\n", ptr, psize, _mhook_debug_freebuf_slot);
|
|
_mhook_debug_canary_check(m);
|
|
_mhook_debug_free_check(ptr, psize);
|
|
memset(m, _mhook_fill_pat_free, MHOOK_DEBUG_HEADER_SPACE);
|
|
memset(((unsigned char *)ptr) + psize, _mhook_fill_pat_free, MHOOK_DEBUG_CANARY_SPACE);
|
|
_mhook_orig_free(realptr);
|
|
}
|
|
|
|
static void
|
|
_mhook_debug_free2(void *ptr)
|
|
{
|
|
// _mhook_debug_real_free(ptr);
|
|
// return;
|
|
|
|
_mhook_debug_freebuf[_mhook_debug_freebuf_slot] = ptr;
|
|
_mhook_debug_freebuf_slot++;
|
|
if (_mhook_debug_freebuf_slot >= MHOOK_DEBUG_FREEBUF_SIZE)
|
|
{
|
|
_mhook_debug_freebuf_slot = 0;
|
|
}
|
|
if (_mhook_debug_freebuf[_mhook_debug_freebuf_slot])
|
|
{
|
|
_mhook_debug_real_free(_mhook_debug_freebuf[_mhook_debug_freebuf_slot]);
|
|
_mhook_debug_freebuf[_mhook_debug_freebuf_slot] = NULL;
|
|
}
|
|
}
|
|
|
|
static void *
|
|
_mhook_debug_malloc(size_t size)
|
|
{
|
|
Mhook_Mem_Debug *m;
|
|
size_t ms = size + MHOOK_DEBUG_HEADER_SPACE + MHOOK_DEBUG_CANARY_SPACE;
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (!_mhook_orig_malloc) return _mhook_buf;
|
|
m = _mhook_orig_malloc(ms);
|
|
if (m)
|
|
{
|
|
result = ((unsigned char *)m) + MHOOK_DEBUG_HEADER_SPACE;
|
|
m->realptr = (unsigned char *)m;
|
|
m->size = size;
|
|
_mhook_debug_magic_fill(m);
|
|
memset(result, _mhook_fill_pat_malloc, size);
|
|
_mhook_debug_canary_fill(result, size);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static void
|
|
_mhook_debug_free(void *ptr)
|
|
{
|
|
Mhook_Mem_Debug *m;
|
|
size_t psize;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (ptr == _mhook_buf) return;
|
|
if (ptr)
|
|
{
|
|
m = (Mhook_Mem_Debug *)(((unsigned char *)ptr) - MHOOK_DEBUG_HEADER_SPACE);
|
|
psize = m->size;
|
|
|
|
_mhook_debug_canary_check(m);
|
|
memset(ptr, _mhook_fill_pat_free, psize);
|
|
_mhook_debug_free2(ptr);
|
|
}
|
|
}
|
|
|
|
static void *
|
|
_mhook_debug_realloc(void *ptr, size_t size)
|
|
{
|
|
Mhook_Mem_Debug *m, *mold;
|
|
void *result = NULL;
|
|
size_t ms = size + MHOOK_DEBUG_HEADER_SPACE + MHOOK_DEBUG_CANARY_SPACE;
|
|
size_t psize;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (ptr == _mhook_buf)
|
|
{
|
|
fprintf(stderr, "mtrack: realloc()ing initial _mhook_buf\n");
|
|
abort();
|
|
}
|
|
if (size == 0)
|
|
{
|
|
if (ptr)
|
|
{
|
|
m = (Mhook_Mem_Debug *)(((unsigned char *)ptr) - MHOOK_DEBUG_HEADER_SPACE);
|
|
psize = m->size;
|
|
|
|
_mhook_debug_canary_check(m);
|
|
memset(ptr, _mhook_fill_pat_free, psize);
|
|
_mhook_debug_free2(ptr);
|
|
}
|
|
}
|
|
else if (ptr)
|
|
{
|
|
m = _mhook_orig_malloc(ms);
|
|
if (m)
|
|
{
|
|
mold = (Mhook_Mem_Debug *)(((unsigned char *)ptr) - MHOOK_DEBUG_HEADER_SPACE);
|
|
psize = mold->size;
|
|
|
|
_mhook_debug_canary_check(mold);
|
|
result = ((unsigned char *)m) + MHOOK_DEBUG_HEADER_SPACE;
|
|
m->realptr = (unsigned char *)m;
|
|
m->size = size;
|
|
_mhook_debug_magic_fill(m);
|
|
_mhook_debug_canary_fill(result, size);
|
|
|
|
if (psize < size)
|
|
{
|
|
memcpy(result, ptr, psize);
|
|
memset(((unsigned char *)result) + psize,
|
|
_mhook_fill_pat_malloc, size - psize);
|
|
}
|
|
else memcpy(result, ptr, size);
|
|
|
|
_mhook_debug_canary_check(mold);
|
|
memset(ptr, _mhook_fill_pat_free, psize);
|
|
_mhook_debug_free2(ptr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m = _mhook_orig_malloc(ms);
|
|
if (m)
|
|
{
|
|
result = ((unsigned char *)m) + MHOOK_DEBUG_HEADER_SPACE;
|
|
m->realptr = (unsigned char *)m;
|
|
m->size = size;
|
|
_mhook_debug_magic_fill(m);
|
|
memset(result, _mhook_fill_pat_malloc, size);
|
|
_mhook_debug_canary_fill(result, size);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static void *
|
|
_mhook_debug_memalign(size_t alignment, size_t size)
|
|
{
|
|
Mhook_Mem_Debug *m;
|
|
size_t ms = size + MHOOK_DEBUG_HEADER_SPACE + MHOOK_DEBUG_CANARY_SPACE + alignment;
|
|
unsigned char *mem;
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (!_mhook_orig_memalign) return _mhook_buf;
|
|
mem = _mhook_orig_malloc(ms);
|
|
if (mem)
|
|
{
|
|
unsigned char *palign = mem + MHOOK_DEBUG_HEADER_SPACE;
|
|
size_t valign = ((size_t)palign) % alignment;
|
|
|
|
if (valign > 0) valign = alignment - valign;
|
|
palign += valign;
|
|
m = (Mhook_Mem_Debug *)palign - (MHOOK_DEBUG_HEADER_SPACE);
|
|
result = palign;
|
|
m->realptr = (unsigned char *)mem;
|
|
m->size = size;
|
|
_mhook_debug_magic_fill(m);
|
|
memset(result, _mhook_fill_pat_malloc, size);
|
|
_mhook_debug_canary_fill(result, size);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static void *
|
|
_mhook_debug_calloc(size_t nmemb, size_t size)
|
|
{
|
|
Mhook_Mem_Debug *m;
|
|
size_t ms = (size * nmemb) + MHOOK_DEBUG_HEADER_SPACE + MHOOK_DEBUG_CANARY_SPACE;
|
|
void *result = NULL;
|
|
|
|
// FIXME: hack around dlsym doing a malloc/calloc
|
|
if (!_mhook_orig_malloc)
|
|
{
|
|
memset(_mhook_buf, 0, nmemb * size);
|
|
return _mhook_buf;
|
|
}
|
|
m = _mhook_orig_malloc(ms);
|
|
if (m)
|
|
{
|
|
result = ((unsigned char *)m) + MHOOK_DEBUG_HEADER_SPACE;
|
|
m->realptr = (unsigned char *)m;
|
|
m->size = nmemb * size;
|
|
_mhook_debug_magic_fill(m);
|
|
memset(result, 0, nmemb * size);
|
|
_mhook_debug_canary_fill(result, nmemb * size);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
static void *
|
|
_mhook_malloc(size_t size)
|
|
{
|
|
void *result = NULL;
|
|
|
|
if (!_mhook_first) pthread_mutex_lock(&lk);
|
|
_mhook_do_init();
|
|
switch (_mhook_mode)
|
|
{
|
|
case MHOOK_NONE: result = _mhook_null_malloc(size); break;
|
|
case MHOOK_FILL: result = _mhook_fill_malloc(size); break;
|
|
case MHOOK_TRACE: result = _mhook_trace_malloc(size); break;
|
|
case MHOOK_TRACK: result = _mhook_track_malloc(size); break;
|
|
case MHOOK_DEBUG: result = _mhook_debug_malloc(size); break;
|
|
}
|
|
if (!_mhook_first) pthread_mutex_unlock(&lk);
|
|
_mhook_first = 0;
|
|
return result;
|
|
}
|
|
|
|
static void
|
|
_mhook_free(void *ptr)
|
|
{
|
|
if (!ptr) return;
|
|
if (!_mhook_first) pthread_mutex_lock(&lk);
|
|
_mhook_do_init();
|
|
switch (_mhook_mode)
|
|
{
|
|
case MHOOK_NONE: _mhook_null_free(ptr); break;
|
|
case MHOOK_FILL: _mhook_fill_free(ptr); break;
|
|
case MHOOK_TRACE: _mhook_trace_free(ptr); break;
|
|
case MHOOK_TRACK: _mhook_track_free(ptr); break;
|
|
case MHOOK_DEBUG: _mhook_debug_free(ptr); break;
|
|
}
|
|
if (!_mhook_first) pthread_mutex_unlock(&lk);
|
|
_mhook_first = 0;
|
|
}
|
|
|
|
static void *
|
|
_mhook_realloc(void *ptr, size_t size)
|
|
{
|
|
void *result = NULL;
|
|
|
|
if ((!ptr) && (size == 0)) return NULL;
|
|
if (!_mhook_first) pthread_mutex_lock(&lk);
|
|
_mhook_do_init();
|
|
switch (_mhook_mode)
|
|
{
|
|
case MHOOK_NONE: result = _mhook_null_realloc(ptr, size); break;
|
|
case MHOOK_FILL: result = _mhook_fill_realloc(ptr, size); break;
|
|
case MHOOK_TRACE: result = _mhook_trace_realloc(ptr, size); break;
|
|
case MHOOK_TRACK: result = _mhook_track_realloc(ptr, size); break;
|
|
case MHOOK_DEBUG: result = _mhook_debug_realloc(ptr, size); break;
|
|
}
|
|
if (!_mhook_first) pthread_mutex_unlock(&lk);
|
|
_mhook_first = 0;
|
|
return result;
|
|
}
|
|
|
|
static void *
|
|
_mhook_memalign(size_t alignment, size_t size)
|
|
{
|
|
void *result = NULL;
|
|
|
|
if (!_mhook_first) pthread_mutex_lock(&lk);
|
|
_mhook_do_init();
|
|
switch (_mhook_mode)
|
|
{
|
|
case MHOOK_NONE: result = _mhook_null_memalign(alignment, size); break;
|
|
case MHOOK_FILL: result = _mhook_fill_memalign(alignment, size); break;
|
|
case MHOOK_TRACE: result = _mhook_trace_memalign(alignment, size); break;
|
|
case MHOOK_TRACK: result = _mhook_track_memalign(alignment, size); break;
|
|
case MHOOK_DEBUG: result = _mhook_debug_memalign(alignment, size); break;
|
|
}
|
|
if (!_mhook_first) pthread_mutex_unlock(&lk);
|
|
_mhook_first = 0;
|
|
return result;
|
|
}
|
|
|
|
static void *
|
|
_mhook_calloc(size_t nmemb, size_t size)
|
|
{
|
|
void *result = NULL;
|
|
|
|
if (!_mhook_first) pthread_mutex_lock(&lk);
|
|
_mhook_do_init();
|
|
switch (_mhook_mode)
|
|
{
|
|
case MHOOK_NONE: result = _mhook_null_calloc(nmemb, size); break;
|
|
case MHOOK_FILL: result = _mhook_fill_calloc(nmemb, size); break;
|
|
case MHOOK_TRACE: result = _mhook_trace_calloc(nmemb, size); break;
|
|
case MHOOK_TRACK: result = _mhook_track_calloc(nmemb, size); break;
|
|
case MHOOK_DEBUG: result = _mhook_debug_calloc(nmemb, size); break;
|
|
}
|
|
if (!_mhook_first) pthread_mutex_unlock(&lk);
|
|
_mhook_first = 0;
|
|
return result;
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
static void
|
|
_mhook_signal(int sig, siginfo_t *si, void *foo)
|
|
{
|
|
switch (_mhook_mode)
|
|
{
|
|
case MHOOK_NONE: break;
|
|
case MHOOK_FILL: break;
|
|
case MHOOK_TRACE: break;
|
|
case MHOOK_TRACK: _mhook_track_dump(); break;
|
|
case MHOOK_DEBUG: break;
|
|
}
|
|
return;
|
|
sig = 0; si = NULL; foo = NULL;
|
|
}
|
|
|
|
/*============================================================================*
|
|
* API *
|
|
*============================================================================*/
|
|
|
|
static void
|
|
_mhook_init(void)
|
|
{
|
|
const char *s = getenv("MTRACK");
|
|
pthread_mutexattr_t attr;
|
|
pthread_mutexattr_init(&attr);
|
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
|
pthread_mutex_init(&lk, &attr);
|
|
if (s)
|
|
{
|
|
if (!strcmp(s, "fill"))
|
|
{
|
|
_mhook_mode = MHOOK_FILL;
|
|
s = getenv("MTRACK_ALLOC_FILL");
|
|
if (s) _mhook_fill_pat_malloc = atoi(s);
|
|
s = getenv("MTRACK_FREE_FILL");
|
|
if (s) _mhook_fill_pat_free = atoi(s);
|
|
}
|
|
else if (!strcmp(s, "debug"))
|
|
{
|
|
_mhook_mode = MHOOK_DEBUG;
|
|
s = getenv("MTRACK_ALLOC_FILL");
|
|
if (s) _mhook_fill_pat_malloc = atoi(s);
|
|
s = getenv("MTRACK_FREE_FILL");
|
|
if (s) _mhook_fill_pat_free = atoi(s);
|
|
s = getenv("MTRACK_CANARY_SIZE");
|
|
if (s) _mhook_canary_size = atoi(s);
|
|
s = getenv("MTRACK_CANARY");
|
|
if (s) _mhook_canary = atoi(s);
|
|
}
|
|
else if (!strcmp(s, "trace"))
|
|
{
|
|
_mhook_mode = MHOOK_TRACE;
|
|
s = getenv("MTRACK_TRACE_FILE");
|
|
if (s)
|
|
{
|
|
_mhook_trace_fd = open(s,
|
|
O_CREAT | O_WRONLY | O_TRUNC,
|
|
S_IRUSR | S_IWUSR);
|
|
if (_mhook_trace_fd < 0)
|
|
_mhook_mode = MHOOK_NONE;
|
|
else
|
|
{
|
|
if (fcntl(_mhook_trace_fd, F_SETFD, FD_CLOEXEC) < 0)
|
|
{
|
|
close(_mhook_trace_fd);
|
|
_mhook_trace_fd = -1;
|
|
_mhook_mode = MHOOK_NONE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(s, "track"))
|
|
{
|
|
_mhook_mode = MHOOK_TRACK;
|
|
s = getenv("MTRACK_TRACE_FILE");
|
|
if (s)
|
|
{
|
|
_mhook_track_fd = open(s,
|
|
O_CREAT | O_WRONLY | O_TRUNC,
|
|
S_IRUSR | S_IWUSR);
|
|
if (_mhook_track_fd < 0)
|
|
_mhook_mode = MHOOK_NONE;
|
|
else
|
|
{
|
|
if (fcntl(_mhook_track_fd, F_SETFD, FD_CLOEXEC) < 0)
|
|
{
|
|
close(_mhook_track_fd);
|
|
_mhook_track_fd = -1;
|
|
_mhook_mode = MHOOK_NONE;
|
|
}
|
|
else
|
|
{
|
|
struct sigaction sa;
|
|
|
|
sa.sa_sigaction = _mhook_signal;
|
|
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
|
sigemptyset(&sa.sa_mask);
|
|
sigaction(SIGURG, &sa, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else _mhook_mode = MHOOK_NONE;
|
|
}
|
|
}
|
|
|
|
EAPI void *__libc_malloc (size_t size) { return _mhook_malloc(size); }
|
|
EAPI void *malloc (size_t size) { return _mhook_malloc(size); }
|
|
EAPI void __libc_free (void *ptr) { _mhook_free(ptr); }
|
|
EAPI void free (void *ptr) { _mhook_free(ptr); }
|
|
EAPI void *__libc_realloc (void *ptr, size_t size) { return _mhook_realloc(ptr, size); }
|
|
EAPI void *realloc (void *ptr, size_t size) { return _mhook_realloc(ptr, size); }
|
|
EAPI void *__libc_memalign(size_t algn, size_t size) { return _mhook_memalign(algn, size); }
|
|
EAPI void *memalign (size_t algn, size_t size) { return _mhook_memalign(algn, size); }
|
|
EAPI void *__libc_calloc (size_t num, size_t size) { return _mhook_calloc(num, size); }
|
|
EAPI void *calloc (size_t num, size_t size) { return _mhook_calloc(num, size); }
|
|
|
|
static void
|
|
_mhook_do_init(void)
|
|
{
|
|
static int initted = 0;
|
|
|
|
if (initted) return;
|
|
unsetenv("LD_PRELOAD");
|
|
initted = 1;
|
|
_mhook_init();
|
|
_mhook_orig_malloc = dlsym(RTLD_NEXT, "__libc_malloc");
|
|
_mhook_orig_free = dlsym(RTLD_NEXT, "__libc_free");
|
|
_mhook_orig_realloc = dlsym(RTLD_NEXT, "__libc_realloc");
|
|
_mhook_orig_memalign = dlsym(RTLD_NEXT, "__libc_memalign");
|
|
_mhook_orig_calloc = dlsym(RTLD_NEXT, "__libc_calloc");
|
|
if (!_mhook_orig_malloc) _mhook_orig_malloc = dlsym(RTLD_NEXT, "malloc");
|
|
if (!_mhook_orig_free) _mhook_orig_free = dlsym(RTLD_NEXT, "free");
|
|
if (!_mhook_orig_realloc) _mhook_orig_realloc = dlsym(RTLD_NEXT, "realloc");
|
|
if (!_mhook_orig_memalign) _mhook_orig_memalign = dlsym(RTLD_NEXT, "memalign");
|
|
if (!_mhook_orig_calloc) _mhook_orig_calloc = dlsym(RTLD_NEXT, "calloc");
|
|
_mhook_first = 0;
|
|
}
|
|
/**
|
|
* @}
|
|
*/
|