/* $Id: UWgrind.c,v 1.2 2013/11/30 01:58:55 khorben Exp $ */ /* TODO: * - determine memory type on the fly (static from stack from mmap from heap...) * - track errno on all system calls * - track format string origin * - track memory not free'd (hook exit) */ #define DEBUG //#define DEBUG_MASK 0x0000000f /* all errors */ //#define DEBUG_MASK 0x00000400 /* statistics */ //#define DEBUG_MASK 0x0000040f /* statistics and errors */ //#define DEBUG_MASK 0x0000042f //#define DEBUG_MASK 0xffffffff /* everything */ #define DEBUG_MASK 0x00001400 #define ABORT_MASK 0x00000000 /* no errors */ //#define ABORT_MASK 0x0000000f /* all errors */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* macros */ /* debugging levels */ #define DL_EFD 0x0001 #define DL_EPTR 0x0002 #define DL_ESTR 0x0004 #define DL_FD 0x0010 #define DL_PTR 0x0020 #define DL_STR 0x0040 /* system */ #define DL_SYSCALL 0x0100 #define DL_WARNING 0x0200 #define DL_STATS 0x0400 /* headers */ #define DL_STDLIB_H 0x1000 #define DL_STRING_H 0x2000 #define DL_STRINGS_H 0x2000 #define DL_UNISTD_H 0x4000 #define DL_PEDANTIC 0xffffffff #ifdef DEBUG # define DPRINTF(level, x) { if((level & DEBUG_MASK) == level) _dprintf x; \ if((level & ABORT_MASK) == level) kill(getpid(), SIGSTOP); } #else # define DPRINTF(level, x) #endif /* functions */ static int _dprintf(const char * format, ...) { int ret; va_list ap; va_start(ap, format); ret = vfprintf(stderr, format, ap); va_end(ap); return ret; } /* UWgrind */ /* private */ /* types */ typedef struct _FunctionWrapper { void ** ptr; char * name; char * symbol; size_t count; } FunctionWrapper; typedef enum _FunctionName { FN_BZERO = 0, FN_CALLOC, FN_CHDIR, FN_CLOSE, FN_EXIT, FN_FCHDIR, FN_FREE, FN_FSTAT, FN_GETENV, FN_GETOPT, FN_LINK, FN_LSEEK, FN_LSTAT, FN_MALLOC, FN_MEMCMP, FN_MEMCPY, FN_MEMMOVE, FN_MEMSET, FN_MKDIR, FN_MKTEMP, FN_MMAP, FN_MREMAP, FN_MUNMAP, FN_OPEN, FN_READ, FN_READLINK, FN_REALLOC, FN_RECV, FN_RMDIR, FN_SEND, FN_SHMGET, FN_SOCKET, FN_STAT, FN_STRCAT, FN_STRCMP, FN_STRCPY, FN_STRDUP, FN_STRLEN, FN_STRNCPY, FN_STRNDUP, FN_SYMLINK, FN_UNLINK, FN_WRITE, } FunctionName; #define FN_LAST FN_WRITE #define FN_COUNT (FN_LAST + 1) typedef enum _PointerType { PT_HEAP = 0, PT_MMAP } PointerType; #define PT_LAST PT_MMAP #define PT_COUNT (PT_LAST + 1) typedef struct _Pointer { void * ptr; size_t size; PointerType type; } Pointer; /* variables */ /* internal */ static int _norec = 0; /* function pointers */ /* static int (*old_asprintf)(char ** ret, char * format, ...); */ static void (*old_bzero)(void * b, size_t len); static void * (*old_calloc)(size_t number, size_t size); static int (*old_chdir)(const char * path); static int (*old_close)(int fd); static void (*old_exit)(int status); static int (*old_fchdir)(int fd); static void (*old_free)(void * ptr); static int (*old_fstat)(int fd, struct stat * st); static char * (*old_getenv)(const char * name); static int (*old_getopt)(int argc, char * const argv[], const char * optstring); static int (*old_link)(const char * name1, const char * name2); static off_t (*old_lseek)(int fd, off_t offset, int whence); static int (*old_lstat)(const char * path, struct stat * st); static void * (*old_malloc)(size_t size); static int (*old_memcmp)(const void * b1, const void * b2, size_t len); static void * (*old_memcpy)(void * dst, const void * src, size_t len); static void * (*old_memmove)(void * dst, const void * src, size_t len); static void * (*old_memset)(void * b, int c, size_t len); static int (*old_mkdir)(const char * path, mode_t mode); static char * (*old_mktemp)(char * template); static void * (*old_mmap)(void * addr, size_t len, int prot, int flags, int fd, off_t offset); static void * (*old_mremap)(void * oldp, size_t oldsize, void * newp, size_t newsize, int flags); static int (*old_munmap)(void * addr, size_t len); static int (*old_open)(const char * path, int flags, mode_t mode); static ssize_t (*old_read)(int fd, void * buf, size_t nbytes); static ssize_t (*old_readlink)(const char * path, char * buf, size_t size); static void * (*old_realloc)(void * ptr, size_t size); static ssize_t (*old_recv)(int fd, void * buf, size_t len, int flags); static int (*old_rmdir)(const char * path); static ssize_t (*old_send)(int fd, const void * buf, size_t len, int flags); static int (*old_shmget)(key_t key, size_t size, int shmflg); static int (*old_socket)(int domain, int type, int protocol); static int (*old_stat)(const char * path, struct stat * st); static char * (*old_strcat)(char * s, const char * append); static int (*old_strcmp)(const char * s1, const char * s2); static char * (*old_strcpy)(char * dst, const char * src); static char * (*old_strdup)(const char * str); static size_t (*old_strlen)(const char * str); static char * (*old_strncpy)(char * dst, const char * src, size_t len); static char * (*old_strndup)(const char * str, size_t len); static int (*old_symlink)(const char * name1, const char * name2); static int (*old_unlink)(const char * path); static ssize_t (*old_write)(int fd, const void * buf, size_t nbytes); #define FW(a) { (void*)&old_ ## a, # a, # a, 0 }, FunctionWrapper _fw[FN_COUNT] = { FW(bzero) FW(calloc) FW(chdir) FW(close) FW(exit) FW(fchdir) FW(free) #ifdef __NetBSD__ { (void*)&old_fstat, "fstat", "__fstat30", 0 }, #else FW(fstat) #endif FW(getenv) FW(getopt) FW(link) FW(lseek) #ifdef __NetBSD__ { (void*)&old_lstat, "lstat", "__lstat30", 0 }, #else FW(lstat) #endif FW(malloc) FW(memcmp) FW(memcpy) FW(memmove) FW(memset) FW(mkdir) FW(mktemp) FW(mmap) FW(mremap) FW(munmap) FW(open) FW(read) FW(readlink) FW(realloc) FW(recv) FW(rmdir) FW(send) FW(shmget) #ifdef __NetBSD__ { (void*)&old_socket, "socket", "__socket30", 0 }, #else FW(socket) #endif #ifdef __NetBSD__ { (void*)&old_stat, "stat", "__stat30", 0 }, #else FW(stat) #endif FW(strcat) FW(strcmp) FW(strcpy) FW(strdup) FW(strlen) FW(strncpy) FW(strndup) FW(symlink) FW(unlink) FW(write) }; /* file descriptors */ static int * _fd = NULL; static size_t _fd_cnt = 0; /* pointers */ static const char * sPointerType[PT_COUNT] = { "heap", "mmapped" }; static Pointer * _ptr = NULL; static size_t _ptr_cnt = 0; static intptr_t _heap; static intptr_t _stack; /* functions */ /* prototypes */ static void _fd_check(int fd); static void _fd_close(int fd); static void _fd_open(int fd); static void _ptr_alloc(void * ptr, size_t size, PointerType type); static void _ptr_check(void * ptr); static void _ptr_read(const void * ptr, size_t size); static void _ptr_free(void * ptr); static void _ptr_write(const void * ptr, size_t size); /* UWgrind_enter */ static void _UWgrind_enter(FunctionName name) { static void * hdl = NULL; #ifdef __Linux__ static char libc[] = "/lib/libc.so.6"; #else static char libc[] = "/lib/libc.so"; #endif int i; assert(_norec == 0); _norec = 1; _fw[name].count++; if(hdl != NULL) return; if((hdl = dlopen(libc, RTLD_LAZY)) == NULL) old_exit(1); for(i = 0; i < FN_COUNT; i++) if((*(_fw[i].ptr) = dlsym(hdl, _fw[i].symbol)) == NULL) old_exit(1); dlclose(hdl); /* file descriptors */ _fd_open(0); _fd_open(1); _fd_open(2); /* pointers */ _heap = (intptr_t)old_malloc(1); _stack = (intptr_t)(&i) | 0xffff; DPRINTF(DL_PEDANTIC, ("INFO: heap is @%p, stack is @%p\n", _heap, _stack)); } /* UWgrind_stats */ static void _UWgrind_stats(void) { size_t i; for(i = 0; i < FN_COUNT; i++) { if(_fw[i].count == 0) continue; DPRINTF(DL_STATS, ("%s called %zu time(s)\n", _fw[i].name, _fw[i].count)); } DPRINTF(DL_STATS, ("%zu block(s) are still allocated\n", _ptr_cnt)); } /* UWgrind_leave */ static void _UWgrind_leave(void) { _norec = 0; } /* UWgrind_error */ void _UWgrind_error(const char * message) { fputs("UWgrind: ", stderr); perror(message); } /* file descriptors */ static void _fd_check(int fd) { size_t i; if(fd < 0) { DPRINTF(DL_EFD, ("ERROR: invalid fd %d\n", fd)); return; } for(i = 0; i < _fd_cnt; i++) if(fd == _fd[i]) return; DPRINTF(DL_EFD, ("ERROR: fd %d is not opened\n", fd)); } static void _fd_close(int fd) { size_t i; int * p; if(fd < 0) { DPRINTF(DL_EFD, ("ERROR: invalid fd %d\n", fd)); return; } for(i = 0; i < _fd_cnt; i++) if(_fd[i] == fd) break; if(i == _fd_cnt) { DPRINTF(DL_EFD, ("ERROR: fd %d is not opened\n", fd)); return; } _fd_cnt--; old_memmove(&_fd[i], &_fd[i + 1], sizeof(*_fd) * (_fd_cnt - i)); if((p = old_realloc(_fd, sizeof(*_fd) * _fd_cnt)) == NULL) _UWgrind_error("realloc"); else _fd = p; } static void _fd_open(int fd) { size_t i; int * p; if(fd < 0) { DPRINTF(DL_EFD, ("ERROR: invalid fd %d\n", fd)); return; } for(i = 0; i < _fd_cnt; i++) if(_fd[i] == fd) { DPRINTF(DL_EFD, ("ERROR: fd %d is already opened\n", fd)); return; } if((p = old_realloc(_fd, sizeof(*_fd) * (_fd_cnt + 1))) == NULL) { _UWgrind_error("realloc"); return; } _fd = p; _fd[_fd_cnt++] = fd; } /* pointers */ static void _ptr_alloc(void * ptr, size_t size, PointerType type) { size_t i; Pointer * p; if(ptr == NULL) { DPRINTF(DL_EPTR, ("%s%s%s", "ERROR: ", sPointerType[type], " allocation returned NULL\n")); return; } for(i = 0; i < _ptr_cnt; i++) if(_ptr[i].ptr == ptr) { DPRINTF(DL_EPTR, ("ERROR: %s pointer %p is already" " allocated\n", sPointerType[type], ptr)); return; } if((p = old_realloc(_ptr, sizeof(*_ptr) * (_ptr_cnt + 1))) == NULL) { _UWgrind_error("realloc"); return; } _ptr = p; _ptr[_ptr_cnt].ptr = ptr; _ptr[_ptr_cnt].size = size; _ptr[_ptr_cnt++].type = type; } static void _ptr_check(void * ptr) { size_t i; for(i = 0; i < _ptr_cnt; i++) if(ptr >= _ptr[i].ptr && ptr < _ptr[i].ptr + _ptr[i].size) return; DPRINTF(DL_EPTR, ("ERROR: pointer %p is not allocated\n", ptr)); } static void _ptr_free(void * ptr) { size_t i; Pointer * p; if(ptr == NULL) { DPRINTF(DL_PEDANTIC, ("ERROR: pointer %p is not valid\n", ptr)); return; } for(i = 0; i < _ptr_cnt; i++) if(_ptr[i].ptr == ptr) break; if(i == _ptr_cnt) { DPRINTF(DL_EPTR, ("ERROR: pointer %p is not allocated\n", ptr)); return; } _ptr_cnt--; old_memmove(&_ptr[i], &_ptr[i + 1], sizeof(*_ptr) * (_ptr_cnt - i)); if((p = old_realloc(_ptr, sizeof(*_ptr) * _ptr_cnt)) == NULL) _UWgrind_error("realloc"); else _ptr = p; } void _ptr_read(const void * ptr, size_t size) { size_t i; if(ptr < _stack && ptr > &i) { DPRINTF(DL_PTR, ("DEBUG: reading stack %zu@%p\n", size, ptr)); if(ptr + size <= &i) DPRINTF(DL_EPTR, ("ERROR: stack read overflow %zu@%p" " (@%p)\n", size, ptr, &i)); return; } for(i = 0; i < _ptr_cnt; i++) if(_ptr[i].ptr <= ptr && _ptr[i].ptr + _ptr[i].size > ptr) break; if(i < _ptr_cnt) { DPRINTF(DL_PTR, ("DEBUG: reading %s %zu@%p\n", sPointerType[_ptr[i].type], size, ptr)); if(ptr + size > _ptr[i].ptr + _ptr[i].size) DPRINTF(DL_EPTR, ("ERROR: %s read overflow %zu@%p" " (%zu@%p)\n", sPointerType[_ptr[i].type], size, ptr, _ptr[i].size, _ptr[i].ptr)); return; } DPRINTF(DL_PTR, ("DEBUG: reading %zu@%p\n", size, ptr)); } void _ptr_write(const void * ptr, size_t size) { size_t i; if(ptr < _stack && ptr > &i) { DPRINTF(DL_PTR, ("DEBUG: writing stack %zu@%p\n", size, ptr)); if(ptr + size <= &i) DPRINTF(DL_EPTR, ("ERROR: stack write overflow %zu@%p" " (@%p)\n", size, ptr, &i)); return; } for(i = 0; i < _ptr_cnt; i++) if(_ptr[i].ptr <= ptr && _ptr[i].ptr + _ptr[i].size > ptr) /* FIXME detect offsets inside allocated memory, * small offsets before, ... */ break; if(i < _ptr_cnt) { DPRINTF(DL_PTR, ("DEBUG: writing %s %zu@%p\n", sPointerType[_ptr[i].type], size, ptr)); if(ptr + size > _ptr[i].ptr + _ptr[i].size) DPRINTF(DL_EPTR, ("ERROR: %s write overflow %zu@%p" " (%zu@%p)\n", sPointerType[_ptr[i].type], size, ptr, _ptr[i].size, _ptr[i].ptr)); return; } DPRINTF(DL_PTR, ("DEBUG: writing %zu@%p\n", size, ptr)); } /* strings */ void _str_check(const char * str) { _ptr_read(str, old_strlen(str) + 1); } /* public */ /* TODO: * - everything that manipulates pointers, buffers... * *_r * asprintf */ /* bzero */ void bzero(void * b, size_t len) { if(_norec) return old_bzero(b, len); _UWgrind_enter(FN_BZERO); _ptr_write(b, len); old_bzero(b, len); DPRINTF(DL_STRINGS_H, ("CALL: bzero(%p, %zu)\n", b, len)); _UWgrind_leave(); } /* calloc */ void * calloc(size_t number, size_t size) { void * ret; if(_norec) return old_calloc(number, size); _UWgrind_enter(FN_CALLOC); ret = old_calloc(number, size); DPRINTF(DL_STDLIB_H, ("CALL: calloc(%zu, %zu) => %p\n", number, size, ret)); _ptr_alloc(ret, number * size, PT_HEAP); _UWgrind_leave(); return ret; } /* chdir */ int chdir(const char * path) { int ret; if(_norec) return old_chdir(path); _UWgrind_enter(FN_CHDIR); ret = old_chdir(path); DPRINTF(DL_SYSCALL, ("CALL: chdir(\"%s\") => %d\n", path, ret)); _UWgrind_leave(); return ret; } /* close */ int close(int fd) { int ret; if(_norec) return old_close(fd); _UWgrind_enter(FN_CLOSE); _fd_close(fd); ret = old_close(fd); DPRINTF(DL_SYSCALL, ("CALL: close(%d) => %d\n", fd, ret)); _UWgrind_leave(); return ret; } /* exit */ void exit(int status) { if(_norec) { old_exit(status); _exit(status); } _UWgrind_enter(FN_EXIT); _UWgrind_stats(); DPRINTF(DL_SYSCALL, ("CALL: exit(%d)\n", status)); old_exit(status); _UWgrind_leave(); } /* fchdir */ int fchdir(int fd) { int ret; if(_norec) return old_fchdir(fd); _UWgrind_enter(FN_FCHDIR); _fd_check(fd); ret = old_fchdir(fd); DPRINTF(DL_SYSCALL, ("CALL: fchdir(%d) => %d\n", fd, ret)); _UWgrind_leave(); return ret; } /* fclose * feof * fgetpos * fgets * fileno * fopen * fprintf * fread */ /* free */ void free(void * ptr) { if(_norec) return old_free(ptr); _UWgrind_enter(FN_FREE); old_free(ptr); DPRINTF(DL_STDLIB_H, ("CALL: free(%p)\n", ptr)); _ptr_free(ptr); _UWgrind_leave(); } /* freopen * fseek * fsetpos * ftell * fwrite */ /* fstat */ int fstat(int fd, struct stat * st) { int ret; if(_norec) return old_fstat(fd, st); _UWgrind_enter(FN_FSTAT); _fd_check(fd); _ptr_write(st, sizeof(*st)); ret = old_fstat(fd, st); DPRINTF(DL_SYSCALL, ("CALL: fstat(%d, %p) => %d\n", fd, st, ret)); _UWgrind_leave(); return ret; } /* getenv */ char * getenv(const char * name) { char * ret; if(_norec) return old_getenv(name); _UWgrind_enter(FN_GETENV); _str_check(name); ret = old_getenv(name); DPRINTF(DL_STDLIB_H, ("CALL: getenv(\"%s\") => %p\n", name, ret)); _UWgrind_leave(); return ret; } /* getopt */ int getopt(int argc, char * const argv[], const char * optstring) { int ret; if(_norec) return old_getopt(argc, argv, optstring); _UWgrind_enter(FN_GETOPT); ret = old_getopt(argc, argv, optstring); DPRINTF(DL_UNISTD_H, ("CALL: getopt(%d, %p, \"%s\") => %d\n", argc, argv, optstring, ret)); _UWgrind_leave(); return ret; } /* link */ int link(const char * name1, const char * name2) { int ret; if(_norec) return old_link(name1, name2); _UWgrind_enter(FN_LINK); _str_check(name1); _str_check(name2); ret = old_link(name1, name2); DPRINTF(DL_SYSCALL, ("CALL: link(\"%s\", \"%s\") => %d\n", name1, name2, ret)); _UWgrind_leave(); return ret; } /* lseek */ off_t lseek(int fd, off_t offset, int whence) { off_t ret; if(_norec) return old_lseek(fd, offset, whence); _UWgrind_enter(FN_LSEEK); _fd_check(fd); ret = old_lseek(fd, offset, whence); DPRINTF(DL_SYSCALL, ("CALL: lseek(%d, %zd, %d) => %zd\n", fd, offset, whence, ret)); _UWgrind_leave(); return ret; } /* lstat */ int lstat(const char * path, struct stat * st) { int ret; if(_norec) return old_lstat(path, st); _UWgrind_enter(FN_LSTAT); _str_check(path); _ptr_write(st, sizeof(*st)); ret = old_lstat(path, st); DPRINTF(DL_SYSCALL, ("CALL: lstat(\"%s\", %p) => %d\n", path, st, ret)); _UWgrind_leave(); return ret; } /* malloc */ void * malloc(size_t size) { void * ret; if(_norec) return old_malloc(size); _UWgrind_enter(FN_MALLOC); ret = old_malloc(size); DPRINTF(DL_STDLIB_H, ("CALL: malloc(%zu) => %p\n", size, ret)); if(ret == NULL) return ret; _ptr_alloc(ret, size, PT_HEAP); _UWgrind_leave(); return ret; } /* memcmp */ int memcmp(const void * b1, const void * b2, size_t len) { int ret; if(_norec) return old_memcmp(b1, b2, len); _UWgrind_enter(FN_MEMCMP); ret = old_memcmp(b1, b2, len); _ptr_read(b2, len); _ptr_read(b1, len); DPRINTF(DL_STRING_H, ("CALL: memcmp(%p, %p, %zu) => %d\n", b1, b2, len, ret)); _UWgrind_leave(); return ret; } /* memcpy */ void * memcpy(void * dst, const void * src, size_t len) { void * ret; if(_norec) return old_memcpy(dst, src, len); _UWgrind_enter(FN_MEMCPY); _ptr_read(src, len); _ptr_write(dst, len); if(src == dst || (dst < src && dst + len > src) || (src < dst && src + len > dst)) DPRINTF(DL_PTR, ("ERROR: potential memory corruption @%p\n", dst)); ret = old_memcpy(dst, src, len); DPRINTF(DL_STRING_H, ("CALL: memcpy(%p, %p, %zu) => %p\n", dst, src, len, ret)); _UWgrind_leave(); return ret; } /* memmove */ void * memmove(void * dst, const void * src, size_t len) { void * ret; if(_norec) return old_memmove(dst, src, len); _UWgrind_enter(FN_MEMMOVE); _ptr_read(src, len); _ptr_write(dst, len); ret = old_memmove(dst, src, len); DPRINTF(DL_STRING_H, ("CALL: memmove(%p, %p, %zu) => %p\n", dst, src, len, ret)); _UWgrind_leave(); return ret; } /* memset */ void * memset(void * b, int c, size_t len) { void * ret; if(_norec) return old_memset(b, c, len); _UWgrind_enter(FN_MEMSET); if(len == 0) DPRINTF(DL_WARNING, ("%s", "WARNING: zero-length memset\n")); _ptr_write(b, len); ret = old_memset(b, c, len); DPRINTF(DL_STRING_H, ("CALL: memset(%p, %d, %zu) => %p\n", b, c, len, ret)); _UWgrind_leave(); return ret; } /* mkdir */ int mkdir(const char * path, mode_t mode) { int ret; if(_norec) return old_mkdir(path, mode); _UWgrind_enter(FN_MKDIR); _str_check(path); ret = old_mkdir(path, mode); DPRINTF(DL_SYSCALL, ("CALL: mkdir(\"%s\", %o) => %d\n", path, mode, ret)); _UWgrind_leave(); return ret; } /* mktemp */ char * mktemp(char * template) { char * ret; if(_norec) return old_mktemp(template); _UWgrind_enter(FN_MKTEMP); ret = old_mktemp(template); DPRINTF(DL_STDLIB_H, ("CALL: mktemp(\"%s\") => \"%s\"\n", ret)); _UWgrind_leave(); return ret; } /* mmap */ void * mmap(void * addr, size_t len, int prot, int flags, int fd, off_t offset) { void * ret; if(_norec) return old_mmap(addr, len, prot, flags, fd, offset); _UWgrind_enter(FN_MMAP); if((flags & MAP_ANON) != MAP_ANON) _fd_check(fd); ret = old_mmap(addr, len, prot, flags, fd, offset); DPRINTF(DL_SYSCALL, ("CALL: mmap(%p, %zu, %d, %d, %d, %zd) => %p\n", addr, len, prot, flags, fd, offset)); if(ret != MAP_FAILED) _ptr_alloc(ret, len, PT_MMAP); _UWgrind_leave(); return ret; } /* mremap */ void * mremap(void * oldp, size_t oldsize, void * newp, size_t newsize, int flags) { void * ret; if(_norec) return old_mremap(oldp, oldsize, newp, newsize, flags); _UWgrind_enter(FN_MREMAP); ret = old_mremap(oldp, oldsize, newp, newsize, flags); DPRINTF(DL_SYSCALL, ("CALL: mremap(%p, %zu, %p, %zu, %d) => %p\n", oldp, oldsize, newp, newsize, flags, ret)); if(ret != MAP_FAILED) { _ptr_free(oldp); _ptr_alloc(ret, newsize, PT_MMAP); } _UWgrind_leave(); return ret; } /* munmap */ int munmap(void * addr, size_t len) { int ret; if(_norec) return old_munmap(addr, len); _UWgrind_enter(FN_MUNMAP); ret = old_munmap(addr, len); DPRINTF(DL_SYSCALL, ("CALL: munmap(%p, %zu) => %d\n", addr, len, ret)); if(ret == 0) _ptr_free(addr); _UWgrind_leave(); return ret; } /* open */ int open(const char * path, int flags, mode_t mode) { int ret; if(_norec) return old_open(path, flags, mode); _UWgrind_enter(FN_OPEN); if((ret = old_open(path, flags, mode)) >= 0) _fd_open(ret); DPRINTF(DL_SYSCALL, ("CALL: open(\"%s\", %d, %o) => %d\n", path, flags, mode, ret)); _UWgrind_leave(); return ret; } /* printf */ /* read */ ssize_t read(int fd, void * buf, size_t nbytes) { ssize_t ret; if(_norec) return old_read(fd, buf, nbytes); _UWgrind_enter(FN_READ); _fd_check(fd); _ptr_write(buf, nbytes); ret = old_read(fd, buf, nbytes); DPRINTF(DL_SYSCALL, ("CALL: read(%d, %p, %zu) => %zd\n", fd, buf, nbytes, ret)); _UWgrind_leave(); return ret; } /* readlink */ ssize_t readlink(const char * path, char * buf, size_t size) { ssize_t ret; if(_norec) return old_readlink(path, buf, size); _UWgrind_enter(FN_READLINK); _str_check(path); _ptr_write(buf, size); ret = old_readlink(path, buf, size); DPRINTF(DL_SYSCALL, ("CALL: readlink(\"%s\", %p, %zu) => %zd\n", path, buf, size, ret)); _UWgrind_leave(); return ret; } /* realloc */ void * realloc(void * ptr, size_t size) { void * ret; if(_norec) return old_realloc(ptr, size); _UWgrind_enter(FN_REALLOC); if(ptr != NULL) _ptr_check(ptr); if(size == 0) DPRINTF(DL_WARNING, ("%s", "WARNING: zero-size realloc()\n")); ret = old_realloc(ptr, size); DPRINTF(DL_STDLIB_H, ("CALL: realloc(%p, %zu) => %p\n", ptr, size, ret)); if(ret == NULL) { if(size == 0) _ptr_free(ptr); _UWgrind_leave(); return ret; } _ptr_free(ptr); _ptr_alloc(ret, size, PT_HEAP); _UWgrind_leave(); return ret; } /* recv */ ssize_t recv(int fd, void * buf, size_t len, int flags) { ssize_t ret; if(_norec) return old_recv(fd, buf, len, flags); _UWgrind_enter(FN_RECV); _fd_check(fd); _ptr_write(buf, len); ret = old_recv(fd, buf, len, flags); DPRINTF(DL_SYSCALL, ("CALL: recv(%d, %p, %zu, %d) => %zd\n", fd, buf, len, flags, ret)); _UWgrind_leave(); return ret; } /* rmdir */ int rmdir(const char * path) { int ret; if(_norec) return old_rmdir(path); _UWgrind_enter(FN_RMDIR); _str_check(path); ret = old_rmdir(path); DPRINTF(DL_SYSCALL, ("CALL: rmdir(%p \"%s\") => %d\n", path, path, ret)); _UWgrind_leave(); return ret; } /* send */ ssize_t send(int fd, const void * buf, size_t len, int flags) { ssize_t ret; if(_norec) return old_send(fd, buf, len, flags); _UWgrind_enter(FN_SEND); _fd_check(fd); _ptr_read(buf, len); ret = old_send(fd, buf, len, flags); DPRINTF(DL_SYSCALL, ("CALL: send(%d, %p, %zu, %d) => %zd\n", fd, buf, len, flags, ret)); _UWgrind_leave(); return ret; } /* setenv */ /* shmget */ int shmget(key_t key, size_t size, int shmflg) { int ret; if(_norec) return old_shmget(key, size, shmflg); _UWgrind_enter(FN_SHMGET); ret = old_shmget(key, size, shmflg); DPRINTF(DL_SYSCALL, ("CALL: shmget(%u, %zu, %d) => %d\n", key, size, shmflg, ret)); _UWgrind_leave(); return ret; } /* snprintf */ /* socket */ int socket(int domain, int type, int protocol) { int ret; if(_norec) return old_socket(domain, type, protocol); _UWgrind_enter(FN_SOCKET); ret = old_socket(domain, type, protocol); DPRINTF(DL_SYSCALL, ("CALL: socket(%d, %d, %d) => %d\n", domain, type, protocol, ret)); if(ret != -1) _fd_open(ret); _UWgrind_leave(); return ret; } /* sprintf */ /* stat */ int stat(const char * path, struct stat * st) { int ret; if(_norec) return old_stat(path, st); _UWgrind_enter(FN_STAT); _str_check(path); _ptr_write(st, sizeof(*st)); ret = old_stat(path, st); DPRINTF(DL_SYSCALL, ("CALL: stat(%p \"%s\", %p) => %d\n", path, path, st, ret)); _UWgrind_leave(); return ret; } /* swab */ /* strcat */ char * strcat(char * s, const char * append) { char * ret; if(_norec) return old_strcat(s, append); _UWgrind_enter(FN_STRCAT); _str_check(s); _str_check(append); ret = old_strcat(s, append); DPRINTF(DL_STRING_H, ("CALL: strcat(%p \"%s\", %p \"%s\") => \"%s\"\n", s, s, append, append, ret)); if(ret != NULL) _str_check(ret); _UWgrind_leave(); return ret; } /* strcmp */ int strcmp(const char * s1, const char * s2) { int ret; if(_norec) return old_strcmp(s1, s2); _UWgrind_enter(FN_STRCMP); _str_check(s1); _str_check(s2); ret = old_strcmp(s1, s2); DPRINTF(DL_STRING_H, ("CALL: strcmp(%p \"%s\", %p \"%s\") => %d\n", s1, s1, s2, s2, ret)); _UWgrind_leave(); return ret; } /* strcpy */ char * strcpy(char * dst, const char * src) { size_t len; char * ret; if(_norec) return old_strcpy(dst, src); _UWgrind_enter(FN_STRCPY); len = old_strlen(src) + 1; _ptr_read(src, len); _ptr_write(dst, len); ret = old_strcpy(dst, src); DPRINTF(DL_STRING_H, ("CALL: strcpy(%p \"%s\", %p \"%s\") => %p\n", dst, dst, src, src, ret)); _UWgrind_leave(); return ret; } /* strdup */ char * strdup(const char * str) { char * ret; size_t len; if(_norec) return old_strdup(str); _UWgrind_enter(FN_STRDUP); len = old_strlen(str) + 1; _ptr_read(str, len); ret = old_strdup(str); DPRINTF(DL_STRING_H, ("CALL: strdup(%p \"%s\") => %p\n", str, str, ret)); if(ret != NULL) _ptr_alloc(ret, len, PT_HEAP); _UWgrind_leave(); return ret; } /* strlen */ size_t strlen(const char * str) { /* static int norec = 0; */ size_t ret; if(_norec) return old_strlen(str); /* if(norec) return old_strlen(str); norec = 1; */ _UWgrind_enter(FN_STRLEN); ret = old_strlen(str); _ptr_read(str, ret + 1); DPRINTF(DL_STRING_H, ("CALL: strlen(%p \"%s\") => %zu\n", str, str, ret)); /* norec = 0; */ _UWgrind_leave(); return ret; } /* strncat * strncmp */ /* strncpy */ char * strncpy(char * dst, const char * src, size_t len) { char * ret; if(_norec) return old_strncpy(dst, src, len); _UWgrind_enter(FN_STRNCPY); _ptr_read(src, len); _ptr_write(dst, len); ret = old_strncpy(dst, src, len); DPRINTF(DL_STRING_H, ("CALL: strcpy(%p \"%s\", %p \"%s\", %zu)" " => %p\n", dst, dst, src, src, len, ret)); _UWgrind_leave(); return ret; } /* strndup */ char * strndup(const char * str, size_t len) { char * ret; if(_norec) return old_strndup(str, len); _UWgrind_enter(FN_STRNDUP); _str_check(str); /* FIXME check with maximum length of len */ ret = old_strndup(str, len); DPRINTF(DL_STRING_H, ("CALL: strndup(%p \"%s\", %zu) => %p\n", str, str, len, ret)); _ptr_alloc(ret, len, PT_HEAP); /* FIXME check with maximum length of len */ _UWgrind_leave(); return ret; } /* symlink */ int symlink(const char * name1, const char * name2) { int ret; if(_norec) return old_symlink(name1, name2); _UWgrind_enter(FN_SYMLINK); _str_check(name1); _str_check(name2); ret = old_symlink(name1, name2); DPRINTF(DL_SYSCALL, ("CALL: symlink(%p \"%s\", %p \"%s\") => %p\n", name1, name1, name2, name2, ret)); _UWgrind_leave(); return ret; } /* unlink */ int unlink(const char * path) { int ret; if(_norec) return old_unlink(path); _str_check(path); _UWgrind_enter(FN_UNLINK); ret = old_unlink(path); DPRINTF(DL_SYSCALL, ("CALL: unlink(%p \"%s\") => %d\n", path, path, ret)); _UWgrind_leave(); return ret; } /* vasprintf * vfprintf * vprintf * vsnprintf * vsprintf */ /* write */ ssize_t write(int fd, const void * buf, size_t nbytes) { ssize_t ret; if(_norec) return old_write(fd, buf, nbytes); _UWgrind_enter(FN_WRITE); _fd_check(fd); _ptr_read(buf, nbytes); ret = old_write(fd, buf, nbytes); DPRINTF(DL_SYSCALL, ("CALL: write(%d, %p, %zu) => %zd\n", fd, buf, nbytes, ret)); _UWgrind_leave(); return ret; }