commit 0601b95da3957dc6bf6373ab884f0f43fb28d9bd Author: mrbesen Date: Fri Jun 24 00:52:59 2022 +0200 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4099997 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.so +*.txt +*.log \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..508de62 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +NAME = trace.so +LDFLAGS = -ldl +CFLAGS = -rdynamic -std=c++11 -shared -fpic + +all: $(NAME) + +$(NAME): trace.cpp getcaller.cpp + g++ $(CFLAGS) -o $@ $< $(LDFLAGS) + +clean: + $(RM) -f trace.so + +.PHONY: all diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..1417be3 --- /dev/null +++ b/Readme.md @@ -0,0 +1,15 @@ +# strace + +Custom strace, that logs the calling function but only logs syscalls that open or close a fd. + +## Compile +``` +make all +``` + +## Use +```bash +TRACEOUT=trace.log LD_PRELOAD=./trace.so ./program-under-test --arg1 --arg2 .... +``` + +This does not log event or epoll fds \ No newline at end of file diff --git a/getcaller.cpp b/getcaller.cpp new file mode 100644 index 0000000..6309475 --- /dev/null +++ b/getcaller.cpp @@ -0,0 +1,60 @@ +// compile with: g++ -rdynamic -c -std=c++11 -o caller.o getcaller.cpp +#include + +#include +#define BT_BUF_SIZE 10 + +#include +#include +#include + +static int depth = 2; + +std::string demangle(std::string& in) { + if(in.size() < 5) return in; + if(in.find("_Z") > 0) return in; + + std::ostringstream out; + std::istringstream is(in.substr(2)); + bool first = true; + while(is) { + char c = is.peek(); + while(c == 'N' || c == 'K') { + is.get(); + c = is.peek(); + } + unsigned int len = 0; + is >> len; + if(len == 0) + break; + if(!first) + out << "::"; + first = false; + + char* buf = new char[len+1]; + buf[len] = '\0'; + is.read(buf, len); + out << buf; + delete[] buf; + } + return out.str(); +} + +std::string getCaller() { + if(depth+1 > BT_BUF_SIZE) return "UNKNOWN"; + void* buffer[BT_BUF_SIZE]; + int nptrs = backtrace(buffer, BT_BUF_SIZE); + + char** strings = backtrace_symbols(buffer, nptrs); + if (!strings) + return "UNKNOWN"; + std::string out(strings[depth]); + free(strings); + size_t startoffset = out.rfind('(')+1; + size_t plusoffset = out.find('+', startoffset)-1; + if(plusoffset == std::string::npos) + return "UNKNOWN"; + + out = out.substr(startoffset, plusoffset-startoffset); + return demangle(out); +} diff --git a/trace.cpp b/trace.cpp new file mode 100644 index 0000000..26007a3 --- /dev/null +++ b/trace.cpp @@ -0,0 +1,174 @@ +// compile with: g++ -rdynamic -std=c++11 -shared -o trace.so trace.cpp getgetCaller().c_str().cpp -fpic -ldl + + +#define RTLD_NEXT ((void *) -1l) +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#define O_WRONLY 01 +#define O_CREAT 0100 +#define O_TRUNC 01000 +// #include // conflicts with open() + +static int (*libc_open)(const char* path, int flags, mode_t mode) = NULL; +static int (*libc_close)(int fd) = NULL; +static int (*libc_socket)(int domain, int type, int protocol) = NULL; +static int (*libc_accept)(int sockfd, struct sockaddr *addr, socklen_t *addrlen) = NULL; +static int (*libc_accept4)(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) = NULL; + +static int (*libc_pipe)(int pipefd[2]) = NULL; +static int (*libc_pipe2)(int pipefd[2], int flags) = NULL; + +static int (*libc_dup)(int oldfd) = NULL; +static int (*libc_dup2)(int oldfd, int newfd) = NULL; +static int (*libc_dup3)(int oldfd, int newfd, int flags) = NULL; + +static int writefd = -1; + +std::string getCaller(); + +#define SETCAST(N) libc_ ## N = ( decltype(libc_ ## N) ) dlsym(RTLD_NEXT, #N) + +void init() { + if(!libc_open) { + SETCAST(open); + SETCAST(close); + SETCAST(socket); + SETCAST(accept); + SETCAST(accept4); + SETCAST(pipe); + SETCAST(pipe2); + SETCAST(dup); + SETCAST(dup2); + SETCAST(dup3); + + char* target = getenv("TRACEOUT"); + if(!target) { + writefd = STDOUT_FILENO; + return; + } + + writefd = libc_open(target, (int) O_WRONLY | O_CREAT | O_TRUNC, (mode_t) 0664); + } +} + +extern "C" { + +int open(const char* path, int flags, mode_t mode) { + init(); + + errno = 0; + int res = libc_open(path, flags, mode); + + dprintf(writefd, "%s -> open(\"%s\", %i, %o) = %i (e: %i)\n", getCaller().c_str(), path, flags, mode, res, errno); + + return res; +} + +int close(int fd) { + init(); + + errno = 0; + int res = libc_close(fd); + + dprintf(writefd, "%s -> close(%i) = %i (e: %i)\n", getCaller().c_str(), fd, res, errno); + + return res; +} + +int socket(int dom, int type, int prot) { + init(); + + errno = 0; + int res = libc_socket(dom, type, prot); + + dprintf(writefd, "%s -> socket(%i, %i, %i) = %i (e: %i)\n", getCaller().c_str(), dom, type, prot, res, errno); + + return res; +} + +int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { + init(); + + errno = 0; + int res = libc_accept(sockfd, addr, addrlen); + + dprintf(writefd, "%s -> accept(%i, x, x) = %i (e: %i)\n", getCaller().c_str(), sockfd, res, errno); + + return res; + +} + +int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) { + init(); + + errno = 0; + int res = libc_accept4(sockfd, addr, addrlen, flags); + + dprintf(writefd, "%s -> accept4(%i, x, x, %i) = %i (e: %i)\n", getCaller().c_str(), sockfd, flags, res, errno); + + return res; +} + +int pipe(int pipefd[2]) { + init(); + + errno = 0; + int res = libc_pipe(pipefd); + + dprintf(writefd, "%s -> pipe([%i, %i]) = %i (e: %i)\n", getCaller().c_str(), pipefd[0], pipefd[1], res, errno); + + return res; +} + +int pipe2(int pipefd[2], int flags) { + init(); + + errno = 0; + int res = libc_pipe2(pipefd, flags); + + dprintf(writefd, "%s -> pipe2([%i, %i], %i) = %i (e: %i)\n", getCaller().c_str(), pipefd[0], pipefd[1], flags, res, errno); + + return res; +} + +int dup(int oldfd) { + init(); + + errno = 0; + int res = libc_dup(oldfd); + + dprintf(writefd, "%s -> dup(%i) = %i (e: %i)\n", getCaller().c_str(), oldfd, res, errno); + return res; +} + +int dup2(int oldfd, int newfd) { + init(); + + errno = 0; + int res = libc_dup2(oldfd, newfd); + + dprintf(writefd, "%s -> dup2(%i, %i) = %i (e: %i)\n", getCaller().c_str(), oldfd, newfd, res, errno); + return res; +} + +int dup3(int oldfd, int newfd, int flags) { + init(); + + errno = 0; + int res = libc_dup3(oldfd, newfd, flags); + + dprintf(writefd, "%s -> dup3(%i, %i, %i) = %i (e: %i)\n", getCaller().c_str(), oldfd, newfd, flags, res, errno); + return res; +} + +}