This commit is contained in:
mrbesen 2022-06-24 00:52:59 +02:00
commit 0601b95da3
Signed by: MrBesen
GPG Key ID: 596B2350DCD67504
5 changed files with 265 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.so
*.txt
*.log

13
Makefile Normal file
View File

@ -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

15
Readme.md Normal file
View File

@ -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

60
getcaller.cpp Normal file
View File

@ -0,0 +1,60 @@
// compile with: g++ -rdynamic -c -std=c++11 -o caller.o getcaller.cpp
#include <string>
#include <execinfo.h>
#define BT_BUF_SIZE 10
#include <memory.h>
#include <stdlib.h>
#include <sstream>
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);
}

174
trace.cpp Normal file
View File

@ -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 <dlfcn.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string>
#include <sys/socket.h>
#define O_WRONLY 01
#define O_CREAT 0100
#define O_TRUNC 01000
// #include <fcntl.h> // 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;
}
}