some try to get a hold on it...

however, it seems as if ld_preload changes offsets, need to find a way around this - so I can get usefull backtraces :-(

/*
 * gcc  -Wall -nostartfiles -fpic -shared -olibbacktrace.so  backtrace_open.c 
 */
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE_SOURCE

#include <dlfcn.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <errno.h>
#include <time.h>

#include <execinfo.h>


/* XXX: do parallel support for open AND open64 by #undef open etc .. */


#define RESOLVE(x)	if (!o_##x && !(o_##x = dlsym(RTLD_NEXT, #x))) { fprintf(stderr, #x"() not found!\n"); exit(-1); }

#define min(x,y) ( (x)<(y)?(x):(y) )
#define max(x,y) ( (x)>(y)?(x):(y) )

#define N_FRAMES 16

/* XXX: need to handle this differently .. linked list? */
#define HIGHEST_FD 256
#define FEAT_RANGE_SUPPORT 1

static int (*o_open64)(const char *, int, ...);
static int (*o_close)(int);

static FILE *(*o_fopen64)(const char *, const char *);
static int (*o_fclose)(FILE *);
static int (*o_socket)(int domain, int type, int protocol);
static int (*o_connect)(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

FILE *myfd = NULL;


void _init(void)
{
	RESOLVE(fopen64);

	/* CRASH! if you load us uninitialized, your process deserves to die! */
	myfd = o_fopen64(getenv("DEBUG_FILENAME"), "w+");

	fprintf(myfd, "%d: my filedescriptor.\n", fileno(myfd));
}


void oneline_backtrace(const char* CallName, const char *str1, long nFD)
{
	const long sizeofstr =
		N_FRAMES *3 + // 0x,
		sizeof(void*) * N_FRAMES * 4 + // hex number
		256;
	void *stack_frames[N_FRAMES];
	char addresslist[sizeofstr]; 
	size_t size, i;
	long offset = 0;

	offset = sprintf(addresslist, "\n%ld: [%s][", nFD, CallName);

	size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
	if (size > 0)
	{
		if (N_FRAMES > size)
			size = N_FRAMES;

		for (i = 1; i < size; i++) {
			offset += sprintf(addresslist + offset, "%p;", stack_frames[i]);
		}
	}
	offset += snprintf(addresslist + offset, sizeof(addresslist) - offset, "]\n\t%s", 
			   str1);

	fwrite(addresslist, 1, offset, myfd);
}



#define NUMBUFSIZE 60
static char numbuf[NUMBUFSIZE];
char *str_off_t(__off64_t t)
{
    char *p=numbuf+sizeof(numbuf)-1;
    int isneg=0;

    if (t < 0)
    {
        t= -t;
        isneg=1;
    }

    *p=0;
    do
    {
        *--p= '0' + (t % 10);
        t=t / 10;
    } while(t);

    if (isneg)
        *--p='-';

    return p;
}


int open64(const char *pathname, int flag, ...)
{
	int ret;
	RESOLVE(open64);

	ret = o_open64(pathname, flag);
	oneline_backtrace (__FUNCTION__, pathname, ret);
	
	return ret;
}

FILE *fopen64(const char *pathname, const char *mode)
{
	FILE *Ret;
	RESOLVE(fopen64);
	Ret = o_fopen64(pathname, mode);

	oneline_backtrace (__FUNCTION__, pathname, fileno(Ret));
	
	return Ret;
}


int socket(int domain, int type, int protocol)
{
	int ret;
	char buf[128];

	RESOLVE(socket);
	ret = o_socket(domain, type, protocol);
	snprintf(buf, sizeof(buf), "t: %d p:%d %s", 
		 type, protocol, strerror(errno));
	
	oneline_backtrace (__FUNCTION__, buf, ret);
	return ret;
}

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
	const char *what;
	int ret;
	RESOLVE(connect);

	if (addrlen == sizeof(struct sockaddr_in6))
	{
		what = " IPv6 ";
	}
	else if (addrlen == sizeof(struct sockaddr_in))
	{

		what = " IPv4 ";
	}
	else
	{
		what = " WTF? ";

	}

	ret = o_connect(sockfd, addr, addrlen);

	oneline_backtrace (__FUNCTION__, what, sockfd);

	return ret;
}


int close(int fd)
{
	oneline_backtrace (__FUNCTION__, "", fd);
	
	RESOLVE(close);
	return o_close(fd);
}

int fclose(FILE *stream)
{
	int fd;
	int ret;

	fd = fileno(stream);
	RESOLVE(fclose);
	ret = o_fclose(stream);

	oneline_backtrace (__FUNCTION__, strerror(errno), fd);
	
	return ret;
}

Reply via email to