#define kakka /*
set -x
g++ -W -Wall -O2 -g -pg -shared -fpic -ldl memcpy_wrap.c -o memcpy_wrap.so
exit
*/

extern "C" {

#include <stdlib.h>
#include <dlfcn.h> 

#include <execinfo.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int _memcpy_wrap_backtrace_flag = 1;

static const size_t maxstack = 15;
static const size_t maxstr = 256;

static __thread int __fd = -1;


static void __close_backtrace()
{
	close(__fd);
	__fd = -2;
}

static void __print_backtrace(void *a, void *b, size_t par)
{
	static __thread int recursion_protect = 0;
	
	if(recursion_protect)
		return;
	recursion_protect = 1;
	
	/* FIXME: insert mutex here */
	
	void *pstack[maxstack];
	size_t n = backtrace(pstack, maxstack);
	
	if(__fd == -1)
	{
		/* FIXME: file name? */
		__fd = open("mcpytrace.txt",
			O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, S_IWUSR|S_IRUSR);
		if(__fd != -1)
			atexit(__close_backtrace);
	}
	if(__fd < 0)
		goto go_out;

	char str[maxstr];
	int bytes = snprintf(str, maxstr, "-- -- -- %lu bytes, %p -> %p\n",
		par, b, a);
	write(__fd, str, bytes);
	if(n>0)
		backtrace_symbols_fd(&pstack[1], n-1, __fd);

go_out:
	recursion_protect = 0;
}

void *memcpy(void *dest, void *src, size_t n)
{
	static void *(*real_memcpy)(void*, void*, size_t) = NULL;
	
	if(!real_memcpy)
	{
		real_memcpy = (void*(*)(void*, void*, size_t))dlsym(
			RTLD_NEXT, "memcpy");
		if(!real_memcpy)
		{
			puts("symbol 'memcpy' not found");
			exit(EXIT_FAILURE);
		}
	}
	if(_memcpy_wrap_backtrace_flag)
		__print_backtrace(dest, src, n);
	
	return real_memcpy(dest, src, n);
}

}

