1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
/* Counts the system calls a run makes, by standing in front of libc.
cc -O2 -shared -fPIC -o syscount.so tests/syscount.c -ldl
LD_PRELOAD=./syscount.so ./opentracker -f conf (DYLD_INSERT_LIBRARIES on macOS)
The tally goes to stderr when the process exits. Reading the source tells
you which calls a path should make; this tells you which it does make,
which is not always the same thing. */
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdarg.h>
#include <stdatomic.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef __linux__
#include <sys/epoll.h>
#endif
#define COUNTER(name) static _Atomic long g_##name
#define BUMP(name) atomic_fetch_add_explicit(&g_##name, 1, memory_order_relaxed)
#define REPORT(name) fprintf(stderr, " %-14s %10ld\n", #name, atomic_load(&g_##name))
COUNTER(accept);
COUNTER(accept4);
COUNTER(read);
COUNTER(write);
COUNTER(close);
COUNTER(fcntl);
COUNTER(recvfrom);
COUNTER(sendto);
COUNTER(epoll_ctl);
COUNTER(epoll_wait);
typedef int (*fn_accept)(int, struct sockaddr *, socklen_t *);
typedef int (*fn_accept4)(int, struct sockaddr *, socklen_t *, int);
typedef ssize_t (*fn_read)(int, void *, size_t);
typedef ssize_t (*fn_write)(int, const void *, size_t);
typedef int (*fn_close)(int);
typedef int (*fn_fcntl)(int, int, ...);
typedef ssize_t (*fn_recvfrom)(int, void *, size_t, int, struct sockaddr *, socklen_t *);
typedef ssize_t (*fn_sendto)(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
static fn_accept real_accept;
static fn_accept4 real_accept4;
static fn_read real_read;
static fn_write real_write;
static fn_close real_close;
static fn_fcntl real_fcntl;
static fn_recvfrom real_recvfrom;
static fn_sendto real_sendto;
/* Resolving lazily keeps the library out of the way until something is
actually called, which matters because dlsym itself allocates */
#define WRAP(name) \
if (!real_##name) \
real_##name = (fn_##name)dlsym(RTLD_NEXT, #name); \
BUMP(name)
int accept(int s, struct sockaddr *addr, socklen_t *len) {
WRAP(accept);
return real_accept(s, addr, len);
}
#ifdef SOCK_NONBLOCK
int accept4(int s, struct sockaddr *addr, socklen_t *len, int flags) {
WRAP(accept4);
return real_accept4(s, addr, len, flags);
}
#endif
ssize_t read(int fd, void *buf, size_t count) {
WRAP(read);
return real_read(fd, buf, count);
}
ssize_t write(int fd, const void *buf, size_t count) {
WRAP(write);
return real_write(fd, buf, count);
}
int close(int fd) {
WRAP(close);
return real_close(fd);
}
int fcntl(int fd, int cmd, ...) {
va_list args;
long arg;
va_start(args, cmd);
arg = va_arg(args, long);
va_end(args);
WRAP(fcntl);
return real_fcntl(fd, cmd, arg);
}
ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) {
WRAP(recvfrom);
return real_recvfrom(s, buf, len, flags, from, fromlen);
}
ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) {
WRAP(sendto);
return real_sendto(s, buf, len, flags, to, tolen);
}
#ifdef __linux__
typedef int (*fn_epoll_ctl)(int, int, int, struct epoll_event *);
typedef int (*fn_epoll_wait)(int, struct epoll_event *, int, int);
static fn_epoll_ctl real_epoll_ctl;
static fn_epoll_wait real_epoll_wait;
int epoll_ctl(int ep, int op, int fd, struct epoll_event *ev) {
WRAP(epoll_ctl);
return real_epoll_ctl(ep, op, fd, ev);
}
int epoll_wait(int ep, struct epoll_event *events, int max, int timeout) {
WRAP(epoll_wait);
return real_epoll_wait(ep, events, max, timeout);
}
#endif
__attribute__((destructor)) static void report(void) {
fprintf(stderr, "\n system calls this run\n");
REPORT(accept);
#ifdef SOCK_NONBLOCK
REPORT(accept4);
#endif
REPORT(read);
REPORT(write);
REPORT(close);
REPORT(fcntl);
REPORT(recvfrom);
REPORT(sendto);
#ifdef __linux__
REPORT(epoll_ctl);
REPORT(epoll_wait);
#endif
}
|