├── .gitignore
├── .travis.yml
├── CONTRIBUTING
├── LICENSE-MIT-fluxcapacitor
├── Makefile
├── README.md
├── examples
├── sleep_sort.sh
└── slowecho
│ ├── run_test.py
│ ├── server.py
│ └── tests.py
├── fluxcapacitor.man
├── src
├── fluxcapacitor.h
├── list.h
├── main.c
├── misc.c
├── parent.c
├── preload.c
├── scnums.h
├── scnums_amd64.h
├── scnums_arm.h
├── scnums_x86.h
├── testlib.c
├── trace.c
├── trace.h
├── types.h
├── uevent.c
├── uevent.h
└── wrapper.c
└── tests
├── __init__.py
├── tests.py
└── tests_basic.py
/.gitignore:
--------------------------------------------------------------------------------
1 | fluxcapacitor_preload.so
2 | fluxcapacitor_test.so
3 | fluxcapacitor
4 | *.gcda
5 | gmon.out
6 | *.pyc
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 |
3 | compiler:
4 | - clang
5 | - gcc
6 |
7 | env:
8 | - FCPATH="$PWD/majek/fluxcapacitor/fluxcapacitor -o log -vvvv"
9 |
10 | branches:
11 | only:
12 | - master
13 |
14 | install:
15 | - sudo apt-get -qq -y install nodejs erlang-nox
16 | - make build
17 |
18 | script:
19 | - make test
20 |
21 | after_script:
22 | - cat log
23 |
24 | notifications:
25 | email:
26 | recipients:
27 | - travis@popcount.org
28 |
--------------------------------------------------------------------------------
/CONTRIBUTING:
--------------------------------------------------------------------------------
1 | By contributing code to the Fluxcapacitor project in any form,
2 | including sending a pull request via Github, a code fragment or patch
3 | via private email or public discussion groups, you agree to release
4 | your code under the terms of the MIT license that you can find in the
5 | LICENSE-MIT-fluxcapacitor file included in the Fluxcapacitor source
6 | distribution. You will include MIT license within each source file
7 | that you contribute.
8 |
--------------------------------------------------------------------------------
/LICENSE-MIT-fluxcapacitor:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012-2013 Marek Majkowski
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | LIBNAME=fluxcapacitor_preload.so
2 | TESTLIBNAME=fluxcapacitor_test.so
3 | LOADERNAME=fluxcapacitor
4 |
5 | LDOPTS+=-lrt -ldl -rdynamic
6 | COPTS+=$(CFLAGS) -g -ggdb -Wall -Wextra -Wno-unused-parameter -O3 -fPIC
7 |
8 | TESTLIB_FILES=src/testlib.c
9 | LIB_FILES=src/preload.c
10 | LOADER_FILES=src/wrapper.c src/parent.c src/misc.c src/uevent.c src/trace.c src/main.c
11 |
12 | all: build test
13 |
14 | .PHONY: build
15 | build: $(TESTLIBNAME) $(LIBNAME) $(LOADERNAME)
16 |
17 | $(TESTLIBNAME): Makefile $(TESTLIB_FILES)
18 | $(CC) $(COPTS) $(TESTLIB_FILES) \
19 | -fPIC -shared -Wl,-soname,$(TESTLIBNAME) -o $(TESTLIBNAME)
20 |
21 | $(LIBNAME): Makefile $(LIB_FILES)
22 | $(CC) $(COPTS) $(LIB_FILES) $(LDOPTS) \
23 | -fPIC -shared -Wl,-soname,$(LIBNAME) -o $(LIBNAME)
24 |
25 | $(LOADERNAME): Makefile $(LOADER_FILES)
26 | $(CC) $(COPTS) $(LOADER_FILES) $(LDOPTS) \
27 | -o $(LOADERNAME)
28 |
29 | FCPATH ?= $(PWD)/$(LOADERNAME)
30 | .PHONY:test
31 | test:
32 | FCPATH="$(FCPATH)" python2 tests/tests_basic.py
33 |
34 | clean:
35 | rm -f *.gcda *.so fluxcapacitor a.out gmon.out
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/majek/fluxcapacitor)
2 |
3 | Fluxcapacitor
4 | =============
5 |
6 | `Fluxcapacitor` is a tool for making your program run without blocking on timeouts, on functions like `poll` and `select`, by spoofing POSIX time functions.
7 |
8 | It is somewhat similar to:
9 |
10 | * [FreezeGun](http://stevepulec.com/freezegun/) for Python
11 | * [TimeCop](https://github.com/travisjeffery/timecop) or
12 | [DeLorean](https://github.com/bebanjo/delorean) for Ruby
13 |
14 | While these tools patch time libraries in Ruby and Python,
15 | `fluxcapacitor` works on a lower layer by "patching" low-level
16 | syscalls. That way, it can lie about time to any program in any
17 | programming language, as long as it runs on Linux.
18 |
19 | This approach has a significant advantage: it is possible to lie about
20 | time to many processes at the same time. It is especially useful for
21 | running network applications where server and client run in different
22 | processes which rely on time. It will also work with multithreaded
23 | applications.
24 |
25 | Another comparable project is:
26 |
27 | * [libfaketime](https://github.com/wolfcw/libfaketime)
28 |
29 | `Fluxcapacitor` is fundamentally different from `libfaketime`, which
30 | can fake the time functions, but doesn't affect the runtime of the
31 | program. Conversely, `fluxcapacitor` will make your program run faster
32 | and be 100% CPU constrained. It does that by "speeding up" blocking
33 | syscalls. Faking time is a necessary side effect.
34 |
35 |
36 | Internally,`Fluxcapacitor` uses `ptrace` on syscalls and `LD_PRELOAD`,
37 | which is why it's Linux specific.
38 |
39 | Join the fluxcapacitor-dev
mailing list. Or view the archives.
40 |
41 |
42 | Basic examples
43 | ----
44 |
45 | When you run `sleep` bash command, well, it will block the console for
46 | a given time. For example:
47 |
48 | $ sleep 12
49 |
50 | will halt terminal for 12 seconds. When you run it with
51 | `fluxcapacitor`:
52 |
53 | $ ./fluxcapacitor -- sleep 12
54 |
55 | it will finish instantly. Cool, huh? To illustrate this:
56 |
57 | $ time sleep 12
58 | real 0m12.003s
59 |
60 | while:
61 |
62 | $ time ./fluxcapacitor -- sleep 12
63 | real 0m0.057s
64 |
65 | Another example, take a look at this session:
66 |
67 | $ date
68 | Thu Feb 14 23:49:55 GMT 2013
69 | $ ./fluxcapacitor -- bash -c "date; sleep 120; date"
70 | Thu Feb 14 23:49:57 GMT 2013
71 | Thu Feb 14 23:51:57 GMT 2013
72 | $ date
73 | Thu Feb 14 23:49:58 GMT 2013
74 |
75 |
76 | You should see a program thinks time had passed, although it did not
77 | in reality.
78 |
79 | Ever heard of the
80 | [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem)?
81 | Here's how it's going to look like in action (this works on 32 bit
82 | systems):
83 |
84 | $ ./fluxcapacitor -- bash -c "sleep 700000000; date"
85 | Thu Apr 26 17:44:25 BST 2035
86 | $ ./fluxcapacitor -- bash -c "sleep 800000000; date"
87 | Wed May 21 20:04:03 GMT 1902
88 |
89 |
90 | Finally, `fluxcapacitor` works with any programming language:
91 |
92 | $ ./fluxcapacitor -- python2 -c "import time; time.sleep(1000)"
93 |
94 |
95 | For reference, `fluxcapacitor` usage info:
96 |
97 | ```
98 | $ ./fluxcapacitor --help
99 | Usage:
100 |
101 | fluxcapacitor [options] [ -- command [ arguments ... ] ... ]
102 |
103 | Options:
104 |
105 | --libpath=PATH Load fluxcapacitor_preload.so from
106 | selected PATH directory.
107 | --signal=SIGNAL Use specified signal to interrupt blocking
108 | syscall instead of SIGURG.
109 | --verbose,-v Print more stuff.
110 | --help Print this message.
111 | ```
112 |
113 |
114 | How does it work
115 | ----
116 |
117 | Fluxcapacitor internally does two things:
118 |
119 | 1) It forces `fluxcapacitor_preload.so` to be preloaded using the
120 | `LD_PRELOAD` linux facility. This library is responsible for two
121 | things:
122 |
123 | * It makes sure that `clock_gettime()` will use the standard
124 | syscall, not the ultra-fast VDSO mechanism. That gives us the
125 | opportunity to replace the return value of the system call later.
126 | * It replaces various time-related libc functions:
127 | `clock_gettime()`, `gettimeofday()`, `time()`, `ftime()`,
128 | `nanosleep()` and `clock_nanosleep()` with variants using
129 | modified `clock_gettime()`. That simplifies syscall semantics
130 | thus making some parts of the server code less involved.
131 |
132 | 2) It runs then given command and its forked children in a `ptrace()`
133 | sandbox, capturing all syscalls. Some syscalls - notably
134 | `clock_gettime`, have their original results returned from the kernel
135 | overwritten by faked values. Other syscalls, like `select()`, `poll()`
136 | and`epoll_wait()`, can be interrupted (by a signal) and the result
137 | will be set to look like a timeout has expired. Full list of
138 | recognized syscalls that can be sped up:
139 |
140 | * `epoll_wait()`, `epoll_pwait()`
141 | * `select()`, `_newselect()`, `pselect6()`
142 | * `poll()`, `ppoll()`
143 | * `nanosleep()`
144 |
145 | ### Speeding up
146 |
147 | Fluxcapacitor monitors all syscalls run by the child processes. All
148 | syscalls are relayed to the kernel, as normal. This operation
149 | continues until fluxcapacitor notices that all the child processes are
150 | waiting on recognised time-related syscalls, like `poll` or
151 | `select`. When that happens, fluxcapacitor decides to speed up the
152 | time. It advances the internal timer and sends a signal (SIGURG by
153 | default) to the process that is blocked with the smallest timeout
154 | value. Fluxcapacitor is then woken up by the kernel to give it a
155 | chance to pass the signal to the child. It swallows the signal and
156 | sets the return value of the syscall to look like a timeout had
157 | expired. See diagram:
158 |
159 | ```
160 | child fluxcapacitor kernel
161 | ----- ------------- ------
162 |
163 | |
164 | +--- select(1s) -->+
165 | |
166 | +------------------------>
167 |
168 | kill(child, SIGURG)
169 |
170 | +<---- signal received ---
171 | |
172 | (pretend it was a timeout)
173 | |
174 | +<--- timeout -----+
175 | |
176 | ```
177 |
178 |
179 | When it won't work
180 | ----
181 |
182 | Fluxcapacitor won't work in a number of cases:
183 |
184 | 1) If your code is statically compiled and `fluxcapacitor_preload.so`
185 | ld-preloaded library can't play its role.
186 |
187 | 2) If your code uses unpopular blocking functions in the event loop,
188 | like `signalfd()` and `sigwait()`, or if your program relies
189 | heavily on signals and things like `alert()`, `setitimer()`, or
190 | `timerfd_create()`.
191 |
192 | 3) If your code uses file access or modification
193 | timestamps. `Fluxcapacitor` does not mock that.
194 |
195 | Basically, for Fluxcapacitor to work all the time, queries need to be
196 | done using `gettimeofday()` or `clock_gettime()`, and all the waiting
197 | for timeouts must rely on `select()`, `poll()` or
198 | `epoll_wait()`. Fortunately, that's the case in most programming
199 | languages.
200 |
201 |
202 | Advanced usage
203 | ----
204 |
205 | `Fluxcapacitor`'s main application is speeding up tests.
206 |
207 | Say you have a "delayed echo" server and you want to test it. It echos
208 | messages, just delayed by a few seconds. You don't want your tests to
209 | take too long. For example the code:
210 |
211 | - [server.py](https://github.com/majek/fluxcapacitor/blob/master/examples/slowecho/server.py)
212 | - [tests.py](https://github.com/majek/fluxcapacitor/blob/master/examples/slowecho/tests.py)
213 |
214 | Normally you could run the server, run the tests in a separate console
215 | and wait for some time. With `fluxcapacitor` you write a
216 | [wrapper program](https://github.com/majek/fluxcapacitor/blob/master/examples/slowecho/run_test.py):
217 |
218 |
219 | ```python2
220 | #!/usr/bin/env python2
221 |
222 | import os
223 | import time
224 | import signal
225 |
226 | server_pid = os.fork()
227 | if server_pid == 0:
228 | os.execv("/usr/bin/python2", ["python2", "server.py"])
229 | os._exit(0)
230 | else:
231 | time.sleep(1)
232 | os.system("python2 tests.py")
233 | os.kill(server_pid, signal.SIGINT)
234 | ```
235 |
236 | This script just runs the tests in an automated manner. Normally the
237 | tests take 1 second each:
238 |
239 | $ time python2 run_test.py
240 | real 0m5.112s
241 |
242 | With `fluxcapacitor` it's much faster:
243 |
244 | $ ./fluxcapacitor -- python2 run_test.py
245 | real 0m0.355s
246 |
247 |
248 | Development
249 | ====
250 |
251 | Prerequisites
252 | ----
253 |
254 | To compile the things you need are `git`, `gcc` and `make`. This
255 | should do:
256 |
257 | $ sudo yum git gcc make
258 |
259 | or
260 |
261 | $ sudo apt-get install git gcc make
262 |
263 | Building
264 | ----
265 |
266 | To compile `fluxcapacitor` you need a reasonably recent linux
267 | distribution. Type:
268 |
269 | make build
270 |
271 | Testing
272 | ----
273 |
274 | `Fluxcapacitor` comes with a number of python tests. See `tests`
275 | subdirectory for details. To test `fluxcapacitor` type:
276 |
277 | make test
278 |
279 | or just:
280 |
281 | make
282 |
283 | You can also run specific tests, but that's a bit more complex. For
284 | example to run `SingleProcess.test_bash_sleep` from `tests/tests_basic.py`:
285 |
286 | FCPATH="$PWD/fluxcapacitor --libpath=$PWD" \
287 | python2 tests/tests_basic.py SingleProcess.test_bash_sleep
288 |
289 |
--------------------------------------------------------------------------------
/examples/sleep_sort.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | function f() {
3 | sleep "$1"
4 | echo -n "$1 "
5 | }
6 | while [ -n "$1" ]
7 | do
8 | f "$1" &
9 | shift
10 | done
11 | wait
12 | echo
13 |
--------------------------------------------------------------------------------
/examples/slowecho/run_test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 |
3 | import os
4 | import time
5 | import signal
6 |
7 | server_pid = os.fork()
8 | if server_pid == 0:
9 | os.execv("/usr/bin/python2", ["python", "server.py"])
10 | os._exit(0)
11 | else:
12 | time.sleep(1)
13 | os.system("python2 tests.py")
14 | os.kill(server_pid, signal.SIGINT)
15 |
--------------------------------------------------------------------------------
/examples/slowecho/server.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 | import socket
3 | import time
4 |
5 | HOST = '0.0.0.0'
6 | PORT = 1234
7 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
8 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
9 | s.bind((HOST, PORT))
10 | s.listen(1)
11 | print 'Listening on %s:%s' % (HOST, PORT)
12 | try:
13 | while True:
14 | conn, addr = s.accept()
15 | print 'Connected by', addr
16 | while True:
17 | data = conn.recv(1024)
18 | if not data:
19 | break
20 | time.sleep(2)
21 | conn.sendall(data)
22 | except KeyboardInterrupt:
23 | pass
24 |
25 |
--------------------------------------------------------------------------------
/examples/slowecho/tests.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 | '''
3 | >>> s = connect()
4 | >>> s.sendall('abc')
5 | >>> s.recv(128)
6 | 'abc'
7 | >>> s.sendall('def')
8 | >>> s.recv(128)
9 | 'def'
10 | '''
11 |
12 | import socket
13 |
14 | def connect(host='127.0.0.1', port=1234):
15 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
16 | s.connect((host, port))
17 | return s
18 |
19 | if __name__ == "__main__":
20 | import doctest
21 | doctest.testmod(verbose=True)
22 |
--------------------------------------------------------------------------------
/fluxcapacitor.man:
--------------------------------------------------------------------------------
1 | .TH FLUXCAPACITOR 1 "2018-01-13" "" "User Commands Manual"
2 | .SH NAME
3 | fluxcapacitor \- run programs without blocking on syscalls
4 | .SH SYNOPSIS
5 | .SY fluxcapacitor
6 | .OP \-\-libpath PATH
7 | .OP \-\-output FILENAME
8 | .OP \-\-signal SIGNAL
9 | .OP \-\-verbose
10 | \-\- command [\fIarguments...\fR]
11 | .YS
12 | .SY fluxcapacitor
13 | \-\- command1 [\fIargs...\fR]
14 | \-\- command2 [\fIargs...\fR] ...
15 | .YS
16 | .SH DESCRIPTION
17 | .B fluxcapacitor
18 | is a tool for making your program run without blocking on timeouts,
19 | on functions like poll and select, by spoofing POSIX time functions.
20 | By "patching" low-level syscalls, it can lie about time to any program
21 | in any programming language, as long as it runs on Linux.
22 |
23 | This approach has a significant advantage: it is possible to lie about time
24 | to many processes at the same time. It is especially useful for running
25 | network applications where server and client run in different processes
26 | which rely on time. It will also work with multithreaded applications.
27 |
28 | .B fluxcapacitor
29 | will make your program run faster and be 100% CPU constrained.
30 | It does that by "speeding up" blocking syscalls.
31 | Faking time is a necessary side effect.
32 | .SH OPTIONS
33 | .TP
34 | .B \-\-help
35 | Print usage instructions and exit.
36 | .TP
37 | \fB\-\-libpath\fR \fIPATH\fR
38 | Load \fIfluxcapacitor_preload.so\fR from selected \fIPATH\fR directory.
39 | .TP
40 | \fB\-\-output\fR \fIFILENAME\fR
41 | Write logs to \fIFILENAME\fR instead of stderr.
42 | .TP
43 | \fB\-\-signal\fR \fISIGNAL\fR
44 | Use specified \fISIGNAL\fR to interrupt blocking syscalls, instead of SIGURG.
45 | .TP
46 | .B \-v
47 | .TQ
48 | .B \-\-verbose
49 | Print more stuff. Repeat for debugging messages.
50 | .SH LIMITATIONS
51 | .B fluxcapacitor
52 | won't work in a number of cases:
53 | .IP \[bu] 2
54 | If your code is statically compiled and \fIfluxcapacitor_preload.so\fR
55 | ld-preloaded library can't play its role.
56 | .IP \[bu] 2
57 | If your code uses unpopular blocking functions in the event loop,
58 | like \%signalfd() and \%sigwait(), or if your program relies heavily on signals
59 | and things like \%alert(), \%setitimer(), or \%timerfd_create().
60 | .IP \[bu] 2
61 | If your code uses file access or modification timestamps.
62 | .B fluxcapacitor
63 | does not mock that.
64 | .PP
65 | Basically, for
66 | .B fluxcapacitor
67 | to work all the time, queries need to be done using
68 | \%gettimeofday() or \%clock_gettime(),
69 | and all the waiting for timeouts must rely on
70 | \%select(), \%poll() or \%epoll_wait().
71 | Fortunately, that's the case in most programming languages.
72 |
--------------------------------------------------------------------------------
/src/fluxcapacitor.h:
--------------------------------------------------------------------------------
1 | #define TEST_LIBNAME "fluxcapacitor_test.so"
2 | #define PRELOAD_LIBNAME "fluxcapacitor_preload.so"
3 |
4 | extern struct timespec uevent_now;
5 |
6 | #define ERRORF(x...) fprintf(stderr, x)
7 | #define FATAL(x...) do { \
8 | ERRORF("[-] PROGRAM ABORT : " x); \
9 | ERRORF("\n Location : %s(), %s:%u\n\n", \
10 | __FUNCTION__, __FILE__, __LINE__); \
11 | exit(EXIT_FAILURE); \
12 | } while (0)
13 |
14 | #define PFATAL(x...) do { \
15 | ERRORF("[-] SYSTEM ERROR : " x); \
16 | ERRORF("\n Location : %s(), %s:%u\n", \
17 | __FUNCTION__, __FILE__, __LINE__); \
18 | perror(" OS message "); \
19 | ERRORF("\n"); \
20 | exit(127); \
21 | } while (0)
22 |
23 | #define SHOUT(x...) do{ \
24 | if (options.verbose) { \
25 | fprintf(options.shoutstream, x); \
26 | fprintf(options.shoutstream, "\n"); \
27 | } \
28 | } while (0)
29 |
30 | #define PRINT(x...) do{ \
31 | if (options.verbose > 1) { \
32 | fprintf(options.shoutstream, x); \
33 | fprintf(options.shoutstream, "\n"); \
34 | } \
35 | } while (0)
36 |
37 | /* All the global state goes here */
38 | struct options {
39 | /* Path to .so files */
40 | char *libpath;
41 |
42 | int verbose;
43 |
44 | FILE *shoutstream;
45 |
46 | /* Should we exit? */
47 | int exit_forced;
48 |
49 | /* Max exit status of the exited children (unsigned) */
50 | unsigned exit_status;
51 |
52 | /* Signo we'll use to continue the child. Must not be used by
53 | the child application. */
54 | int signo;
55 |
56 | /* Wait for `idleness_threshold` ns of not handling any
57 | * changes before speeding up time. */
58 | u64 idleness_threshold;
59 |
60 | /* Don't advance time in tiny chunks */
61 | u64 min_speedup;
62 | };
63 |
64 |
65 | struct parent {
66 | int child_count;
67 | struct list_head list_of_children;
68 |
69 | int blocked_count;
70 | struct list_head list_of_blocked;
71 |
72 | int started;
73 |
74 | flux_time time_drift;
75 | };
76 |
77 |
78 | struct trace_process;
79 |
80 | struct child {
81 | int pid;
82 | struct list_head in_children;
83 | struct list_head in_blocked;
84 |
85 | int blocked;
86 | flux_time blocked_until;
87 |
88 | struct parent *parent;
89 | struct trace_process *process;
90 |
91 | int interrupted;
92 |
93 | int syscall_no;
94 |
95 | int stat_fd;
96 | char stat;
97 | };
98 |
99 |
100 | /* misc.c */
101 | void pin_cpu();
102 | char ***argv_split(char **argv, const char *delimiter, int upper_bound);
103 | char *argv_join(char **argv, const char *delimiter);
104 | void ensure_libpath(const char *argv_0);
105 | void ldpreload_extend(const char *lib_path, const char *file);
106 | const char *ldpreload_get();
107 | void handle_backtrace();
108 | int str_to_signal(const char *s);
109 | int str_to_time(const char *s, u64 *timens_ptr);
110 | const char *syscall_to_str(int no);
111 | int proc_running();
112 | void ping_myself();
113 |
114 | /* parent.c */
115 | #define TIMEOUT_UNKNOWN (-1LL)
116 | /* 2**63 - 1, LLONG_MAX but not depending on limits.h */
117 | #define TIMEOUT_FOREVER (-2LL)
118 |
119 | struct trace;
120 | struct trace_process;
121 | struct parent *parent_new();
122 | void parent_run_one(struct parent *parent, struct trace *trace,
123 | char **child_argv);
124 | struct child *parent_min_timeout_child(struct parent *parent);
125 | struct child *parent_woken_child(struct parent *parent);
126 | void parent_kill_all(struct parent *parent, int signo);
127 |
128 | struct child *child_new(struct parent *parent, struct trace_process *process, int pid);
129 | void child_del(struct child *child);
130 | struct trace_sysarg;
131 | void child_mark_blocked(struct child *child);
132 | void child_mark_unblocked(struct child *child);
133 |
134 |
135 | void wrapper_syscall_enter(struct child *child, struct trace_sysarg *sysarg);
136 | int wrapper_syscall_exit(struct child *child, struct trace_sysarg *sysarg);
137 | void wrapper_pacify_signal(struct child *child, struct trace_sysarg *sysarg);
138 |
139 |
140 |
141 | void child_kill(struct child *child, int signo);
142 | void child_fake_response(struct child *child, struct trace_sysarg *sysarg);
143 |
144 |
145 | #define TIMESPEC_NSEC(ts) ((ts)->tv_sec * 1000000000ULL + (ts)->tv_nsec)
146 | #define TIMEVAL_NSEC(ts) ((ts)->tv_sec * 1000000000ULL + (ts)->tv_usec * 1000ULL)
147 | #define NSEC_TIMESPEC(ns) (struct timespec){(ns) / 1000000000ULL, \
148 | (ns) % 1000000000ULL}
149 | #define NSEC_TIMEVAL(ns) (struct timeval){(ns) / 1000000000ULL, \
150 | ((ns) % 1000000000ULL) / 1000ULL}
151 | #define MSEC_NSEC(ms) ((ms) * 1000000ULL)
152 |
--------------------------------------------------------------------------------
/src/list.h:
--------------------------------------------------------------------------------
1 | #ifndef _LINUX_LIST_H
2 | #define _LINUX_LIST_H
3 |
4 | //#include
5 | //#include
6 | #define LIST_POISON1 (void*)0xDEADBEEF
7 | #define LIST_POISON2 (void*)0xDEADBEFE
8 |
9 | #define prefetch(a) __builtin_prefetch(a)
10 |
11 | #ifndef container_of
12 | # define container_of(ptr, type, member) \
13 | ({ \
14 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \
15 | (type *)( (char *)__mptr - offsetof(type,member) ); \
16 | })
17 | #endif //container_of
18 |
19 | #ifndef offsetof
20 | # define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
21 | #endif
22 |
23 | //#include
24 | //#include
25 |
26 | /*
27 | * Simple doubly linked list implementation.
28 | *
29 | * Some of the internal functions ("__xxx") are useful when
30 | * manipulating whole lists rather than single entries, as
31 | * sometimes we already know the next/prev entries and we can
32 | * generate better code by using them directly rather than
33 | * using the generic single-entry routines.
34 | */
35 |
36 | struct list_head {
37 | struct list_head *next, *prev;
38 | };
39 |
40 | #define LIST_HEAD_INIT(name) { &(name), &(name) }
41 |
42 | #define LIST_HEAD(name) \
43 | struct list_head name = LIST_HEAD_INIT(name)
44 |
45 | static inline void INIT_LIST_HEAD(struct list_head *list)
46 | {
47 | list->next = list;
48 | list->prev = list;
49 | }
50 |
51 | /*
52 | * Insert a new entry between two known consecutive entries.
53 | *
54 | * This is only for internal list manipulation where we know
55 | * the prev/next entries already!
56 | */
57 | #ifndef CONFIG_DEBUG_LIST
58 | static inline void __list_add(struct list_head *new,
59 | struct list_head *prev,
60 | struct list_head *next)
61 | {
62 | next->prev = new;
63 | new->next = next;
64 | new->prev = prev;
65 | prev->next = new;
66 | }
67 | #else
68 | extern void __list_add(struct list_head *new,
69 | struct list_head *prev,
70 | struct list_head *next);
71 | #endif
72 |
73 | /**
74 | * list_add - add a new entry
75 | * @new: new entry to be added
76 | * @head: list head to add it after
77 | *
78 | * Insert a new entry after the specified head.
79 | * This is good for implementing stacks.
80 | */
81 | static inline void list_add(struct list_head *new, struct list_head *head)
82 | {
83 | __list_add(new, head, head->next);
84 | }
85 |
86 |
87 | /**
88 | * list_add_tail - add a new entry
89 | * @new: new entry to be added
90 | * @head: list head to add it before
91 | *
92 | * Insert a new entry before the specified head.
93 | * This is useful for implementing queues.
94 | */
95 | static inline void list_add_tail(struct list_head *new, struct list_head *head)
96 | {
97 | __list_add(new, head->prev, head);
98 | }
99 |
100 | /*
101 | * Delete a list entry by making the prev/next entries
102 | * point to each other.
103 | *
104 | * This is only for internal list manipulation where we know
105 | * the prev/next entries already!
106 | */
107 | static inline void __list_del(struct list_head * prev, struct list_head * next)
108 | {
109 | next->prev = prev;
110 | prev->next = next;
111 | }
112 |
113 | /**
114 | * list_del - deletes entry from list.
115 | * @entry: the element to delete from the list.
116 | * Note: list_empty() on entry does not return true after this, the entry is
117 | * in an undefined state.
118 | */
119 | #ifndef CONFIG_DEBUG_LIST
120 | static inline void list_del(struct list_head *entry)
121 | {
122 | __list_del(entry->prev, entry->next);
123 | entry->next = LIST_POISON1;
124 | entry->prev = LIST_POISON2;
125 | }
126 | #else
127 | extern void list_del(struct list_head *entry);
128 | #endif
129 |
130 | /**
131 | * list_replace - replace old entry by new one
132 | * @old : the element to be replaced
133 | * @new : the new element to insert
134 | *
135 | * If @old was empty, it will be overwritten.
136 | */
137 | static inline void list_replace(struct list_head *old,
138 | struct list_head *new)
139 | {
140 | new->next = old->next;
141 | new->next->prev = new;
142 | new->prev = old->prev;
143 | new->prev->next = new;
144 | }
145 |
146 | static inline void list_replace_init(struct list_head *old,
147 | struct list_head *new)
148 | {
149 | list_replace(old, new);
150 | INIT_LIST_HEAD(old);
151 | }
152 |
153 | /**
154 | * list_del_init - deletes entry from list and reinitialize it.
155 | * @entry: the element to delete from the list.
156 | */
157 | static inline void list_del_init(struct list_head *entry)
158 | {
159 | __list_del(entry->prev, entry->next);
160 | INIT_LIST_HEAD(entry);
161 | }
162 |
163 | /**
164 | * list_move - delete from one list and add as another's head
165 | * @list: the entry to move
166 | * @head: the head that will precede our entry
167 | */
168 | static inline void list_move(struct list_head *list, struct list_head *head)
169 | {
170 | __list_del(list->prev, list->next);
171 | list_add(list, head);
172 | }
173 |
174 | /**
175 | * list_move_tail - delete from one list and add as another's tail
176 | * @list: the entry to move
177 | * @head: the head that will follow our entry
178 | */
179 | static inline void list_move_tail(struct list_head *list,
180 | struct list_head *head)
181 | {
182 | __list_del(list->prev, list->next);
183 | list_add_tail(list, head);
184 | }
185 |
186 | /**
187 | * list_is_last - tests whether @list is the last entry in list @head
188 | * @list: the entry to test
189 | * @head: the head of the list
190 | */
191 | static inline int list_is_last(const struct list_head *list,
192 | const struct list_head *head)
193 | {
194 | return list->next == head;
195 | }
196 |
197 | /**
198 | * list_empty - tests whether a list is empty
199 | * @head: the list to test.
200 | */
201 | static inline int list_empty(const struct list_head *head)
202 | {
203 | return head->next == head;
204 | }
205 |
206 | /**
207 | * list_empty_careful - tests whether a list is empty and not being modified
208 | * @head: the list to test
209 | *
210 | * Description:
211 | * tests whether a list is empty _and_ checks that no other CPU might be
212 | * in the process of modifying either member (next or prev)
213 | *
214 | * NOTE: using list_empty_careful() without synchronization
215 | * can only be safe if the only activity that can happen
216 | * to the list entry is list_del_init(). Eg. it cannot be used
217 | * if another CPU could re-list_add() it.
218 | */
219 | static inline int list_empty_careful(const struct list_head *head)
220 | {
221 | struct list_head *next = head->next;
222 | return (next == head) && (next == head->prev);
223 | }
224 |
225 | /**
226 | * list_is_singular - tests whether a list has just one entry.
227 | * @head: the list to test.
228 | */
229 | static inline int list_is_singular(const struct list_head *head)
230 | {
231 | return !list_empty(head) && (head->next == head->prev);
232 | }
233 |
234 | static inline void __list_cut_position(struct list_head *list,
235 | struct list_head *head, struct list_head *entry)
236 | {
237 | struct list_head *new_first = entry->next;
238 | list->next = head->next;
239 | list->next->prev = list;
240 | list->prev = entry;
241 | entry->next = list;
242 | head->next = new_first;
243 | new_first->prev = head;
244 | }
245 |
246 | /**
247 | * list_cut_position - cut a list into two
248 | * @list: a new list to add all removed entries
249 | * @head: a list with entries
250 | * @entry: an entry within head, could be the head itself
251 | * and if so we won't cut the list
252 | *
253 | * This helper moves the initial part of @head, up to and
254 | * including @entry, from @head to @list. You should
255 | * pass on @entry an element you know is on @head. @list
256 | * should be an empty list or a list you do not care about
257 | * losing its data.
258 | *
259 | */
260 | static inline void list_cut_position(struct list_head *list,
261 | struct list_head *head, struct list_head *entry)
262 | {
263 | if (list_empty(head))
264 | return;
265 | if (list_is_singular(head) &&
266 | (head->next != entry && head != entry))
267 | return;
268 | if (entry == head)
269 | INIT_LIST_HEAD(list);
270 | else
271 | __list_cut_position(list, head, entry);
272 | }
273 |
274 | static inline void __list_splice(const struct list_head *list,
275 | struct list_head *prev,
276 | struct list_head *next)
277 | {
278 | struct list_head *first = list->next;
279 | struct list_head *last = list->prev;
280 |
281 | first->prev = prev;
282 | prev->next = first;
283 |
284 | last->next = next;
285 | next->prev = last;
286 | }
287 |
288 | /**
289 | * list_splice - join two lists, this is designed for stacks
290 | * @list: the new list to add.
291 | * @head: the place to add it in the first list.
292 | */
293 | static inline void list_splice(const struct list_head *list,
294 | struct list_head *head)
295 | {
296 | if (!list_empty(list))
297 | __list_splice(list, head, head->next);
298 | }
299 |
300 | /**
301 | * list_splice_tail - join two lists, each list being a queue
302 | * @list: the new list to add.
303 | * @head: the place to add it in the first list.
304 | */
305 | static inline void list_splice_tail(struct list_head *list,
306 | struct list_head *head)
307 | {
308 | if (!list_empty(list))
309 | __list_splice(list, head->prev, head);
310 | }
311 |
312 | /**
313 | * list_splice_init - join two lists and reinitialise the emptied list.
314 | * @list: the new list to add.
315 | * @head: the place to add it in the first list.
316 | *
317 | * The list at @list is reinitialised
318 | */
319 | static inline void list_splice_init(struct list_head *list,
320 | struct list_head *head)
321 | {
322 | if (!list_empty(list)) {
323 | __list_splice(list, head, head->next);
324 | INIT_LIST_HEAD(list);
325 | }
326 | }
327 |
328 | /**
329 | * list_splice_tail_init - join two lists and reinitialise the emptied list
330 | * @list: the new list to add.
331 | * @head: the place to add it in the first list.
332 | *
333 | * Each of the lists is a queue.
334 | * The list at @list is reinitialised
335 | */
336 | static inline void list_splice_tail_init(struct list_head *list,
337 | struct list_head *head)
338 | {
339 | if (!list_empty(list)) {
340 | __list_splice(list, head->prev, head);
341 | INIT_LIST_HEAD(list);
342 | }
343 | }
344 |
345 | /**
346 | * list_entry - get the struct for this entry
347 | * @ptr: the &struct list_head pointer.
348 | * @type: the type of the struct this is embedded in.
349 | * @member: the name of the list_struct within the struct.
350 | */
351 | #define list_entry(ptr, type, member) \
352 | container_of(ptr, type, member)
353 |
354 | /**
355 | * list_first_entry - get the first element from a list
356 | * @ptr: the list head to take the element from.
357 | * @type: the type of the struct this is embedded in.
358 | * @member: the name of the list_struct within the struct.
359 | *
360 | * Note, that list is expected to be not empty.
361 | */
362 | #define list_first_entry(ptr, type, member) \
363 | list_entry((ptr)->next, type, member)
364 |
365 | /**
366 | * list_for_each - iterate over a list
367 | * @pos: the &struct list_head to use as a loop cursor.
368 | * @head: the head for your list.
369 | */
370 | #define list_for_each(pos, head) \
371 | for (pos = (head)->next; prefetch(pos->next), pos != (head); \
372 | pos = pos->next)
373 |
374 | /**
375 | * __list_for_each - iterate over a list
376 | * @pos: the &struct list_head to use as a loop cursor.
377 | * @head: the head for your list.
378 | *
379 | * This variant differs from list_for_each() in that it's the
380 | * simplest possible list iteration code, no prefetching is done.
381 | * Use this for code that knows the list to be very short (empty
382 | * or 1 entry) most of the time.
383 | */
384 | #define __list_for_each(pos, head) \
385 | for (pos = (head)->next; pos != (head); pos = pos->next)
386 |
387 | /**
388 | * list_for_each_prev - iterate over a list backwards
389 | * @pos: the &struct list_head to use as a loop cursor.
390 | * @head: the head for your list.
391 | */
392 | #define list_for_each_prev(pos, head) \
393 | for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
394 | pos = pos->prev)
395 |
396 | /**
397 | * list_for_each_safe - iterate over a list safe against removal of list entry
398 | * @pos: the &struct list_head to use as a loop cursor.
399 | * @n: another &struct list_head to use as temporary storage
400 | * @head: the head for your list.
401 | */
402 | #define list_for_each_safe(pos, n, head) \
403 | for (pos = (head)->next, n = pos->next; pos != (head); \
404 | pos = n, n = pos->next)
405 |
406 | /**
407 | * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
408 | * @pos: the &struct list_head to use as a loop cursor.
409 | * @n: another &struct list_head to use as temporary storage
410 | * @head: the head for your list.
411 | */
412 | #define list_for_each_prev_safe(pos, n, head) \
413 | for (pos = (head)->prev, n = pos->prev; \
414 | prefetch(pos->prev), pos != (head); \
415 | pos = n, n = pos->prev)
416 |
417 | /**
418 | * list_for_each_entry - iterate over list of given type
419 | * @pos: the type * to use as a loop cursor.
420 | * @head: the head for your list.
421 | * @member: the name of the list_struct within the struct.
422 | */
423 | #define list_for_each_entry(pos, head, member) \
424 | for (pos = list_entry((head)->next, typeof(*pos), member); \
425 | prefetch(pos->member.next), &pos->member != (head); \
426 | pos = list_entry(pos->member.next, typeof(*pos), member))
427 |
428 | /**
429 | * list_for_each_entry_reverse - iterate backwards over list of given type.
430 | * @pos: the type * to use as a loop cursor.
431 | * @head: the head for your list.
432 | * @member: the name of the list_struct within the struct.
433 | */
434 | #define list_for_each_entry_reverse(pos, head, member) \
435 | for (pos = list_entry((head)->prev, typeof(*pos), member); \
436 | prefetch(pos->member.prev), &pos->member != (head); \
437 | pos = list_entry(pos->member.prev, typeof(*pos), member))
438 |
439 | /**
440 | * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
441 | * @pos: the type * to use as a start point
442 | * @head: the head of the list
443 | * @member: the name of the list_struct within the struct.
444 | *
445 | * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
446 | */
447 | #define list_prepare_entry(pos, head, member) \
448 | ((pos) ? : list_entry(head, typeof(*pos), member))
449 |
450 | /**
451 | * list_for_each_entry_continue - continue iteration over list of given type
452 | * @pos: the type * to use as a loop cursor.
453 | * @head: the head for your list.
454 | * @member: the name of the list_struct within the struct.
455 | *
456 | * Continue to iterate over list of given type, continuing after
457 | * the current position.
458 | */
459 | #define list_for_each_entry_continue(pos, head, member) \
460 | for (pos = list_entry(pos->member.next, typeof(*pos), member); \
461 | prefetch(pos->member.next), &pos->member != (head); \
462 | pos = list_entry(pos->member.next, typeof(*pos), member))
463 |
464 | /**
465 | * list_for_each_entry_continue_reverse - iterate backwards from the given point
466 | * @pos: the type * to use as a loop cursor.
467 | * @head: the head for your list.
468 | * @member: the name of the list_struct within the struct.
469 | *
470 | * Start to iterate over list of given type backwards, continuing after
471 | * the current position.
472 | */
473 | #define list_for_each_entry_continue_reverse(pos, head, member) \
474 | for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
475 | prefetch(pos->member.prev), &pos->member != (head); \
476 | pos = list_entry(pos->member.prev, typeof(*pos), member))
477 |
478 | /**
479 | * list_for_each_entry_from - iterate over list of given type from the current point
480 | * @pos: the type * to use as a loop cursor.
481 | * @head: the head for your list.
482 | * @member: the name of the list_struct within the struct.
483 | *
484 | * Iterate over list of given type, continuing from current position.
485 | */
486 | #define list_for_each_entry_from(pos, head, member) \
487 | for (; prefetch(pos->member.next), &pos->member != (head); \
488 | pos = list_entry(pos->member.next, typeof(*pos), member))
489 |
490 | /**
491 | * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
492 | * @pos: the type * to use as a loop cursor.
493 | * @n: another type * to use as temporary storage
494 | * @head: the head for your list.
495 | * @member: the name of the list_struct within the struct.
496 | */
497 | #define list_for_each_entry_safe(pos, n, head, member) \
498 | for (pos = list_entry((head)->next, typeof(*pos), member), \
499 | n = list_entry(pos->member.next, typeof(*pos), member); \
500 | &pos->member != (head); \
501 | pos = n, n = list_entry(n->member.next, typeof(*n), member))
502 |
503 | /**
504 | * list_for_each_entry_safe_continue
505 | * @pos: the type * to use as a loop cursor.
506 | * @n: another type * to use as temporary storage
507 | * @head: the head for your list.
508 | * @member: the name of the list_struct within the struct.
509 | *
510 | * Iterate over list of given type, continuing after current point,
511 | * safe against removal of list entry.
512 | */
513 | #define list_for_each_entry_safe_continue(pos, n, head, member) \
514 | for (pos = list_entry(pos->member.next, typeof(*pos), member), \
515 | n = list_entry(pos->member.next, typeof(*pos), member); \
516 | &pos->member != (head); \
517 | pos = n, n = list_entry(n->member.next, typeof(*n), member))
518 |
519 | /**
520 | * list_for_each_entry_safe_from
521 | * @pos: the type * to use as a loop cursor.
522 | * @n: another type * to use as temporary storage
523 | * @head: the head for your list.
524 | * @member: the name of the list_struct within the struct.
525 | *
526 | * Iterate over list of given type from current point, safe against
527 | * removal of list entry.
528 | */
529 | #define list_for_each_entry_safe_from(pos, n, head, member) \
530 | for (n = list_entry(pos->member.next, typeof(*pos), member); \
531 | &pos->member != (head); \
532 | pos = n, n = list_entry(n->member.next, typeof(*n), member))
533 |
534 | /**
535 | * list_for_each_entry_safe_reverse
536 | * @pos: the type * to use as a loop cursor.
537 | * @n: another type * to use as temporary storage
538 | * @head: the head for your list.
539 | * @member: the name of the list_struct within the struct.
540 | *
541 | * Iterate backwards over list of given type, safe against removal
542 | * of list entry.
543 | */
544 | #define list_for_each_entry_safe_reverse(pos, n, head, member) \
545 | for (pos = list_entry((head)->prev, typeof(*pos), member), \
546 | n = list_entry(pos->member.prev, typeof(*pos), member); \
547 | &pos->member != (head); \
548 | pos = n, n = list_entry(n->member.prev, typeof(*n), member))
549 |
550 | /*
551 | * Double linked lists with a single pointer list head.
552 | * Mostly useful for hash tables where the two pointer list head is
553 | * too wasteful.
554 | * You lose the ability to access the tail in O(1).
555 | */
556 |
557 | struct hlist_head {
558 | struct hlist_node *first;
559 | };
560 |
561 | struct hlist_node {
562 | struct hlist_node *next, **pprev;
563 | };
564 |
565 | #define HLIST_HEAD_INIT { .first = NULL }
566 | #define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
567 | #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
568 | static inline void INIT_HLIST_NODE(struct hlist_node *h)
569 | {
570 | h->next = NULL;
571 | h->pprev = NULL;
572 | }
573 |
574 | static inline int hlist_unhashed(const struct hlist_node *h)
575 | {
576 | return !h->pprev;
577 | }
578 |
579 | static inline int hlist_empty(const struct hlist_head *h)
580 | {
581 | return !h->first;
582 | }
583 |
584 | static inline void __hlist_del(struct hlist_node *n)
585 | {
586 | struct hlist_node *next = n->next;
587 | struct hlist_node **pprev = n->pprev;
588 | *pprev = next;
589 | if (next)
590 | next->pprev = pprev;
591 | }
592 |
593 | static inline void hlist_del(struct hlist_node *n)
594 | {
595 | __hlist_del(n);
596 | n->next = LIST_POISON1;
597 | n->pprev = LIST_POISON2;
598 | }
599 |
600 | static inline void hlist_del_init(struct hlist_node *n)
601 | {
602 | if (!hlist_unhashed(n)) {
603 | __hlist_del(n);
604 | INIT_HLIST_NODE(n);
605 | }
606 | }
607 |
608 | static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
609 | {
610 | struct hlist_node *first = h->first;
611 | n->next = first;
612 | if (first)
613 | first->pprev = &n->next;
614 | h->first = n;
615 | n->pprev = &h->first;
616 | }
617 |
618 | /* next must be != NULL */
619 | static inline void hlist_add_before(struct hlist_node *n,
620 | struct hlist_node *next)
621 | {
622 | n->pprev = next->pprev;
623 | n->next = next;
624 | next->pprev = &n->next;
625 | *(n->pprev) = n;
626 | }
627 |
628 | static inline void hlist_add_after(struct hlist_node *n,
629 | struct hlist_node *next)
630 | {
631 | next->next = n->next;
632 | n->next = next;
633 | next->pprev = &n->next;
634 |
635 | if(next->next)
636 | next->next->pprev = &next->next;
637 | }
638 |
639 | /*
640 | * Move a list from one list head to another. Fixup the pprev
641 | * reference of the first entry if it exists.
642 | */
643 | static inline void hlist_move_list(struct hlist_head *old,
644 | struct hlist_head *new)
645 | {
646 | new->first = old->first;
647 | if (new->first)
648 | new->first->pprev = &new->first;
649 | old->first = NULL;
650 | }
651 |
652 | #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
653 |
654 | #define hlist_for_each(pos, head) \
655 | for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
656 | pos = pos->next)
657 |
658 | #define hlist_for_each_safe(pos, n, head) \
659 | for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
660 | pos = n)
661 |
662 | /**
663 | * hlist_for_each_entry - iterate over list of given type
664 | * @tpos: the type * to use as a loop cursor.
665 | * @pos: the &struct hlist_node to use as a loop cursor.
666 | * @head: the head for your list.
667 | * @member: the name of the hlist_node within the struct.
668 | */
669 | #define hlist_for_each_entry(tpos, pos, head, member) \
670 | for (pos = (head)->first; \
671 | pos && ({ prefetch(pos->next); 1;}) && \
672 | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
673 | pos = pos->next)
674 |
675 | /**
676 | * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
677 | * @tpos: the type * to use as a loop cursor.
678 | * @pos: the &struct hlist_node to use as a loop cursor.
679 | * @member: the name of the hlist_node within the struct.
680 | */
681 | #define hlist_for_each_entry_continue(tpos, pos, member) \
682 | for (pos = (pos)->next; \
683 | pos && ({ prefetch(pos->next); 1;}) && \
684 | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
685 | pos = pos->next)
686 |
687 | /**
688 | * hlist_for_each_entry_from - iterate over a hlist continuing from current point
689 | * @tpos: the type * to use as a loop cursor.
690 | * @pos: the &struct hlist_node to use as a loop cursor.
691 | * @member: the name of the hlist_node within the struct.
692 | */
693 | #define hlist_for_each_entry_from(tpos, pos, member) \
694 | for (; pos && ({ prefetch(pos->next); 1;}) && \
695 | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
696 | pos = pos->next)
697 |
698 | /**
699 | * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
700 | * @tpos: the type * to use as a loop cursor.
701 | * @pos: the &struct hlist_node to use as a loop cursor.
702 | * @n: another &struct hlist_node to use as temporary storage
703 | * @head: the head for your list.
704 | * @member: the name of the hlist_node within the struct.
705 | */
706 | #define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
707 | for (pos = (head)->first; \
708 | pos && ({ n = pos->next; 1; }) && \
709 | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
710 | pos = n)
711 |
712 | #endif
713 |
--------------------------------------------------------------------------------
/src/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include "types.h"
10 | #include "list.h"
11 |
12 | #include "fluxcapacitor.h"
13 | #include "uevent.h"
14 | #include "trace.h"
15 |
16 | static void usage() {
17 | ERRORF(
18 | "Usage:\n"
19 | "\n"
20 | " fluxcapacitor [options] [ -- command [ arguments ... ] ... ]\n"
21 | "\n"
22 | "Options:\n"
23 | "\n"
24 | " --output=FILENAME Write logs to FILENAME instead of stderr.\n"
25 | " --libpath=PATH Load " PRELOAD_LIBNAME " from\n"
26 | " selected PATH directory.\n"
27 | " --signal=SIGNAL Use specified signal to interrupt blocking\n"
28 | " syscall instead of SIGURG.\n"
29 | " --verbose,-v Print more stuff. Repeat for debugging\n"
30 | " messages.\n"
31 | " --help Print this message.\n"
32 | "\n"
33 | );
34 | exit(EXIT_FAILURE);
35 | }
36 |
37 |
38 |
39 | /* Global */
40 | struct options options;
41 |
42 | static flux_time main_loop(char ***list_of_argv);
43 |
44 | int main(int argc, char **argv) {
45 |
46 | options.verbose = 0;
47 | options.shoutstream = stderr;
48 | options.signo = SIGURG;
49 |
50 | handle_backtrace();
51 | pin_cpu();
52 |
53 | optind = 1;
54 | while (1) {
55 | int option_index = 0;
56 | static struct option long_options[] = {
57 | {"output", required_argument, 0, 'o' },
58 | {"libpath", required_argument, 0, 0 },
59 | {"help", no_argument, 0, 'h' },
60 | {"verbose", no_argument, 0, 'v' },
61 | {"signal", required_argument, 0, 0 },
62 | {0, 0, 0, 0 }
63 | };
64 |
65 | int arg = getopt_long(argc, argv, "vho:",
66 | long_options, &option_index);
67 | if (arg == -1) {
68 | break;
69 | }
70 |
71 | switch (arg) {
72 | case 0: {
73 | const char *opt_name = long_options[option_index].name;
74 | if (0 == strcasecmp(opt_name, "libpath")) {
75 | options.libpath = strdup(optarg);
76 | } else if (0 == strcasecmp(opt_name, "signal")) {
77 | options.signo = str_to_signal(optarg);
78 | if (!options.signo)
79 | FATAL("Unrecognised signal \"%s\"", optarg);
80 | } else {
81 | FATAL("Unknown option: %s", argv[optind]);
82 | }
83 | break; }
84 |
85 | case 'v':
86 | options.verbose += 1;
87 | break;
88 |
89 | case 'h':
90 | usage();
91 | break;
92 |
93 | case 'o': {
94 | if (strcmp(optarg, "-") == 0) {
95 | options.shoutstream = stdout;
96 | } else {
97 | FILE *f = fopen(optarg, "a+");
98 | if (f == NULL)
99 | PFATAL("fopen(%s)", optarg);
100 | if (fcntl(fileno(f), F_SETFD, FD_CLOEXEC) == -1)
101 | PFATAL("fcntl(FD_CLOEXEC)");
102 | options.shoutstream = f;
103 | }
104 | /* Make sure there's something to be logged */
105 | if (options.verbose == 0)
106 | options.verbose += 1;
107 | break; }
108 |
109 | default:
110 | FATAL("Unknown option: %s", argv[optind]);
111 | }
112 | }
113 |
114 | if (!argv[optind]) {
115 | FATAL("You must specify at least one command to execute.");
116 | }
117 |
118 | char ***list_of_argv = argv_split(&argv[optind], "--", argc);
119 |
120 | ensure_libpath(argv[0]);
121 | ldpreload_extend(options.libpath, PRELOAD_LIBNAME);
122 |
123 | SHOUT("--- Flux Capacitor ---\n");
124 |
125 | SHOUT("[.] LD_PRELOAD=%s", ldpreload_get());
126 |
127 | u64 time_drift = main_loop(list_of_argv);
128 |
129 | free(options.libpath);
130 | fflush(options.shoutstream);
131 | char ***child_argv = list_of_argv;
132 | while (*child_argv) {
133 | free(*child_argv);
134 | child_argv ++;
135 | }
136 | free(list_of_argv);
137 |
138 | PRINT(" ~ Exiting with code %i. Speedup %.3f sec.",
139 | options.exit_status, time_drift / 1000000000.);
140 | return options.exit_status;
141 | }
142 |
143 |
144 | static int on_signal(struct uevent *uevent, int sfd, int mask, void *userdata) {
145 | struct trace *trace = userdata;
146 | trace_read(trace);
147 | return 0;
148 | }
149 |
150 |
151 | static int on_trace(struct trace_process *process, int type, void *arg,
152 | void *userdata);
153 |
154 | static int on_trace_start(struct trace_process *process, int type, void *arg,
155 | void *userdata) {
156 | if (type != TRACE_ENTER)
157 | FATAL("");
158 | int pid = (long)arg;
159 | SHOUT("[+] %i started", pid);
160 | struct parent *parent = (struct parent *)userdata;
161 | struct child *child = child_new(parent, process, pid);
162 | return trace_continue(process, on_trace, child);
163 | }
164 |
165 | static int on_trace(struct trace_process *process, int type, void *arg,
166 | void *userdata) {
167 | struct child *child = userdata;
168 | switch (type) {
169 |
170 | case TRACE_EXIT: {
171 | struct trace_exitarg *exitarg = arg;
172 | if (exitarg->type == TRACE_EXIT_NORMAL) {
173 | SHOUT("[-] %i exited with return status %u",
174 | child->pid, exitarg->value);
175 | options.exit_status = MAX(options.exit_status,
176 | (unsigned)exitarg->value);
177 | } else {
178 | SHOUT("[-] %i exited due to signal %u",
179 | child->pid, exitarg->value);
180 | }
181 | child_del(child);
182 | break; }
183 |
184 | case TRACE_SYSCALL_ENTER: {
185 | struct trace_sysarg *sysarg = arg;
186 | child_mark_blocked(child);
187 | wrapper_syscall_enter(child, sysarg);
188 | break; }
189 |
190 | case TRACE_SYSCALL_EXIT: {
191 | struct trace_sysarg *sysarg = arg;
192 | child_mark_unblocked(child);
193 | wrapper_syscall_exit(child, sysarg);
194 | if (child->interrupted) {
195 | child->interrupted = 0;
196 | wrapper_pacify_signal(child, sysarg);
197 | }
198 | break; }
199 |
200 | case TRACE_SIGNAL: {
201 | int *signal_ptr = (int*)arg;
202 | if (*signal_ptr == options.signo)
203 | *signal_ptr = 0;
204 | break; }
205 |
206 | default:
207 | FATAL("");
208 |
209 | }
210 | return 0;
211 | }
212 |
213 | static flux_time main_loop(char ***list_of_argv) {
214 | struct timeval timeout;
215 |
216 | struct parent *parent = parent_new();
217 | struct trace *trace = trace_new(on_trace_start, parent);
218 | struct uevent *uevent = uevent_new(NULL);
219 |
220 | parent_run_one(parent, trace, *list_of_argv);
221 | list_of_argv ++;
222 |
223 | uevent_yield(uevent, trace_sfd(trace), UEVENT_READ, on_signal, trace);
224 |
225 | while ((parent->child_count || *list_of_argv) && !options.exit_forced) {
226 | /* Is everyone blocking? */
227 | if (parent->blocked_count != parent->child_count) {
228 | /* Nope, need to wait for some process to block */
229 | uevent_select(uevent, NULL);
230 | continue;
231 | }
232 |
233 | /* Continue only after some time passed with no action. */
234 | if (parent->child_count) {
235 | /* Say a child process did a syscall that
236 | * produces side effects. For example a
237 | * network write. It make take a while before
238 | * the side effects become visible to another
239 | * watched process.
240 | *
241 | * Although from our point of view everyone's
242 | * "blocked", there may be some stuff
243 | * available but not yet processed by the
244 | * kernel. We must give some time for a kernel
245 | * to work it out. */
246 |
247 | /* First. Let's make it clear we want to give
248 | * priority to anybody requiring CPU now. */
249 | sched_yield();
250 | sched_yield();
251 |
252 | #if 0
253 | /* Next, let's wait until we're the only
254 | * process in running state. This can be
255 | * painful on SMP.
256 | *
257 | * This also means fluxcapacitor won't work on
258 | * a busy system. */
259 | if (proc_running() > 1) {
260 | int c = 0;
261 | for (c = 0; c < 3 * parent->child_count; c++) {
262 | if (proc_running() < 2)
263 | break;
264 | sched_yield();
265 | }
266 |
267 | SHOUT("[ ] Your system looks busy. I waited %i sched_yields.", c);
268 | }
269 | #endif
270 |
271 | /* Now, lets wait for 1us to see if anything
272 | * new arrived. Setting timeout to zero
273 | * doesn't work - kernel returns immediately
274 | * and doesn't do any work. Therefore we must
275 | * set the timeout to a next smallest value,
276 | * and 'select()' granularity is in us. */
277 |
278 | timeout = NSEC_TIMEVAL(1000ULL);
279 | int r = uevent_select(uevent, &timeout);
280 | if (r != 0)
281 | continue;
282 |
283 | /* Next, make sure all processes are in 'S'
284 | * sleeping state. They should be! */
285 | struct child *woken = parent_woken_child(parent);
286 | if (woken) {
287 | int woken_pid = woken->pid;
288 | SHOUT("[ ] %i not in 'S' state but in '%c'. "
289 | "Waiting for a state change.",
290 | woken_pid, woken->stat);
291 |
292 | timeout = NSEC_TIMEVAL(1000000ULL);
293 | uevent_select(uevent, &timeout);
294 | continue;
295 | }
296 |
297 | /* Finally, send something to myself using
298 | * localhost to make sure network buffers are
299 | * drained. */
300 | ping_myself();
301 |
302 | if (parent->child_count) {
303 | timeout = NSEC_TIMEVAL(0);
304 | r = uevent_select(uevent, &timeout);
305 | if (r != 0)
306 | continue;
307 | }
308 | }
309 |
310 | /* All children started? */
311 | if (*list_of_argv) {
312 | parent_run_one(parent, trace, *list_of_argv);
313 | list_of_argv ++;
314 | uevent_select(uevent, NULL);
315 | continue;
316 | }
317 |
318 | /* Hurray, we're most likely waiting for a timeout. */
319 | struct child *min_child = parent_min_timeout_child(parent);
320 | if (min_child) {
321 | flux_time now = (flux_time)TIMESPEC_NSEC(&uevent_now) + parent->time_drift;
322 | flux_time speedup = min_child->blocked_until - now;
323 | /* Don't speed up less than 10ms */
324 | if (speedup > 0 && speedup < 10 * 1000000) {
325 | SHOUT("[ ] %i too small speedup on %s(), waiting",
326 | min_child->pid,
327 | syscall_to_str(min_child->syscall_no));
328 | timeout = NSEC_TIMEVAL(speedup);
329 | uevent_select(uevent, &timeout);
330 | continue;
331 | } else if (speedup > 0) {
332 | SHOUT("[ ] %i speeding up %s() by %.3f sec",
333 | min_child->pid,
334 | syscall_to_str(min_child->syscall_no),
335 | speedup / 1000000000.0);
336 | } else {
337 | /* Timeout already passed, wake up the process */
338 | speedup = 0;
339 | SHOUT("[ ] %i waking expired %s()",
340 | min_child->pid,
341 | syscall_to_str(min_child->syscall_no));
342 | }
343 | parent->time_drift += speedup;
344 | min_child->interrupted = 1;
345 | child_kill(min_child, options.signo);
346 | } else {
347 | SHOUT("[ ] Can't speedup!");
348 | /* Wait for any event. */
349 | if (parent->child_count) {
350 | timeout = NSEC_TIMEVAL(1000000000ULL);
351 | uevent_select(uevent, &timeout);
352 | }
353 | }
354 | }
355 | parent_kill_all(parent, SIGINT);
356 |
357 | trace_free(trace);
358 |
359 | flux_time time_drift = parent->time_drift;
360 | free(parent);
361 | free(uevent);
362 |
363 | return time_drift;
364 | }
365 |
--------------------------------------------------------------------------------
/src/misc.c:
--------------------------------------------------------------------------------
1 | #define _GNU_SOURCE /* sched_setaffinity() and sched_getcpu() */
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #include
16 | #include
17 |
18 | #include "types.h"
19 | #include "list.h"
20 |
21 | #include "fluxcapacitor.h"
22 | #include "scnums.h"
23 |
24 |
25 | extern struct options options;
26 |
27 |
28 | /* Pin current process and its children to a single CPU. Man
29 | * sched_setaffinity(2) says:
30 | *
31 | * > A child created via fork(2) inherits its parent's CPU affinity
32 | * > mask. The affinity mask is preserved across an execve(2).
33 | */
34 | void pin_cpu() {
35 | int cpu = sched_getcpu();
36 | if (cpu == -1)
37 | PFATAL("sched_getcpu()");
38 |
39 | cpu_set_t mask;
40 | CPU_ZERO(&mask);
41 | CPU_SET(cpu, &mask);
42 | int r = sched_setaffinity(0, sizeof(cpu_set_t), &mask);
43 | if (r == -1)
44 | PFATAL("sched_setaffinity()");
45 | }
46 |
47 | char ***argv_split(char **argv, const char *delimiter, int upper_bound) {
48 | upper_bound += 1;
49 |
50 | int child_no = 0;
51 | char ***child_argv = malloc(upper_bound * sizeof(char *));
52 |
53 | while (*argv) {
54 | int pos = 0;
55 | child_argv[child_no] = malloc(upper_bound * sizeof(char *));
56 | for (;*argv; argv++) {
57 | if (strcmp(*argv, delimiter) != 0) {
58 | child_argv[child_no][pos++] = *argv;
59 | } else {
60 | argv ++;
61 | break;
62 | }
63 | }
64 | child_argv[child_no][pos++] = NULL;
65 | child_argv[child_no] = realloc(child_argv[child_no],
66 | pos * sizeof(char *));
67 | child_no += 1;
68 | }
69 | child_argv[child_no] = NULL;
70 | child_no += 1;
71 | return realloc(child_argv, child_no * sizeof(char *));
72 | }
73 |
74 |
75 | /* Returns malloced memory */
76 | char *argv_join(char **argv, const char *delim) {
77 | int len = 0, delim_len = strlen(delim);
78 | char **a;
79 | for (a = argv; *a; a++) {
80 | len += strlen(*a) + delim_len;
81 | }
82 | if (len) len -= delim_len;
83 | char *s = malloc(len + 1), *p = s;
84 | for (a = argv; *a; a++) {
85 | if (a != argv)
86 | p = stpcpy(p, delim);
87 | p = stpcpy(p, *a);
88 | }
89 | *p = '\0';
90 | return s;
91 | }
92 |
93 | #define PATH_DELIMITER "/"
94 |
95 | static int dl_checkpath(const char *path_prefix, const char *solib) {
96 | char filename[PATH_MAX];
97 | if (strlen(path_prefix) > 0) {
98 | snprintf(filename, sizeof(filename), "%s" PATH_DELIMITER "%s",
99 | path_prefix, solib);
100 | } else {
101 | snprintf(filename, sizeof(filename), "%s", solib);
102 | }
103 |
104 | void *handle = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
105 | if (!handle) {
106 | PRINT(" ~ Trying dlopen(\"%s\"): fail", filename);
107 | return 0;
108 | } else {
109 | PRINT(" ~ Trying dlopen(\"%s\"): success", filename);
110 | dlclose(handle);
111 | return 1;
112 | }
113 | }
114 |
115 |
116 | /* Make sure options.libpath is actually working. */
117 | void ensure_libpath(const char *argv_0) {
118 | if (!options.libpath) {
119 | char *path = NULL;
120 | do {
121 | // 1. Relative to executable, useful for development
122 | char tmp[PATH_MAX];
123 | if (!realpath(argv_0, tmp)) {
124 | PFATAL("realpath(argv[0])");
125 | }
126 | path = dirname(tmp);
127 | if (dl_checkpath(path, TEST_LIBNAME)) break;
128 |
129 | // 2. Linker resolution (ie: no slash in name)
130 | path = "";
131 | if (dl_checkpath(path, TEST_LIBNAME)) break;
132 |
133 | // 3. Give up.
134 | path = NULL;
135 | } while(0);
136 |
137 | if (!path) {
138 | FATAL("Unable to load library \"" PRELOAD_LIBNAME "\", "
139 | "most likely I tried a wrong path. "
140 | "Consider specifying --libpath option.");
141 | }
142 | options.libpath = strdup(path);
143 | } else {
144 | if (!dl_checkpath(options.libpath, TEST_LIBNAME)) {
145 | FATAL("Unable to load " PRELOAD_LIBNAME " from directory \"%s\".\n"
146 | "\tAre files \"" PRELOAD_LIBNAME "\" and \"" TEST_LIBNAME "\" available there?", options.libpath);
147 | }
148 | }
149 | }
150 |
151 | void ldpreload_extend(const char *lib_path, const char *file) {
152 | char pathname[PATH_MAX];
153 | if (strlen(lib_path) > 0) {
154 | snprintf(pathname, sizeof(pathname), "%s" PATH_DELIMITER "%s",
155 | lib_path, file);
156 | } else {
157 | snprintf(pathname, sizeof(pathname), "%s", file);
158 | }
159 |
160 | char ld_preload[PATH_MAX];
161 | char *prev_ld_preload = getenv("LD_PRELOAD");
162 |
163 | if (prev_ld_preload == NULL) {
164 | snprintf(ld_preload, sizeof(ld_preload), "%s", pathname);
165 | } else {
166 | // On Linux LD_PRELOAD is whitespace separated, with first
167 | // library taking precedence
168 | snprintf(ld_preload, sizeof(ld_preload), "%s %s",
169 | pathname, prev_ld_preload);
170 | }
171 | setenv("LD_PRELOAD", ld_preload, 1);
172 |
173 | }
174 |
175 | const char *ldpreload_get() {
176 | return getenv("LD_PRELOAD");
177 | }
178 |
179 |
180 | static void *getMcontextEip(ucontext_t *uc) {
181 | #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
182 | /* OSX < 10.6 */
183 | #if defined(__x86_64__)
184 | return (void*) uc->uc_mcontext->__ss.__rip;
185 | #elif defined(__i386__)
186 | return (void*) uc->uc_mcontext->__ss.__eip;
187 | #else
188 | return (void*) uc->uc_mcontext->__ss.__srr0;
189 | #endif
190 | #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
191 | /* OSX >= 10.6 */
192 | #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
193 | return (void*) uc->uc_mcontext->__ss.__rip;
194 | #else
195 | return (void*) uc->uc_mcontext->__ss.__eip;
196 | #endif
197 | #elif defined(__linux__)
198 | /* Linux */
199 | #if defined(__i386__)
200 | return (void*) uc->uc_mcontext.gregs[14]; /* Linux 32 */
201 | #elif defined(__X86_64__) || defined(__x86_64__)
202 | return (void*) uc->uc_mcontext.gregs[16]; /* Linux 64 */
203 | #elif defined(__ia64__) /* Linux IA64 */
204 | return (void*) uc->uc_mcontext.sc_ip;
205 | #endif
206 | #else
207 | return NULL;
208 | #endif
209 | }
210 |
211 | /* TODO: replace with libunwind one day. */
212 | static void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
213 | ucontext_t *uc = (ucontext_t*) secret;
214 | fprintf(stderr, "Crashed with signal %i\n", sig);
215 |
216 | void *trace[100];
217 | int trace_size = 0;
218 |
219 | /* Generate the stack trace */
220 | trace_size = backtrace(trace, 100);
221 |
222 | /* overwrite sigaction with caller's address */
223 | if (getMcontextEip(uc) != NULL)
224 | trace[1] = getMcontextEip(uc);
225 |
226 | /* Write symbols to log file */
227 | backtrace_symbols_fd(trace, trace_size, 2); /* stderr */
228 | }
229 |
230 | void handle_backtrace() {
231 | struct sigaction act;
232 | sigemptyset(&act.sa_mask);
233 | act.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
234 | act.sa_sigaction = sigsegvHandler;
235 | sigaction(SIGSEGV, &act, NULL);
236 | sigaction(SIGBUS, &act, NULL);
237 | sigaction(SIGFPE, &act, NULL);
238 | sigaction(SIGILL, &act, NULL);
239 | }
240 |
241 |
242 | static struct {
243 | int no;
244 | char *name;
245 | } signal_names[] = {
246 | {SIGHUP, "SIGHUP"},
247 | {SIGINT, "SIGINT"},
248 | {SIGQUIT, "SIGQUIT"},
249 | {SIGILL, "SIGILL"},
250 | {SIGTRAP, "SIGTRAP"},
251 | {SIGABRT, "SIGABRT"},
252 | {SIGIOT, "SIGIOT"},
253 | {SIGBUS, "SIGBUS"},
254 | {SIGFPE, "SIGFPE"},
255 | {SIGKILL, "SIGKILL"},
256 | {SIGUSR1, "SIGUSR1"},
257 | {SIGSEGV, "SIGSEGV"},
258 | {SIGUSR2, "SIGUSR2"},
259 | {SIGPIPE, "SIGPIPE"},
260 | {SIGALRM, "SIGALRM"},
261 | {SIGTERM, "SIGTERM"},
262 | {SIGSTKFLT, "SIGSTKFLT"},
263 | {SIGCHLD, "SIGCHLD"},
264 | {SIGCLD, "SIGCLD"},
265 | {SIGCONT, "SIGCONT"},
266 | {SIGSTOP, "SIGSTOP"},
267 | {SIGTSTP, "SIGTSTP"},
268 | {SIGTTIN, "SIGTTIN"},
269 | {SIGTTOU, "SIGTTOU"},
270 | {SIGURG, "SIGURG"},
271 | {SIGXCPU, "SIGXCPU"},
272 | {SIGXFSZ, "SIGXFSZ"},
273 | {SIGVTALRM, "SIGVTALRM"},
274 | {SIGPROF, "SIGPROF"},
275 | {SIGWINCH, "SIGWINCH"},
276 | {SIGIO, "SIGIO"},
277 | {SIGPOLL, "SIGPOLL"},
278 | {SIGPWR, "SIGPWR"},
279 | {SIGSYS, "SIGSYS"},
280 | {0, NULL}
281 | };
282 |
283 |
284 | int str_to_signal(const char *s) {
285 |
286 | int signo = atoi(s);
287 | if (signo > 0 && signo < SIGRTMAX)
288 | return signo;
289 | int i;
290 | for (i=0; signal_names[i].no; i++) {
291 | if (strcasecmp(s, signal_names[i].name) == 0 ||
292 | strcasecmp(s, &signal_names[i].name[3]) == 0) {
293 | return signal_names[i].no;
294 | }
295 | }
296 |
297 | int rtoffset = 0;
298 | if (strncasecmp(s, "SIGRTMIN+", 9) == 0)
299 | rtoffset = 9;
300 | if (strncasecmp(s, "RTMIN+", 6) == 0)
301 | rtoffset = 6;
302 | if (rtoffset) {
303 | signo = SIGRTMIN + atoi(&s[rtoffset]);
304 | if (signo > 0 && signo < SIGRTMAX)
305 | return signo;
306 | }
307 | return 0;
308 |
309 | }
310 |
311 |
312 | int str_to_time(const char *s, u64 *timens_ptr) {
313 | char *end;
314 | u64 v = strtoull(s, &end, 10);
315 |
316 | if (end == s)
317 | return -1;
318 |
319 | if (*end == '\0' ||
320 | strcasecmp(end, "ns") == 0 ||
321 | strcasecmp(end, "nsec") == 0) {
322 | // already in ns
323 | } else if (strcasecmp(end, "us") == 0 || strcasecmp(end, "usec") == 0) {
324 | v *= 1000ULL;
325 | } else if (strcasecmp(end, "ms") == 0 || strcasecmp(end, "msec") == 0) {
326 | v *= 1000000ULL;
327 | } else if (strcasecmp(end, "s") == 0 || strcasecmp(end, "sec") == 0) {
328 | v *= 1000000000ULL;
329 | } else {
330 | return -1;
331 | }
332 |
333 | *timens_ptr = v;
334 | return 0;
335 | }
336 |
337 | const char *syscall_to_str(int no) {
338 | const int map_sz = sizeof(syscall_to_str_map) / sizeof(syscall_to_str_map[0]);
339 | if (no >= 0 && no < map_sz) {
340 | const char *r = syscall_to_str_map[no];
341 | if (r != NULL) return r;
342 | }
343 |
344 | static char buf[32];
345 | snprintf(buf, sizeof(buf), "syscall_%i", no);
346 | return buf;
347 | }
348 |
349 | int proc_running() {
350 | static int fd = -1;
351 | if (fd == -1) {
352 | fd = open("/proc/stat", O_RDONLY | O_CLOEXEC);
353 | }
354 |
355 | char buf[1024*16];
356 | int r = pread(fd, buf, sizeof(buf)-1, 0);
357 | if (r < 16)
358 | FATAL("");
359 | buf[r] = '\0';
360 |
361 | char *start, *saveptr;
362 | for (start = buf; ; start = NULL) {
363 | char *line = strtok_r(start, "\n", &saveptr);
364 | if (line == NULL)
365 | break;
366 | if (strncmp(line, "procs_running ", 14) == 0) {
367 | return atoi(line + 14);
368 | }
369 | }
370 | FATAL("Can't read /proc/stat!");
371 | return -1;
372 | }
373 |
374 | void ping_myself() {
375 | static int cd = -1;
376 | static int rd = -1;
377 |
378 | if (cd == -1) {
379 | int sd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
380 | if (sd < 0)
381 | PFATAL("socket()");
382 | int one = 1;
383 | int r = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
384 | sizeof(one));
385 | if (r < 0)
386 | PFATAL("setsockopt()");
387 |
388 | struct sockaddr_in sin;
389 | memset(&sin, 0, sizeof(sin));
390 | sin.sin_family = AF_INET;
391 | sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
392 | sin.sin_port = 0; // assign any free
393 | if (bind(sd, (void *)&sin, sizeof(sin)) < 0)
394 | PFATAL("bind");
395 |
396 | r = listen(sd, 16);
397 | if (r < 0)
398 | PFATAL("listen()");
399 |
400 | struct sockaddr_in bind_sin;
401 | socklen_t bind_sin_len = sizeof(bind_sin);
402 | r = getsockname(sd, &bind_sin, &bind_sin_len);
403 | if (r < 0)
404 | PFATAL("getsockname()");
405 | if (bind_sin_len != sizeof(bind_sin))
406 | FATAL("getsockname length");
407 |
408 |
409 | cd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
410 | if (cd < 0)
411 | PFATAL("socket()");
412 |
413 | r = connect(cd, &bind_sin, sizeof(bind_sin));
414 | if (r < 0)
415 | PFATAL("connect()");
416 |
417 | rd = accept(sd, NULL, NULL);
418 | if (rd < 0)
419 | PFATAL("accept()");
420 |
421 | if (fcntl(rd, F_SETFD, FD_CLOEXEC) == -1)
422 | PFATAL("fcntl(FD_CLOEXEC)");
423 |
424 | /* Don't need bind socket anymore */
425 | close(sd);
426 | }
427 |
428 | char buf[128];
429 |
430 | int r = write(cd, buf, sizeof(buf));
431 | if (r != 128)
432 | PFATAL("write()");
433 |
434 | r = read(rd, buf, sizeof(buf));
435 | if (r != 128)
436 | PFATAL("read()");
437 |
438 | }
439 |
--------------------------------------------------------------------------------
/src/parent.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "list.h"
11 | #include "types.h"
12 | #include "trace.h"
13 | #include "fluxcapacitor.h"
14 |
15 | extern struct options options;
16 |
17 |
18 | struct parent *parent_new() {
19 | struct parent *parent = calloc(1, sizeof(struct parent));
20 |
21 | INIT_LIST_HEAD(&parent->list_of_children);
22 | INIT_LIST_HEAD(&parent->list_of_blocked);
23 |
24 | return parent;
25 | }
26 |
27 | void parent_run_one(struct parent *parent, struct trace *trace,
28 | char **child_argv) {
29 | int pid = trace_execvp(trace, child_argv);
30 | char *flat_argv = argv_join(child_argv, " ");
31 | SHOUT("[+] %i running: %s", pid, flat_argv);
32 | free(flat_argv);
33 | }
34 |
35 | struct child *parent_min_timeout_child(struct parent *parent) {
36 | struct child *min_child = NULL;
37 |
38 | /* All children must be blocking */
39 | if (parent->blocked_count != parent->child_count)
40 | FATAL("");
41 |
42 | struct list_head *pos = NULL;
43 | list_for_each(pos, &parent->list_of_children) {
44 | struct child *child = hlist_entry(pos, struct child, in_children);
45 | if (child->blocked_until != TIMEOUT_UNKNOWN) {
46 | if (!min_child ||
47 | min_child->blocked_until > child->blocked_until) {
48 | min_child = child;
49 | }
50 | }
51 | }
52 |
53 | if (!min_child ||
54 | min_child->blocked_until <= 0 ||
55 | min_child->blocked_until == TIMEOUT_FOREVER) {
56 | return NULL;
57 | }
58 | return min_child;
59 | }
60 |
61 | static char read_process_status(int stat_fd) {
62 | char buf[1024] = {0};
63 |
64 | int r = pread(stat_fd, buf, sizeof(buf), 0);
65 | if (r < 16 || r == sizeof(buf))
66 | PFATAL("pread(): Error while reading /proc/[pid]/stat");
67 | buf[r] = '\0';
68 |
69 | // Let's pray there aren't parenthesis in the program name
70 | char *p = strchr(buf, ')');
71 | if (p[0] != ')')
72 | FATAL("");
73 | if (p[1] != ' ')
74 | FATAL("");
75 | return p[2];
76 | }
77 |
78 | struct child *parent_woken_child(struct parent *parent) {
79 | struct list_head *pos = NULL;
80 | list_for_each(pos, &parent->list_of_children) {
81 | struct child *child = hlist_entry(pos, struct child, in_children);
82 |
83 | child->stat = read_process_status(child->stat_fd);
84 | if (child->stat != 'S')
85 | return child;
86 | }
87 | return NULL;
88 | }
89 |
90 | void parent_kill_all(struct parent *parent, int signo) {
91 | struct list_head *pos = NULL;
92 | list_for_each(pos, &parent->list_of_children) {
93 | struct child *child = hlist_entry(pos, struct child, in_children);
94 | kill(child->pid, signo);
95 | }
96 | }
97 |
98 | void child_kill(struct child *child, int signo) {
99 | kill(child->pid, signo);
100 | }
101 |
102 | struct child *child_new(struct parent *parent, struct trace_process *process,
103 | int pid) {
104 | struct child *child = calloc(1, sizeof(struct child));
105 | child->blocked_until = TIMEOUT_UNKNOWN;
106 | child->pid = pid;
107 | child->process = process;
108 | child->parent = parent;
109 |
110 | char fname[64] = {0};
111 | snprintf(fname, sizeof(fname), "/proc/%i/stat", pid);
112 |
113 | child->stat_fd = open(fname, O_RDONLY | O_CLOEXEC);
114 | if (child->stat_fd < 0)
115 | PFATAL("open(%s, O_RDONLY)", fname);
116 |
117 | list_add(&child->in_children, &parent->list_of_children);
118 | parent->child_count += 1;
119 | return child;
120 | }
121 |
122 | void child_del(struct child *child) {
123 | if (child->blocked)
124 | child_mark_unblocked(child);
125 | list_del(&child->in_children);
126 | child->pid = 0;
127 | child->parent->child_count -= 1;
128 | close(child->stat_fd);
129 | free(child);
130 | }
131 |
132 |
133 | void child_mark_blocked(struct child *child) {
134 | if (child->blocked)
135 | FATAL("");
136 |
137 | child->blocked = 1;
138 | child->blocked_until = TIMEOUT_UNKNOWN;
139 | list_add(&child->in_blocked, &child->parent->list_of_blocked);
140 | child->parent->blocked_count += 1;
141 | }
142 |
143 | void child_mark_unblocked(struct child *child) {
144 | if (!child->blocked)
145 | FATAL("");
146 |
147 | child->blocked = 0;
148 | list_del(&child->in_blocked);
149 | child->parent->blocked_count -= 1;
150 | }
151 |
--------------------------------------------------------------------------------
/src/preload.c:
--------------------------------------------------------------------------------
1 | #define _GNU_SOURCE
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 | #include
10 | #include
11 |
12 | #include "types.h"
13 | #include "scnums.h"
14 |
15 | static int (*libc_gettimeofday)(struct timeval *tv, struct timezone *tz);
16 | static int (*libc_ftime)(struct timeb *tp);
17 | static int (*libc_nanosleep)(const struct timespec *req, struct timespec *rem);
18 |
19 | #define ERRORF(x...) fprintf(stderr, x)
20 | #define FATAL(x...) do { \
21 | ERRORF("[-] PROGRAM ABORT : " x); \
22 | ERRORF("\n Location : %s(), %s:%u\n\n", \
23 | __FUNCTION__, __FILE__, __LINE__); \
24 | exit(EXIT_FAILURE); \
25 | } while (0)
26 |
27 | #if __GNUC__ >= 4
28 | # define PUBLIC __attribute__ ((visibility ("default")))
29 | #else
30 | # define PUBLIC
31 | #endif
32 |
33 | /* Not even attempting:
34 | *
35 | * alarm(2), ualarm(2), signalfd(2), timer_create(2),
36 | * timerfd_create(2), setitimer(2), rtc(4) */
37 |
38 | #define TIMESPEC_NSEC(ts) ((ts)->tv_sec * 1000000000ULL + (ts)->tv_nsec)
39 | #define NSEC_TIMESPEC(ns) (struct timespec){(ns) / 1000000000ULL, (ns) % 1000000000ULL}
40 |
41 | PUBLIC
42 | int clock_gettime(clockid_t clk_id, struct timespec *tp) {
43 | /* Ignore clk_id. Don't use libc version - we want a
44 | * ptrace-able syscall not a vdso call. */
45 | return syscall(__NR_clock_gettime, CLOCK_REALTIME, tp);
46 | }
47 |
48 | /* Translate to clock_gettime() */
49 | PUBLIC
50 | int gettimeofday(struct timeval *tv, struct timezone *tz) {
51 | long a = 0, b = 0;
52 | if (tv) {
53 | struct timespec ts;
54 | a = syscall(__NR_clock_gettime, CLOCK_REALTIME, &ts);
55 | *tv = (struct timeval){ts.tv_sec, ts.tv_nsec / 1000ULL};
56 | }
57 | if (tz) {
58 | struct timeval tmp;
59 | b = libc_gettimeofday(&tmp, tz);
60 | }
61 | return a || b;
62 | }
63 |
64 | PUBLIC
65 | time_t time(time_t *t) {
66 | struct timespec ts;
67 | syscall(__NR_clock_gettime, CLOCK_REALTIME, &ts);
68 | if (t) {
69 | *t = ts.tv_sec;
70 | }
71 | return ts.tv_sec;
72 | }
73 |
74 | PUBLIC
75 | int ftime(struct timeb *tp) {
76 | if (tp) {
77 | libc_ftime(tp);
78 | struct timespec ts;
79 | syscall(__NR_clock_gettime, CLOCK_REALTIME, &ts);
80 | tp->time = ts.tv_sec;
81 | tp->millitm = ts.tv_nsec / 1000000ULL;
82 | }
83 | return 0;
84 | }
85 |
86 | PUBLIC
87 | int nanosleep(const struct timespec *req, struct timespec *rem) {
88 | return libc_nanosleep(req, rem);
89 | }
90 |
91 | PUBLIC
92 | int clock_nanosleep(clockid_t clk_id, int flags,
93 | const struct timespec *request,
94 | struct timespec *remain) {
95 | /* As for clock_gettime() - ignore clk_id */
96 | struct timespec tmp;
97 | clock_gettime(CLOCK_REALTIME, &tmp);
98 | u64 now = TIMESPEC_NSEC(&tmp);
99 | u64 end, diff;
100 | if (flags & TIMER_ABSTIME) {
101 | end = TIMESPEC_NSEC(request);
102 | if (end > now) {
103 | diff = end - now;
104 | } else {
105 | diff = 0;
106 | }
107 | } else {
108 | end = now + TIMESPEC_NSEC(request);
109 | diff = TIMESPEC_NSEC(request);
110 | }
111 | tmp = NSEC_TIMESPEC(diff);
112 | int r = libc_nanosleep(&tmp, NULL);
113 | if (r == 0 && remain) {
114 | clock_gettime(CLOCK_REALTIME, &tmp);
115 | u64 t2 = TIMESPEC_NSEC(&tmp);
116 | if (end > t2) {
117 | *remain = NSEC_TIMESPEC(end - t2);
118 | } else {
119 | *remain = NSEC_TIMESPEC(0);
120 | }
121 | }
122 | return r;
123 | }
124 |
125 |
126 | static void __attribute__ ((constructor)) my_init(void) {
127 | static void *libc_handle;
128 | libc_handle = dlopen("libc.so.6", RTLD_LAZY | RTLD_GLOBAL | RTLD_NOLOAD);
129 | if (!libc_handle) {
130 | FATAL("[-] dlopen(): %s", dlerror());
131 | }
132 |
133 | char *error;
134 |
135 | libc_gettimeofday = dlsym(libc_handle, "gettimeofday");
136 | error = dlerror();
137 | if (error != NULL) {
138 | FATAL("[-] dlsym(): %s", error);
139 | }
140 |
141 | libc_ftime = dlsym(libc_handle, "ftime");
142 | error = dlerror();
143 | if (error != NULL) {
144 | FATAL("[-] dlsym(): %s", error);
145 | }
146 |
147 | libc_nanosleep = dlsym(libc_handle, "nanosleep");
148 | error = dlerror();
149 | if (error != NULL) {
150 | FATAL("[-] dlsym(): %s", error);
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/scnums.h:
--------------------------------------------------------------------------------
1 | #if defined(__x86_64__)
2 | # include "scnums_amd64.h"
3 | #elif defined(__i386__)
4 | # include "scnums_x86.h"
5 | #elif defined(__arm__)
6 | # include "scnums_arm.h"
7 | #else
8 | # error "Unknown architecture!"
9 | #endif
10 |
--------------------------------------------------------------------------------
/src/scnums_amd64.h:
--------------------------------------------------------------------------------
1 | #ifndef _SCNUMS_AMD64_H
2 | #define _SCNUMS_AMD64_H
3 | /*
4 | Derived from kernel sycall_64.tbl
5 |
6 | cat linux/arch/x86/syscalls/syscall_64.tbl| \
7 | egrep -v "^#"| \
8 | sed 's|^\([0-9]\+\)\s\+\w\+\s\+\(\w\+\).*$|#define __NR_\2\t\t\t\1|g' \
9 | > scnums-amd64.h
10 |
11 | cat linux/arch/x86/syscalls/syscall_64.tbl| \
12 | egrep -v "^#"| \
13 | sed 's|^\([0-9]\+\)\s\+\w\+\s\+\(\w\+\).*$|\t[__NR_\2] = "\2",|g' \
14 | >> scnums-amd64.h
15 | */
16 |
17 | #define __NR_read 0
18 | #define __NR_write 1
19 | #define __NR_open 2
20 | #define __NR_close 3
21 | #define __NR_stat 4
22 | #define __NR_fstat 5
23 | #define __NR_lstat 6
24 | #define __NR_poll 7
25 | #define __NR_lseek 8
26 | #define __NR_mmap 9
27 | #define __NR_mprotect 10
28 | #define __NR_munmap 11
29 | #define __NR_brk 12
30 | #define __NR_rt_sigaction 13
31 | #define __NR_rt_sigprocmask 14
32 | #define __NR_rt_sigreturn 15
33 | #define __NR_ioctl 16
34 | #define __NR_pread64 17
35 | #define __NR_pwrite64 18
36 | #define __NR_readv 19
37 | #define __NR_writev 20
38 | #define __NR_access 21
39 | #define __NR_pipe 22
40 | #define __NR_select 23
41 | #define __NR_sched_yield 24
42 | #define __NR_mremap 25
43 | #define __NR_msync 26
44 | #define __NR_mincore 27
45 | #define __NR_madvise 28
46 | #define __NR_shmget 29
47 | #define __NR_shmat 30
48 | #define __NR_shmctl 31
49 | #define __NR_dup 32
50 | #define __NR_dup2 33
51 | #define __NR_pause 34
52 | #define __NR_nanosleep 35
53 | #define __NR_getitimer 36
54 | #define __NR_alarm 37
55 | #define __NR_setitimer 38
56 | #define __NR_getpid 39
57 | #define __NR_sendfile 40
58 | #define __NR_socket 41
59 | #define __NR_connect 42
60 | #define __NR_accept 43
61 | #define __NR_sendto 44
62 | #define __NR_recvfrom 45
63 | #define __NR_sendmsg 46
64 | #define __NR_recvmsg 47
65 | #define __NR_shutdown 48
66 | #define __NR_bind 49
67 | #define __NR_listen 50
68 | #define __NR_getsockname 51
69 | #define __NR_getpeername 52
70 | #define __NR_socketpair 53
71 | #define __NR_setsockopt 54
72 | #define __NR_getsockopt 55
73 | #define __NR_clone 56
74 | #define __NR_fork 57
75 | #define __NR_vfork 58
76 | #define __NR_execve 59
77 | #define __NR_exit 60
78 | #define __NR_wait4 61
79 | #define __NR_kill 62
80 | #define __NR_uname 63
81 | #define __NR_semget 64
82 | #define __NR_semop 65
83 | #define __NR_semctl 66
84 | #define __NR_shmdt 67
85 | #define __NR_msgget 68
86 | #define __NR_msgsnd 69
87 | #define __NR_msgrcv 70
88 | #define __NR_msgctl 71
89 | #define __NR_fcntl 72
90 | #define __NR_flock 73
91 | #define __NR_fsync 74
92 | #define __NR_fdatasync 75
93 | #define __NR_truncate 76
94 | #define __NR_ftruncate 77
95 | #define __NR_getdents 78
96 | #define __NR_getcwd 79
97 | #define __NR_chdir 80
98 | #define __NR_fchdir 81
99 | #define __NR_rename 82
100 | #define __NR_mkdir 83
101 | #define __NR_rmdir 84
102 | #define __NR_creat 85
103 | #define __NR_link 86
104 | #define __NR_unlink 87
105 | #define __NR_symlink 88
106 | #define __NR_readlink 89
107 | #define __NR_chmod 90
108 | #define __NR_fchmod 91
109 | #define __NR_chown 92
110 | #define __NR_fchown 93
111 | #define __NR_lchown 94
112 | #define __NR_umask 95
113 | #define __NR_gettimeofday 96
114 | #define __NR_getrlimit 97
115 | #define __NR_getrusage 98
116 | #define __NR_sysinfo 99
117 | #define __NR_times 100
118 | #define __NR_ptrace 101
119 | #define __NR_getuid 102
120 | #define __NR_syslog 103
121 | #define __NR_getgid 104
122 | #define __NR_setuid 105
123 | #define __NR_setgid 106
124 | #define __NR_geteuid 107
125 | #define __NR_getegid 108
126 | #define __NR_setpgid 109
127 | #define __NR_getppid 110
128 | #define __NR_getpgrp 111
129 | #define __NR_setsid 112
130 | #define __NR_setreuid 113
131 | #define __NR_setregid 114
132 | #define __NR_getgroups 115
133 | #define __NR_setgroups 116
134 | #define __NR_setresuid 117
135 | #define __NR_getresuid 118
136 | #define __NR_setresgid 119
137 | #define __NR_getresgid 120
138 | #define __NR_getpgid 121
139 | #define __NR_setfsuid 122
140 | #define __NR_setfsgid 123
141 | #define __NR_getsid 124
142 | #define __NR_capget 125
143 | #define __NR_capset 126
144 | #define __NR_rt_sigpending 127
145 | #define __NR_rt_sigtimedwait 128
146 | #define __NR_rt_sigqueueinfo 129
147 | #define __NR_rt_sigsuspend 130
148 | #define __NR_sigaltstack 131
149 | #define __NR_utime 132
150 | #define __NR_mknod 133
151 | #define __NR_uselib 134
152 | #define __NR_personality 135
153 | #define __NR_ustat 136
154 | #define __NR_statfs 137
155 | #define __NR_fstatfs 138
156 | #define __NR_sysfs 139
157 | #define __NR_getpriority 140
158 | #define __NR_setpriority 141
159 | #define __NR_sched_setparam 142
160 | #define __NR_sched_getparam 143
161 | #define __NR_sched_setscheduler 144
162 | #define __NR_sched_getscheduler 145
163 | #define __NR_sched_get_priority_max 146
164 | #define __NR_sched_get_priority_min 147
165 | #define __NR_sched_rr_get_interval 148
166 | #define __NR_mlock 149
167 | #define __NR_munlock 150
168 | #define __NR_mlockall 151
169 | #define __NR_munlockall 152
170 | #define __NR_vhangup 153
171 | #define __NR_modify_ldt 154
172 | #define __NR_pivot_root 155
173 | #define __NR__sysctl 156
174 | #define __NR_prctl 157
175 | #define __NR_arch_prctl 158
176 | #define __NR_adjtimex 159
177 | #define __NR_setrlimit 160
178 | #define __NR_chroot 161
179 | #define __NR_sync 162
180 | #define __NR_acct 163
181 | #define __NR_settimeofday 164
182 | #define __NR_mount 165
183 | #define __NR_umount2 166
184 | #define __NR_swapon 167
185 | #define __NR_swapoff 168
186 | #define __NR_reboot 169
187 | #define __NR_sethostname 170
188 | #define __NR_setdomainname 171
189 | #define __NR_iopl 172
190 | #define __NR_ioperm 173
191 | #define __NR_create_module 174
192 | #define __NR_init_module 175
193 | #define __NR_delete_module 176
194 | #define __NR_get_kernel_syms 177
195 | #define __NR_query_module 178
196 | #define __NR_quotactl 179
197 | #define __NR_nfsservctl 180
198 | #define __NR_getpmsg 181
199 | #define __NR_putpmsg 182
200 | #define __NR_afs_syscall 183
201 | #define __NR_tuxcall 184
202 | #define __NR_security 185
203 | #define __NR_gettid 186
204 | #define __NR_readahead 187
205 | #define __NR_setxattr 188
206 | #define __NR_lsetxattr 189
207 | #define __NR_fsetxattr 190
208 | #define __NR_getxattr 191
209 | #define __NR_lgetxattr 192
210 | #define __NR_fgetxattr 193
211 | #define __NR_listxattr 194
212 | #define __NR_llistxattr 195
213 | #define __NR_flistxattr 196
214 | #define __NR_removexattr 197
215 | #define __NR_lremovexattr 198
216 | #define __NR_fremovexattr 199
217 | #define __NR_tkill 200
218 | #define __NR_time 201
219 | #define __NR_futex 202
220 | #define __NR_sched_setaffinity 203
221 | #define __NR_sched_getaffinity 204
222 | #define __NR_set_thread_area 205
223 | #define __NR_io_setup 206
224 | #define __NR_io_destroy 207
225 | #define __NR_io_getevents 208
226 | #define __NR_io_submit 209
227 | #define __NR_io_cancel 210
228 | #define __NR_get_thread_area 211
229 | #define __NR_lookup_dcookie 212
230 | #define __NR_epoll_create 213
231 | #define __NR_epoll_ctl_old 214
232 | #define __NR_epoll_wait_old 215
233 | #define __NR_remap_file_pages 216
234 | #define __NR_getdents64 217
235 | #define __NR_set_tid_address 218
236 | #define __NR_restart_syscall 219
237 | #define __NR_semtimedop 220
238 | #define __NR_fadvise64 221
239 | #define __NR_timer_create 222
240 | #define __NR_timer_settime 223
241 | #define __NR_timer_gettime 224
242 | #define __NR_timer_getoverrun 225
243 | #define __NR_timer_delete 226
244 | #define __NR_clock_settime 227
245 | #define __NR_clock_gettime 228
246 | #define __NR_clock_getres 229
247 | #define __NR_clock_nanosleep 230
248 | #define __NR_exit_group 231
249 | #define __NR_epoll_wait 232
250 | #define __NR_epoll_ctl 233
251 | #define __NR_tgkill 234
252 | #define __NR_utimes 235
253 | #define __NR_vserver 236
254 | #define __NR_mbind 237
255 | #define __NR_set_mempolicy 238
256 | #define __NR_get_mempolicy 239
257 | #define __NR_mq_open 240
258 | #define __NR_mq_unlink 241
259 | #define __NR_mq_timedsend 242
260 | #define __NR_mq_timedreceive 243
261 | #define __NR_mq_notify 244
262 | #define __NR_mq_getsetattr 245
263 | #define __NR_kexec_load 246
264 | #define __NR_waitid 247
265 | #define __NR_add_key 248
266 | #define __NR_request_key 249
267 | #define __NR_keyctl 250
268 | #define __NR_ioprio_set 251
269 | #define __NR_ioprio_get 252
270 | #define __NR_inotify_init 253
271 | #define __NR_inotify_add_watch 254
272 | #define __NR_inotify_rm_watch 255
273 | #define __NR_migrate_pages 256
274 | #define __NR_openat 257
275 | #define __NR_mkdirat 258
276 | #define __NR_mknodat 259
277 | #define __NR_fchownat 260
278 | #define __NR_futimesat 261
279 | #define __NR_newfstatat 262
280 | #define __NR_unlinkat 263
281 | #define __NR_renameat 264
282 | #define __NR_linkat 265
283 | #define __NR_symlinkat 266
284 | #define __NR_readlinkat 267
285 | #define __NR_fchmodat 268
286 | #define __NR_faccessat 269
287 | #define __NR_pselect6 270
288 | #define __NR_ppoll 271
289 | #define __NR_unshare 272
290 | #define __NR_set_robust_list 273
291 | #define __NR_get_robust_list 274
292 | #define __NR_splice 275
293 | #define __NR_tee 276
294 | #define __NR_sync_file_range 277
295 | #define __NR_vmsplice 278
296 | #define __NR_move_pages 279
297 | #define __NR_utimensat 280
298 | #define __NR_epoll_pwait 281
299 | #define __NR_signalfd 282
300 | #define __NR_timerfd_create 283
301 | #define __NR_eventfd 284
302 | #define __NR_fallocate 285
303 | #define __NR_timerfd_settime 286
304 | #define __NR_timerfd_gettime 287
305 | #define __NR_accept4 288
306 | #define __NR_signalfd4 289
307 | #define __NR_eventfd2 290
308 | #define __NR_epoll_create1 291
309 | #define __NR_dup3 292
310 | #define __NR_pipe2 293
311 | #define __NR_inotify_init1 294
312 | #define __NR_preadv 295
313 | #define __NR_pwritev 296
314 | #define __NR_rt_tgsigqueueinfo 297
315 | #define __NR_perf_event_open 298
316 | #define __NR_recvmmsg 299
317 | #define __NR_fanotify_init 300
318 | #define __NR_fanotify_mark 301
319 | #define __NR_prlimit64 302
320 | #define __NR_name_to_handle_at 303
321 | #define __NR_open_by_handle_at 304
322 | #define __NR_clock_adjtime 305
323 | #define __NR_syncfs 306
324 | #define __NR_sendmmsg 307
325 | #define __NR_setns 308
326 | #define __NR_getcpu 309
327 | #define __NR_process_vm_readv 310
328 | #define __NR_process_vm_writev 311
329 | #define __NR_kcmp 312
330 |
331 | static const char *const syscall_to_str_map[] = {
332 | [__NR_read] = "read",
333 | [__NR_write] = "write",
334 | [__NR_open] = "open",
335 | [__NR_close] = "close",
336 | [__NR_stat] = "stat",
337 | [__NR_fstat] = "fstat",
338 | [__NR_lstat] = "lstat",
339 | [__NR_poll] = "poll",
340 | [__NR_lseek] = "lseek",
341 | [__NR_mmap] = "mmap",
342 | [__NR_mprotect] = "mprotect",
343 | [__NR_munmap] = "munmap",
344 | [__NR_brk] = "brk",
345 | [__NR_rt_sigaction] = "rt_sigaction",
346 | [__NR_rt_sigprocmask] = "rt_sigprocmask",
347 | [__NR_rt_sigreturn] = "rt_sigreturn",
348 | [__NR_ioctl] = "ioctl",
349 | [__NR_pread64] = "pread64",
350 | [__NR_pwrite64] = "pwrite64",
351 | [__NR_readv] = "readv",
352 | [__NR_writev] = "writev",
353 | [__NR_access] = "access",
354 | [__NR_pipe] = "pipe",
355 | [__NR_select] = "select",
356 | [__NR_sched_yield] = "sched_yield",
357 | [__NR_mremap] = "mremap",
358 | [__NR_msync] = "msync",
359 | [__NR_mincore] = "mincore",
360 | [__NR_madvise] = "madvise",
361 | [__NR_shmget] = "shmget",
362 | [__NR_shmat] = "shmat",
363 | [__NR_shmctl] = "shmctl",
364 | [__NR_dup] = "dup",
365 | [__NR_dup2] = "dup2",
366 | [__NR_pause] = "pause",
367 | [__NR_nanosleep] = "nanosleep",
368 | [__NR_getitimer] = "getitimer",
369 | [__NR_alarm] = "alarm",
370 | [__NR_setitimer] = "setitimer",
371 | [__NR_getpid] = "getpid",
372 | [__NR_sendfile] = "sendfile",
373 | [__NR_socket] = "socket",
374 | [__NR_connect] = "connect",
375 | [__NR_accept] = "accept",
376 | [__NR_sendto] = "sendto",
377 | [__NR_recvfrom] = "recvfrom",
378 | [__NR_sendmsg] = "sendmsg",
379 | [__NR_recvmsg] = "recvmsg",
380 | [__NR_shutdown] = "shutdown",
381 | [__NR_bind] = "bind",
382 | [__NR_listen] = "listen",
383 | [__NR_getsockname] = "getsockname",
384 | [__NR_getpeername] = "getpeername",
385 | [__NR_socketpair] = "socketpair",
386 | [__NR_setsockopt] = "setsockopt",
387 | [__NR_getsockopt] = "getsockopt",
388 | [__NR_clone] = "clone",
389 | [__NR_fork] = "fork",
390 | [__NR_vfork] = "vfork",
391 | [__NR_execve] = "execve",
392 | [__NR_exit] = "exit",
393 | [__NR_wait4] = "wait4",
394 | [__NR_kill] = "kill",
395 | [__NR_uname] = "uname",
396 | [__NR_semget] = "semget",
397 | [__NR_semop] = "semop",
398 | [__NR_semctl] = "semctl",
399 | [__NR_shmdt] = "shmdt",
400 | [__NR_msgget] = "msgget",
401 | [__NR_msgsnd] = "msgsnd",
402 | [__NR_msgrcv] = "msgrcv",
403 | [__NR_msgctl] = "msgctl",
404 | [__NR_fcntl] = "fcntl",
405 | [__NR_flock] = "flock",
406 | [__NR_fsync] = "fsync",
407 | [__NR_fdatasync] = "fdatasync",
408 | [__NR_truncate] = "truncate",
409 | [__NR_ftruncate] = "ftruncate",
410 | [__NR_getdents] = "getdents",
411 | [__NR_getcwd] = "getcwd",
412 | [__NR_chdir] = "chdir",
413 | [__NR_fchdir] = "fchdir",
414 | [__NR_rename] = "rename",
415 | [__NR_mkdir] = "mkdir",
416 | [__NR_rmdir] = "rmdir",
417 | [__NR_creat] = "creat",
418 | [__NR_link] = "link",
419 | [__NR_unlink] = "unlink",
420 | [__NR_symlink] = "symlink",
421 | [__NR_readlink] = "readlink",
422 | [__NR_chmod] = "chmod",
423 | [__NR_fchmod] = "fchmod",
424 | [__NR_chown] = "chown",
425 | [__NR_fchown] = "fchown",
426 | [__NR_lchown] = "lchown",
427 | [__NR_umask] = "umask",
428 | [__NR_gettimeofday] = "gettimeofday",
429 | [__NR_getrlimit] = "getrlimit",
430 | [__NR_getrusage] = "getrusage",
431 | [__NR_sysinfo] = "sysinfo",
432 | [__NR_times] = "times",
433 | [__NR_ptrace] = "ptrace",
434 | [__NR_getuid] = "getuid",
435 | [__NR_syslog] = "syslog",
436 | [__NR_getgid] = "getgid",
437 | [__NR_setuid] = "setuid",
438 | [__NR_setgid] = "setgid",
439 | [__NR_geteuid] = "geteuid",
440 | [__NR_getegid] = "getegid",
441 | [__NR_setpgid] = "setpgid",
442 | [__NR_getppid] = "getppid",
443 | [__NR_getpgrp] = "getpgrp",
444 | [__NR_setsid] = "setsid",
445 | [__NR_setreuid] = "setreuid",
446 | [__NR_setregid] = "setregid",
447 | [__NR_getgroups] = "getgroups",
448 | [__NR_setgroups] = "setgroups",
449 | [__NR_setresuid] = "setresuid",
450 | [__NR_getresuid] = "getresuid",
451 | [__NR_setresgid] = "setresgid",
452 | [__NR_getresgid] = "getresgid",
453 | [__NR_getpgid] = "getpgid",
454 | [__NR_setfsuid] = "setfsuid",
455 | [__NR_setfsgid] = "setfsgid",
456 | [__NR_getsid] = "getsid",
457 | [__NR_capget] = "capget",
458 | [__NR_capset] = "capset",
459 | [__NR_rt_sigpending] = "rt_sigpending",
460 | [__NR_rt_sigtimedwait] = "rt_sigtimedwait",
461 | [__NR_rt_sigqueueinfo] = "rt_sigqueueinfo",
462 | [__NR_rt_sigsuspend] = "rt_sigsuspend",
463 | [__NR_sigaltstack] = "sigaltstack",
464 | [__NR_utime] = "utime",
465 | [__NR_mknod] = "mknod",
466 | [__NR_uselib] = "uselib",
467 | [__NR_personality] = "personality",
468 | [__NR_ustat] = "ustat",
469 | [__NR_statfs] = "statfs",
470 | [__NR_fstatfs] = "fstatfs",
471 | [__NR_sysfs] = "sysfs",
472 | [__NR_getpriority] = "getpriority",
473 | [__NR_setpriority] = "setpriority",
474 | [__NR_sched_setparam] = "sched_setparam",
475 | [__NR_sched_getparam] = "sched_getparam",
476 | [__NR_sched_setscheduler] = "sched_setscheduler",
477 | [__NR_sched_getscheduler] = "sched_getscheduler",
478 | [__NR_sched_get_priority_max] = "sched_get_priority_max",
479 | [__NR_sched_get_priority_min] = "sched_get_priority_min",
480 | [__NR_sched_rr_get_interval] = "sched_rr_get_interval",
481 | [__NR_mlock] = "mlock",
482 | [__NR_munlock] = "munlock",
483 | [__NR_mlockall] = "mlockall",
484 | [__NR_munlockall] = "munlockall",
485 | [__NR_vhangup] = "vhangup",
486 | [__NR_modify_ldt] = "modify_ldt",
487 | [__NR_pivot_root] = "pivot_root",
488 | [__NR__sysctl] = "_sysctl",
489 | [__NR_prctl] = "prctl",
490 | [__NR_arch_prctl] = "arch_prctl",
491 | [__NR_adjtimex] = "adjtimex",
492 | [__NR_setrlimit] = "setrlimit",
493 | [__NR_chroot] = "chroot",
494 | [__NR_sync] = "sync",
495 | [__NR_acct] = "acct",
496 | [__NR_settimeofday] = "settimeofday",
497 | [__NR_mount] = "mount",
498 | [__NR_umount2] = "umount2",
499 | [__NR_swapon] = "swapon",
500 | [__NR_swapoff] = "swapoff",
501 | [__NR_reboot] = "reboot",
502 | [__NR_sethostname] = "sethostname",
503 | [__NR_setdomainname] = "setdomainname",
504 | [__NR_iopl] = "iopl",
505 | [__NR_ioperm] = "ioperm",
506 | [__NR_create_module] = "create_module",
507 | [__NR_init_module] = "init_module",
508 | [__NR_delete_module] = "delete_module",
509 | [__NR_get_kernel_syms] = "get_kernel_syms",
510 | [__NR_query_module] = "query_module",
511 | [__NR_quotactl] = "quotactl",
512 | [__NR_nfsservctl] = "nfsservctl",
513 | [__NR_getpmsg] = "getpmsg",
514 | [__NR_putpmsg] = "putpmsg",
515 | [__NR_afs_syscall] = "afs_syscall",
516 | [__NR_tuxcall] = "tuxcall",
517 | [__NR_security] = "security",
518 | [__NR_gettid] = "gettid",
519 | [__NR_readahead] = "readahead",
520 | [__NR_setxattr] = "setxattr",
521 | [__NR_lsetxattr] = "lsetxattr",
522 | [__NR_fsetxattr] = "fsetxattr",
523 | [__NR_getxattr] = "getxattr",
524 | [__NR_lgetxattr] = "lgetxattr",
525 | [__NR_fgetxattr] = "fgetxattr",
526 | [__NR_listxattr] = "listxattr",
527 | [__NR_llistxattr] = "llistxattr",
528 | [__NR_flistxattr] = "flistxattr",
529 | [__NR_removexattr] = "removexattr",
530 | [__NR_lremovexattr] = "lremovexattr",
531 | [__NR_fremovexattr] = "fremovexattr",
532 | [__NR_tkill] = "tkill",
533 | [__NR_time] = "time",
534 | [__NR_futex] = "futex",
535 | [__NR_sched_setaffinity] = "sched_setaffinity",
536 | [__NR_sched_getaffinity] = "sched_getaffinity",
537 | [__NR_set_thread_area] = "set_thread_area",
538 | [__NR_io_setup] = "io_setup",
539 | [__NR_io_destroy] = "io_destroy",
540 | [__NR_io_getevents] = "io_getevents",
541 | [__NR_io_submit] = "io_submit",
542 | [__NR_io_cancel] = "io_cancel",
543 | [__NR_get_thread_area] = "get_thread_area",
544 | [__NR_lookup_dcookie] = "lookup_dcookie",
545 | [__NR_epoll_create] = "epoll_create",
546 | [__NR_epoll_ctl_old] = "epoll_ctl_old",
547 | [__NR_epoll_wait_old] = "epoll_wait_old",
548 | [__NR_remap_file_pages] = "remap_file_pages",
549 | [__NR_getdents64] = "getdents64",
550 | [__NR_set_tid_address] = "set_tid_address",
551 | [__NR_restart_syscall] = "restart_syscall",
552 | [__NR_semtimedop] = "semtimedop",
553 | [__NR_fadvise64] = "fadvise64",
554 | [__NR_timer_create] = "timer_create",
555 | [__NR_timer_settime] = "timer_settime",
556 | [__NR_timer_gettime] = "timer_gettime",
557 | [__NR_timer_getoverrun] = "timer_getoverrun",
558 | [__NR_timer_delete] = "timer_delete",
559 | [__NR_clock_settime] = "clock_settime",
560 | [__NR_clock_gettime] = "clock_gettime",
561 | [__NR_clock_getres] = "clock_getres",
562 | [__NR_clock_nanosleep] = "clock_nanosleep",
563 | [__NR_exit_group] = "exit_group",
564 | [__NR_epoll_wait] = "epoll_wait",
565 | [__NR_epoll_ctl] = "epoll_ctl",
566 | [__NR_tgkill] = "tgkill",
567 | [__NR_utimes] = "utimes",
568 | [__NR_vserver] = "vserver",
569 | [__NR_mbind] = "mbind",
570 | [__NR_set_mempolicy] = "set_mempolicy",
571 | [__NR_get_mempolicy] = "get_mempolicy",
572 | [__NR_mq_open] = "mq_open",
573 | [__NR_mq_unlink] = "mq_unlink",
574 | [__NR_mq_timedsend] = "mq_timedsend",
575 | [__NR_mq_timedreceive] = "mq_timedreceive",
576 | [__NR_mq_notify] = "mq_notify",
577 | [__NR_mq_getsetattr] = "mq_getsetattr",
578 | [__NR_kexec_load] = "kexec_load",
579 | [__NR_waitid] = "waitid",
580 | [__NR_add_key] = "add_key",
581 | [__NR_request_key] = "request_key",
582 | [__NR_keyctl] = "keyctl",
583 | [__NR_ioprio_set] = "ioprio_set",
584 | [__NR_ioprio_get] = "ioprio_get",
585 | [__NR_inotify_init] = "inotify_init",
586 | [__NR_inotify_add_watch] = "inotify_add_watch",
587 | [__NR_inotify_rm_watch] = "inotify_rm_watch",
588 | [__NR_migrate_pages] = "migrate_pages",
589 | [__NR_openat] = "openat",
590 | [__NR_mkdirat] = "mkdirat",
591 | [__NR_mknodat] = "mknodat",
592 | [__NR_fchownat] = "fchownat",
593 | [__NR_futimesat] = "futimesat",
594 | [__NR_newfstatat] = "newfstatat",
595 | [__NR_unlinkat] = "unlinkat",
596 | [__NR_renameat] = "renameat",
597 | [__NR_linkat] = "linkat",
598 | [__NR_symlinkat] = "symlinkat",
599 | [__NR_readlinkat] = "readlinkat",
600 | [__NR_fchmodat] = "fchmodat",
601 | [__NR_faccessat] = "faccessat",
602 | [__NR_pselect6] = "pselect6",
603 | [__NR_ppoll] = "ppoll",
604 | [__NR_unshare] = "unshare",
605 | [__NR_set_robust_list] = "set_robust_list",
606 | [__NR_get_robust_list] = "get_robust_list",
607 | [__NR_splice] = "splice",
608 | [__NR_tee] = "tee",
609 | [__NR_sync_file_range] = "sync_file_range",
610 | [__NR_vmsplice] = "vmsplice",
611 | [__NR_move_pages] = "move_pages",
612 | [__NR_utimensat] = "utimensat",
613 | [__NR_epoll_pwait] = "epoll_pwait",
614 | [__NR_signalfd] = "signalfd",
615 | [__NR_timerfd_create] = "timerfd_create",
616 | [__NR_eventfd] = "eventfd",
617 | [__NR_fallocate] = "fallocate",
618 | [__NR_timerfd_settime] = "timerfd_settime",
619 | [__NR_timerfd_gettime] = "timerfd_gettime",
620 | [__NR_accept4] = "accept4",
621 | [__NR_signalfd4] = "signalfd4",
622 | [__NR_eventfd2] = "eventfd2",
623 | [__NR_epoll_create1] = "epoll_create1",
624 | [__NR_dup3] = "dup3",
625 | [__NR_pipe2] = "pipe2",
626 | [__NR_inotify_init1] = "inotify_init1",
627 | [__NR_preadv] = "preadv",
628 | [__NR_pwritev] = "pwritev",
629 | [__NR_rt_tgsigqueueinfo] = "rt_tgsigqueueinfo",
630 | [__NR_perf_event_open] = "perf_event_open",
631 | [__NR_recvmmsg] = "recvmmsg",
632 | [__NR_fanotify_init] = "fanotify_init",
633 | [__NR_fanotify_mark] = "fanotify_mark",
634 | [__NR_prlimit64] = "prlimit64",
635 | [__NR_name_to_handle_at] = "name_to_handle_at",
636 | [__NR_open_by_handle_at] = "open_by_handle_at",
637 | [__NR_clock_adjtime] = "clock_adjtime",
638 | [__NR_syncfs] = "syncfs",
639 | [__NR_sendmmsg] = "sendmmsg",
640 | [__NR_setns] = "setns",
641 | [__NR_getcpu] = "getcpu",
642 | [__NR_process_vm_readv] = "process_vm_readv",
643 | [__NR_process_vm_writev] = "process_vm_writev",
644 | [__NR_kcmp] = "kcmp",
645 |
646 | // x32-specific system call on amd64 start from 512
647 |
648 | [512] = "rt_sigaction",
649 | [513] = "rt_sigreturn",
650 | [514] = "ioctl",
651 | [515] = "readv",
652 | [516] = "writev",
653 | [517] = "recvfrom",
654 | [518] = "sendmsg",
655 | [519] = "recvmsg",
656 | [520] = "execve",
657 | [521] = "ptrace",
658 | [522] = "rt_sigpending",
659 | [523] = "rt_sigtimedwait",
660 | [524] = "rt_sigqueueinfo",
661 | [525] = "sigaltstack",
662 | [526] = "timer_create",
663 | [527] = "mq_notify",
664 | [528] = "kexec_load",
665 | [529] = "waitid",
666 | [530] = "set_robust_list",
667 | [531] = "get_robust_list",
668 | [532] = "vmsplice",
669 | [533] = "move_pages",
670 | [534] = "preadv",
671 | [535] = "pwritev",
672 | [536] = "rt_tgsigqueueinfo",
673 | [537] = "recvmmsg",
674 | [538] = "sendmmsg",
675 | [539] = "process_vm_readv",
676 | [540] = "process_vm_writev",
677 | [541] = "setsockopt",
678 | [542] = "getsockopt",
679 | };
680 |
681 | #endif /* _SCNUMS_AMD64_H */
682 |
--------------------------------------------------------------------------------
/src/scnums_arm.h:
--------------------------------------------------------------------------------
1 | #ifndef _SCNUMS_ARM_H
2 | #define _SCNUMS_ARM_H
3 | /*
4 | Derived from kernel arch/arm/include/asm/unistd.h
5 |
6 | cat arch/arm/include/uapi/asm/unistd.h| \
7 | grep NR_SYSCALL| \
8 | sed 's|^#define __NR_\(\w*\).*(__NR_SYSCALL_BASE[+]\([^\)]\+\)).*$|\t[\1] = "\1",|g' \
9 | scnums-arm.h
10 |
11 | */
12 |
13 | #define __NR_restart_syscall 0
14 | #define __NR_exit 1
15 | #define __NR_fork 2
16 | #define __NR_read 3
17 | #define __NR_write 4
18 | #define __NR_open 5
19 | #define __NR_close 6
20 | /* 7 was sys_waitpid */
21 | #define __NR_creat 8
22 | #define __NR_link 9
23 | #define __NR_unlink 10
24 | #define __NR_execve 11
25 | #define __NR_chdir 12
26 | /* 13 was sys_time, not in EABI */
27 | #define __NR_mknod 14
28 | #define __NR_chmod 15
29 | #define __NR_lchown 16
30 | /* 17 was sys_break */
31 | /* 18 was sys_stat */
32 | #define __NR_lseek 19
33 | #define __NR_getpid 20
34 | #define __NR_mount 21
35 | /* 22 was sys_umount, not in EABI*/
36 | #define __NR_setuid 23
37 | #define __NR_getuid 24
38 | /* 25 was sys_stime, not in EABI */
39 | #define __NR_ptrace 26
40 | /* 27 was sys_alarm, not in EABI */
41 | /* 28 was sys_fstat */
42 | #define __NR_pause 29
43 | /* 30 was sys_utime, not in EABI */
44 | /* 31 was sys_stty */
45 | /* 32 was sys_gtty */
46 | #define __NR_access 33
47 | #define __NR_nice 34
48 | /* 35 was sys_ftime */
49 | #define __NR_sync 36
50 | #define __NR_kill 37
51 | #define __NR_rename 38
52 | #define __NR_mkdir 39
53 | #define __NR_rmdir 40
54 | #define __NR_dup 41
55 | #define __NR_pipe 42
56 | #define __NR_times 43
57 | /* 44 was sys_prof */
58 | #define __NR_brk 45
59 | #define __NR_setgid 46
60 | #define __NR_getgid 47
61 | /* 48 was sys_signal */
62 | #define __NR_geteuid 49
63 | #define __NR_getegid 50
64 | #define __NR_acct 51
65 | #define __NR_umount2 52
66 | /* 53 was sys_lock */
67 | #define __NR_ioctl 54
68 | #define __NR_fcntl 55
69 | /* 56 was sys_mpx */
70 | #define __NR_setpgid 57
71 | /* 58 was sys_ulimit */
72 | /* 59 was sys_olduname */
73 | #define __NR_umask 60
74 | #define __NR_chroot 61
75 | #define __NR_ustat 62
76 | #define __NR_dup2 63
77 | #define __NR_getppid 64
78 | #define __NR_getpgrp 65
79 | #define __NR_setsid 66
80 | #define __NR_sigaction 67
81 | /* 68 was sys_sgetmask */
82 | /* 69 was sys_ssetmask */
83 | #define __NR_setreuid 70
84 | #define __NR_setregid 71
85 | #define __NR_sigsuspend 72
86 | #define __NR_sigpending 73
87 | #define __NR_sethostname 74
88 | #define __NR_setrlimit 75
89 | /* 76 was sys_getrlimit, not in EABI */
90 | #define __NR_getrusage 77
91 | #define __NR_gettimeofday 78
92 | #define __NR_settimeofday 79
93 | #define __NR_getgroups 80
94 | #define __NR_setgroups 81
95 | /* 82 was sys_select, not in EABI */
96 | #define __NR_symlink 83
97 | /* 84 was sys_lstat */
98 | #define __NR_readlink 85
99 | #define __NR_uselib 86
100 | #define __NR_swapon 87
101 | #define __NR_reboot 88
102 | /* 89 was sys_readdir, not in EABI */
103 | /* 90 was sys_mmap, not in EABI */
104 | #define __NR_munmap 91
105 | #define __NR_truncate 92
106 | #define __NR_ftruncate 93
107 | #define __NR_fchmod 94
108 | #define __NR_fchown 95
109 | #define __NR_getpriority 96
110 | #define __NR_setpriority 97
111 | /* 98 was sys_profil */
112 | #define __NR_statfs 99
113 | #define __NR_fstatfs 100
114 | /* 101 was sys_ioperm */
115 | /* 102 was sys_socketcall, not in EABI */
116 | #define __NR_syslog 103
117 | #define __NR_setitimer 104
118 | #define __NR_getitimer 105
119 | #define __NR_stat 106
120 | #define __NR_lstat 107
121 | #define __NR_fstat 108
122 | /* 109 was sys_uname */
123 | /* 110 was sys_iopl */
124 | #define __NR_vhangup 111
125 | /* 112 was sys_idle */
126 | /* 113 was sys_syscall, not in EABI */
127 | #define __NR_wait4 114
128 | #define __NR_swapoff 115
129 | #define __NR_sysinfo 116
130 | /* 117 was sys_ipc, not in EABI */
131 | #define __NR_fsync 118
132 | #define __NR_sigreturn 119
133 | #define __NR_clone 120
134 | #define __NR_setdomainname 121
135 | #define __NR_uname 122
136 | /* 123 was sys_modify_ldt */
137 | #define __NR_adjtimex 124
138 | #define __NR_mprotect 125
139 | #define __NR_sigprocmask 126
140 | /* 127 was sys_create_module */
141 | #define __NR_init_module 128
142 | #define __NR_delete_module 129
143 | /* 130 was sys_get_kernel_syms */
144 | #define __NR_quotactl 131
145 | #define __NR_getpgid 132
146 | #define __NR_fchdir 133
147 | #define __NR_bdflush 134
148 | #define __NR_sysfs 135
149 | #define __NR_personality 136
150 | /* 137 was sys_afs_syscall */
151 | #define __NR_setfsuid 138
152 | #define __NR_setfsgid 139
153 | #define __NR__llseek 140
154 | #define __NR_getdents 141
155 | #define __NR__newselect 142
156 | #define __NR_flock 143
157 | #define __NR_msync 144
158 | #define __NR_readv 145
159 | #define __NR_writev 146
160 | #define __NR_getsid 147
161 | #define __NR_fdatasync 148
162 | #define __NR__sysctl 149
163 | #define __NR_mlock 150
164 | #define __NR_munlock 151
165 | #define __NR_mlockall 152
166 | #define __NR_munlockall 153
167 | #define __NR_sched_setparam 154
168 | #define __NR_sched_getparam 155
169 | #define __NR_sched_setscheduler 156
170 | #define __NR_sched_getscheduler 157
171 | #define __NR_sched_yield 158
172 | #define __NR_sched_get_priority_max 159
173 | #define __NR_sched_get_priority_min 160
174 | #define __NR_sched_rr_get_interval 161
175 | #define __NR_nanosleep 162
176 | #define __NR_mremap 163
177 | #define __NR_setresuid 164
178 | #define __NR_getresuid 165
179 | /* 166 was sys_vm86 */
180 | /* 167 was sys_query_module */
181 | #define __NR_poll 168
182 | #define __NR_nfsservctl 169
183 | #define __NR_setresgid 170
184 | #define __NR_getresgid 171
185 | #define __NR_prctl 172
186 | #define __NR_rt_sigreturn 173
187 | #define __NR_rt_sigaction 174
188 | #define __NR_rt_sigprocmask 175
189 | #define __NR_rt_sigpending 176
190 | #define __NR_rt_sigtimedwait 177
191 | #define __NR_rt_sigqueueinfo 178
192 | #define __NR_rt_sigsuspend 179
193 | #define __NR_pread64 180
194 | #define __NR_pwrite64 181
195 | #define __NR_chown 182
196 | #define __NR_getcwd 183
197 | #define __NR_capget 184
198 | #define __NR_capset 185
199 | #define __NR_sigaltstack 186
200 | #define __NR_sendfile 187
201 | /* 188 reserved */
202 | /* 189 reserved */
203 | #define __NR_vfork 190
204 | #define __NR_ugetrlimit 191 /* SuS compliant getrlimit */
205 | #define __NR_mmap2 192
206 | #define __NR_truncate64 193
207 | #define __NR_ftruncate64 194
208 | #define __NR_stat64 195
209 | #define __NR_lstat64 196
210 | #define __NR_fstat64 197
211 | #define __NR_lchown32 198
212 | #define __NR_getuid32 199
213 | #define __NR_getgid32 200
214 | #define __NR_geteuid32 201
215 | #define __NR_getegid32 202
216 | #define __NR_setreuid32 203
217 | #define __NR_setregid32 204
218 | #define __NR_getgroups32 205
219 | #define __NR_setgroups32 206
220 | #define __NR_fchown32 207
221 | #define __NR_setresuid32 208
222 | #define __NR_getresuid32 209
223 | #define __NR_setresgid32 210
224 | #define __NR_getresgid32 211
225 | #define __NR_chown32 212
226 | #define __NR_setuid32 213
227 | #define __NR_setgid32 214
228 | #define __NR_setfsuid32 215
229 | #define __NR_setfsgid32 216
230 | #define __NR_getdents64 217
231 | #define __NR_pivot_root 218
232 | #define __NR_mincore 219
233 | #define __NR_madvise 220
234 | #define __NR_fcntl64 221
235 | /* 222 for tux */
236 | /* 223 is unused */
237 | #define __NR_gettid 224
238 | #define __NR_readahead 225
239 | #define __NR_setxattr 226
240 | #define __NR_lsetxattr 227
241 | #define __NR_fsetxattr 228
242 | #define __NR_getxattr 229
243 | #define __NR_lgetxattr 230
244 | #define __NR_fgetxattr 231
245 | #define __NR_listxattr 232
246 | #define __NR_llistxattr 233
247 | #define __NR_flistxattr 234
248 | #define __NR_removexattr 235
249 | #define __NR_lremovexattr 236
250 | #define __NR_fremovexattr 237
251 | #define __NR_tkill 238
252 | #define __NR_sendfile64 239
253 | #define __NR_futex 240
254 | #define __NR_sched_setaffinity 241
255 | #define __NR_sched_getaffinity 242
256 | #define __NR_io_setup 243
257 | #define __NR_io_destroy 244
258 | #define __NR_io_getevents 245
259 | #define __NR_io_submit 246
260 | #define __NR_io_cancel 247
261 | #define __NR_exit_group 248
262 | #define __NR_lookup_dcookie 249
263 | #define __NR_epoll_create 250
264 | #define __NR_epoll_ctl 251
265 | #define __NR_epoll_wait 252
266 | #define __NR_remap_file_pages 253
267 | /* 254 for set_thread_area */
268 | /* 255 for get_thread_area */
269 | #define __NR_set_tid_address 256
270 | #define __NR_timer_create 257
271 | #define __NR_timer_settime 258
272 | #define __NR_timer_gettime 259
273 | #define __NR_timer_getoverrun 260
274 | #define __NR_timer_delete 261
275 | #define __NR_clock_settime 262
276 | #define __NR_clock_gettime 263
277 | #define __NR_clock_getres 264
278 | #define __NR_clock_nanosleep 265
279 | #define __NR_statfs64 266
280 | #define __NR_fstatfs64 267
281 | #define __NR_tgkill 268
282 | #define __NR_utimes 269
283 | #define __NR_arm_fadvise64_64 270
284 | #define __NR_pciconfig_iobase 271
285 | #define __NR_pciconfig_read 272
286 | #define __NR_pciconfig_write 273
287 | #define __NR_mq_open 274
288 | #define __NR_mq_unlink 275
289 | #define __NR_mq_timedsend 276
290 | #define __NR_mq_timedreceive 277
291 | #define __NR_mq_notify 278
292 | #define __NR_mq_getsetattr 279
293 | #define __NR_waitid 280
294 | #define __NR_socket 281
295 | #define __NR_bind 282
296 | #define __NR_connect 283
297 | #define __NR_listen 284
298 | #define __NR_accept 285
299 | #define __NR_getsockname 286
300 | #define __NR_getpeername 287
301 | #define __NR_socketpair 288
302 | #define __NR_send 289
303 | #define __NR_sendto 290
304 | #define __NR_recv 291
305 | #define __NR_recvfrom 292
306 | #define __NR_shutdown 293
307 | #define __NR_setsockopt 294
308 | #define __NR_getsockopt 295
309 | #define __NR_sendmsg 296
310 | #define __NR_recvmsg 297
311 | #define __NR_semop 298
312 | #define __NR_semget 299
313 | #define __NR_semctl 300
314 | #define __NR_msgsnd 301
315 | #define __NR_msgrcv 302
316 | #define __NR_msgget 303
317 | #define __NR_msgctl 304
318 | #define __NR_shmat 305
319 | #define __NR_shmdt 306
320 | #define __NR_shmget 307
321 | #define __NR_shmctl 308
322 | #define __NR_add_key 309
323 | #define __NR_request_key 310
324 | #define __NR_keyctl 311
325 | #define __NR_semtimedop 312
326 | #define __NR_vserver 313
327 | #define __NR_ioprio_set 314
328 | #define __NR_ioprio_get 315
329 | #define __NR_inotify_init 316
330 | #define __NR_inotify_add_watch 317
331 | #define __NR_inotify_rm_watch 318
332 | #define __NR_mbind 319
333 | #define __NR_get_mempolicy 320
334 | #define __NR_set_mempolicy 321
335 | #define __NR_openat 322
336 | #define __NR_mkdirat 323
337 | #define __NR_mknodat 324
338 | #define __NR_fchownat 325
339 | #define __NR_futimesat 326
340 | #define __NR_fstatat64 327
341 | #define __NR_unlinkat 328
342 | #define __NR_renameat 329
343 | #define __NR_linkat 330
344 | #define __NR_symlinkat 331
345 | #define __NR_readlinkat 332
346 | #define __NR_fchmodat 333
347 | #define __NR_faccessat 334
348 | #define __NR_pselect6 335
349 | #define __NR_ppoll 336
350 | #define __NR_unshare 337
351 | #define __NR_set_robust_list 338
352 | #define __NR_get_robust_list 339
353 | #define __NR_splice 340
354 | #define __NR_arm_sync_file_range 341
355 | #define __NR_sync_file_range2 __NR_arm_sync_file_range
356 | #define __NR_tee 342
357 | #define __NR_vmsplice 343
358 | #define __NR_move_pages 344
359 | #define __NR_getcpu 345
360 | #define __NR_epoll_pwait 346
361 | #define __NR_kexec_load 347
362 | #define __NR_utimensat 348
363 | #define __NR_signalfd 349
364 | #define __NR_timerfd_create 350
365 | #define __NR_eventfd 351
366 | #define __NR_fallocate 352
367 | #define __NR_timerfd_settime 353
368 | #define __NR_timerfd_gettime 354
369 | #define __NR_signalfd4 355
370 | #define __NR_eventfd2 356
371 | #define __NR_epoll_create1 357
372 | #define __NR_dup3 358
373 | #define __NR_pipe2 359
374 | #define __NR_inotify_init1 360
375 | #define __NR_preadv 361
376 | #define __NR_pwritev 362
377 | #define __NR_rt_tgsigqueueinfo 363
378 | #define __NR_perf_event_open 364
379 | #define __NR_recvmmsg 365
380 | #define __NR_accept4 366
381 | #define __NR_fanotify_init 367
382 | #define __NR_fanotify_mark 368
383 | #define __NR_prlimit64 369
384 | #define __NR_name_to_handle_at 370
385 | #define __NR_open_by_handle_at 371
386 | #define __NR_clock_adjtime 372
387 | #define __NR_syncfs 373
388 | #define __NR_sendmmsg 374
389 | #define __NR_setns 375
390 | #define __NR_process_vm_readv 376
391 | #define __NR_process_vm_writev 377
392 | /* 378 for kcmp */
393 |
394 | static const char *const syscall_to_str_map[] = {
395 | [__NR_restart_syscall] = "restart_syscall",
396 | [__NR_exit] = "exit",
397 | [__NR_fork] = "fork",
398 | [__NR_read] = "read",
399 | [__NR_write] = "write",
400 | [__NR_open] = "open",
401 | [__NR_close] = "close",
402 | [__NR_creat] = "creat",
403 | [__NR_link] = "link",
404 | [__NR_unlink] = "unlink",
405 | [__NR_execve] = "execve",
406 | [__NR_chdir] = "chdir",
407 | [__NR_mknod] = "mknod",
408 | [__NR_chmod] = "chmod",
409 | [__NR_lchown] = "lchown",
410 | [__NR_lseek] = "lseek",
411 | [__NR_getpid] = "getpid",
412 | [__NR_mount] = "mount",
413 | [__NR_setuid] = "setuid",
414 | [__NR_getuid] = "getuid",
415 | [__NR_ptrace] = "ptrace",
416 | [__NR_pause] = "pause",
417 | [__NR_access] = "access",
418 | [__NR_nice] = "nice",
419 | [__NR_sync] = "sync",
420 | [__NR_kill] = "kill",
421 | [__NR_rename] = "rename",
422 | [__NR_mkdir] = "mkdir",
423 | [__NR_rmdir] = "rmdir",
424 | [__NR_dup] = "dup",
425 | [__NR_pipe] = "pipe",
426 | [__NR_times] = "times",
427 | [__NR_brk] = "brk",
428 | [__NR_setgid] = "setgid",
429 | [__NR_getgid] = "getgid",
430 | [__NR_geteuid] = "geteuid",
431 | [__NR_getegid] = "getegid",
432 | [__NR_acct] = "acct",
433 | [__NR_umount2] = "umount2",
434 | [__NR_ioctl] = "ioctl",
435 | [__NR_fcntl] = "fcntl",
436 | [__NR_setpgid] = "setpgid",
437 | [__NR_umask] = "umask",
438 | [__NR_chroot] = "chroot",
439 | [__NR_ustat] = "ustat",
440 | [__NR_dup2] = "dup2",
441 | [__NR_getppid] = "getppid",
442 | [__NR_getpgrp] = "getpgrp",
443 | [__NR_setsid] = "setsid",
444 | [__NR_sigaction] = "sigaction",
445 | [__NR_setreuid] = "setreuid",
446 | [__NR_setregid] = "setregid",
447 | [__NR_sigsuspend] = "sigsuspend",
448 | [__NR_sigpending] = "sigpending",
449 | [__NR_sethostname] = "sethostname",
450 | [__NR_setrlimit] = "setrlimit",
451 | [__NR_getrusage] = "getrusage",
452 | [__NR_gettimeofday] = "gettimeofday",
453 | [__NR_settimeofday] = "settimeofday",
454 | [__NR_getgroups] = "getgroups",
455 | [__NR_setgroups] = "setgroups",
456 | [__NR_symlink] = "symlink",
457 | [__NR_readlink] = "readlink",
458 | [__NR_uselib] = "uselib",
459 | [__NR_swapon] = "swapon",
460 | [__NR_reboot] = "reboot",
461 | [__NR_munmap] = "munmap",
462 | [__NR_truncate] = "truncate",
463 | [__NR_ftruncate] = "ftruncate",
464 | [__NR_fchmod] = "fchmod",
465 | [__NR_fchown] = "fchown",
466 | [__NR_getpriority] = "getpriority",
467 | [__NR_setpriority] = "setpriority",
468 | [__NR_statfs] = "statfs",
469 | [__NR_fstatfs] = "fstatfs",
470 | [__NR_syslog] = "syslog",
471 | [__NR_setitimer] = "setitimer",
472 | [__NR_getitimer] = "getitimer",
473 | [__NR_stat] = "stat",
474 | [__NR_lstat] = "lstat",
475 | [__NR_fstat] = "fstat",
476 | [__NR_vhangup] = "vhangup",
477 | [__NR_wait4] = "wait4",
478 | [__NR_swapoff] = "swapoff",
479 | [__NR_sysinfo] = "sysinfo",
480 | [__NR_fsync] = "fsync",
481 | [__NR_sigreturn] = "sigreturn",
482 | [__NR_clone] = "clone",
483 | [__NR_setdomainname] = "setdomainname",
484 | [__NR_uname] = "uname",
485 | [__NR_adjtimex] = "adjtimex",
486 | [__NR_mprotect] = "mprotect",
487 | [__NR_sigprocmask] = "sigprocmask",
488 | [__NR_init_module] = "init_module",
489 | [__NR_delete_module] = "delete_module",
490 | [__NR_quotactl] = "quotactl",
491 | [__NR_getpgid] = "getpgid",
492 | [__NR_fchdir] = "fchdir",
493 | [__NR_bdflush] = "bdflush",
494 | [__NR_sysfs] = "sysfs",
495 | [__NR_personality] = "personality",
496 | [__NR_setfsuid] = "setfsuid",
497 | [__NR_setfsgid] = "setfsgid",
498 | [__NR__llseek] = "_llseek",
499 | [__NR_getdents] = "getdents",
500 | [__NR__newselect] = "_newselect",
501 | [__NR_flock] = "flock",
502 | [__NR_msync] = "msync",
503 | [__NR_readv] = "readv",
504 | [__NR_writev] = "writev",
505 | [__NR_getsid] = "getsid",
506 | [__NR_fdatasync] = "fdatasync",
507 | [__NR__sysctl] = "_sysctl",
508 | [__NR_mlock] = "mlock",
509 | [__NR_munlock] = "munlock",
510 | [__NR_mlockall] = "mlockall",
511 | [__NR_munlockall] = "munlockall",
512 | [__NR_sched_setparam] = "sched_setparam",
513 | [__NR_sched_getparam] = "sched_getparam",
514 | [__NR_sched_setscheduler] = "sched_setscheduler",
515 | [__NR_sched_getscheduler] = "sched_getscheduler",
516 | [__NR_sched_yield] = "sched_yield",
517 | [__NR_sched_get_priority_max] = "sched_get_priority_max",
518 | [__NR_sched_get_priority_min] = "sched_get_priority_min",
519 | [__NR_sched_rr_get_interval] = "sched_rr_get_interval",
520 | [__NR_nanosleep] = "nanosleep",
521 | [__NR_mremap] = "mremap",
522 | [__NR_setresuid] = "setresuid",
523 | [__NR_getresuid] = "getresuid",
524 | [__NR_poll] = "poll",
525 | [__NR_nfsservctl] = "nfsservctl",
526 | [__NR_setresgid] = "setresgid",
527 | [__NR_getresgid] = "getresgid",
528 | [__NR_prctl] = "prctl",
529 | [__NR_rt_sigreturn] = "rt_sigreturn",
530 | [__NR_rt_sigaction] = "rt_sigaction",
531 | [__NR_rt_sigprocmask] = "rt_sigprocmask",
532 | [__NR_rt_sigpending] = "rt_sigpending",
533 | [__NR_rt_sigtimedwait] = "rt_sigtimedwait",
534 | [__NR_rt_sigqueueinfo] = "rt_sigqueueinfo",
535 | [__NR_rt_sigsuspend] = "rt_sigsuspend",
536 | [__NR_pread64] = "pread64",
537 | [__NR_pwrite64] = "pwrite64",
538 | [__NR_chown] = "chown",
539 | [__NR_getcwd] = "getcwd",
540 | [__NR_capget] = "capget",
541 | [__NR_capset] = "capset",
542 | [__NR_sigaltstack] = "sigaltstack",
543 | [__NR_sendfile] = "sendfile",
544 | [__NR_vfork] = "vfork",
545 | [__NR_ugetrlimit] = "ugetrlimit",
546 | [__NR_mmap2] = "mmap2",
547 | [__NR_truncate64] = "truncate64",
548 | [__NR_ftruncate64] = "ftruncate64",
549 | [__NR_stat64] = "stat64",
550 | [__NR_lstat64] = "lstat64",
551 | [__NR_fstat64] = "fstat64",
552 | [__NR_lchown32] = "lchown32",
553 | [__NR_getuid32] = "getuid32",
554 | [__NR_getgid32] = "getgid32",
555 | [__NR_geteuid32] = "geteuid32",
556 | [__NR_getegid32] = "getegid32",
557 | [__NR_setreuid32] = "setreuid32",
558 | [__NR_setregid32] = "setregid32",
559 | [__NR_getgroups32] = "getgroups32",
560 | [__NR_setgroups32] = "setgroups32",
561 | [__NR_fchown32] = "fchown32",
562 | [__NR_setresuid32] = "setresuid32",
563 | [__NR_getresuid32] = "getresuid32",
564 | [__NR_setresgid32] = "setresgid32",
565 | [__NR_getresgid32] = "getresgid32",
566 | [__NR_chown32] = "chown32",
567 | [__NR_setuid32] = "setuid32",
568 | [__NR_setgid32] = "setgid32",
569 | [__NR_setfsuid32] = "setfsuid32",
570 | [__NR_setfsgid32] = "setfsgid32",
571 | [__NR_getdents64] = "getdents64",
572 | [__NR_pivot_root] = "pivot_root",
573 | [__NR_mincore] = "mincore",
574 | [__NR_madvise] = "madvise",
575 | [__NR_fcntl64] = "fcntl64",
576 | [__NR_gettid] = "gettid",
577 | [__NR_readahead] = "readahead",
578 | [__NR_setxattr] = "setxattr",
579 | [__NR_lsetxattr] = "lsetxattr",
580 | [__NR_fsetxattr] = "fsetxattr",
581 | [__NR_getxattr] = "getxattr",
582 | [__NR_lgetxattr] = "lgetxattr",
583 | [__NR_fgetxattr] = "fgetxattr",
584 | [__NR_listxattr] = "listxattr",
585 | [__NR_llistxattr] = "llistxattr",
586 | [__NR_flistxattr] = "flistxattr",
587 | [__NR_removexattr] = "removexattr",
588 | [__NR_lremovexattr] = "lremovexattr",
589 | [__NR_fremovexattr] = "fremovexattr",
590 | [__NR_tkill] = "tkill",
591 | [__NR_sendfile64] = "sendfile64",
592 | [__NR_futex] = "futex",
593 | [__NR_sched_setaffinity] = "sched_setaffinity",
594 | [__NR_sched_getaffinity] = "sched_getaffinity",
595 | [__NR_io_setup] = "io_setup",
596 | [__NR_io_destroy] = "io_destroy",
597 | [__NR_io_getevents] = "io_getevents",
598 | [__NR_io_submit] = "io_submit",
599 | [__NR_io_cancel] = "io_cancel",
600 | [__NR_exit_group] = "exit_group",
601 | [__NR_lookup_dcookie] = "lookup_dcookie",
602 | [__NR_epoll_create] = "epoll_create",
603 | [__NR_epoll_ctl] = "epoll_ctl",
604 | [__NR_epoll_wait] = "epoll_wait",
605 | [__NR_remap_file_pages] = "remap_file_pages",
606 | [__NR_set_tid_address] = "set_tid_address",
607 | [__NR_timer_create] = "timer_create",
608 | [__NR_timer_settime] = "timer_settime",
609 | [__NR_timer_gettime] = "timer_gettime",
610 | [__NR_timer_getoverrun] = "timer_getoverrun",
611 | [__NR_timer_delete] = "timer_delete",
612 | [__NR_clock_settime] = "clock_settime",
613 | [__NR_clock_gettime] = "clock_gettime",
614 | [__NR_clock_getres] = "clock_getres",
615 | [__NR_clock_nanosleep] = "clock_nanosleep",
616 | [__NR_statfs64] = "statfs64",
617 | [__NR_fstatfs64] = "fstatfs64",
618 | [__NR_tgkill] = "tgkill",
619 | [__NR_utimes] = "utimes",
620 | [__NR_arm_fadvise64_64] = "arm_fadvise64_64",
621 | [__NR_pciconfig_iobase] = "pciconfig_iobase",
622 | [__NR_pciconfig_read] = "pciconfig_read",
623 | [__NR_pciconfig_write] = "pciconfig_write",
624 | [__NR_mq_open] = "mq_open",
625 | [__NR_mq_unlink] = "mq_unlink",
626 | [__NR_mq_timedsend] = "mq_timedsend",
627 | [__NR_mq_timedreceive] = "mq_timedreceive",
628 | [__NR_mq_notify] = "mq_notify",
629 | [__NR_mq_getsetattr] = "mq_getsetattr",
630 | [__NR_waitid] = "waitid",
631 | [__NR_socket] = "socket",
632 | [__NR_bind] = "bind",
633 | [__NR_connect] = "connect",
634 | [__NR_listen] = "listen",
635 | [__NR_accept] = "accept",
636 | [__NR_getsockname] = "getsockname",
637 | [__NR_getpeername] = "getpeername",
638 | [__NR_socketpair] = "socketpair",
639 | [__NR_send] = "send",
640 | [__NR_sendto] = "sendto",
641 | [__NR_recv] = "recv",
642 | [__NR_recvfrom] = "recvfrom",
643 | [__NR_shutdown] = "shutdown",
644 | [__NR_setsockopt] = "setsockopt",
645 | [__NR_getsockopt] = "getsockopt",
646 | [__NR_sendmsg] = "sendmsg",
647 | [__NR_recvmsg] = "recvmsg",
648 | [__NR_semop] = "semop",
649 | [__NR_semget] = "semget",
650 | [__NR_semctl] = "semctl",
651 | [__NR_msgsnd] = "msgsnd",
652 | [__NR_msgrcv] = "msgrcv",
653 | [__NR_msgget] = "msgget",
654 | [__NR_msgctl] = "msgctl",
655 | [__NR_shmat] = "shmat",
656 | [__NR_shmdt] = "shmdt",
657 | [__NR_shmget] = "shmget",
658 | [__NR_shmctl] = "shmctl",
659 | [__NR_add_key] = "add_key",
660 | [__NR_request_key] = "request_key",
661 | [__NR_keyctl] = "keyctl",
662 | [__NR_semtimedop] = "semtimedop",
663 | [__NR_vserver] = "vserver",
664 | [__NR_ioprio_set] = "ioprio_set",
665 | [__NR_ioprio_get] = "ioprio_get",
666 | [__NR_inotify_init] = "inotify_init",
667 | [__NR_inotify_add_watch] = "inotify_add_watch",
668 | [__NR_inotify_rm_watch] = "inotify_rm_watch",
669 | [__NR_mbind] = "mbind",
670 | [__NR_get_mempolicy] = "get_mempolicy",
671 | [__NR_set_mempolicy] = "set_mempolicy",
672 | [__NR_openat] = "openat",
673 | [__NR_mkdirat] = "mkdirat",
674 | [__NR_mknodat] = "mknodat",
675 | [__NR_fchownat] = "fchownat",
676 | [__NR_futimesat] = "futimesat",
677 | [__NR_fstatat64] = "fstatat64",
678 | [__NR_unlinkat] = "unlinkat",
679 | [__NR_renameat] = "renameat",
680 | [__NR_linkat] = "linkat",
681 | [__NR_symlinkat] = "symlinkat",
682 | [__NR_readlinkat] = "readlinkat",
683 | [__NR_fchmodat] = "fchmodat",
684 | [__NR_faccessat] = "faccessat",
685 | [__NR_pselect6] = "pselect6",
686 | [__NR_ppoll] = "ppoll",
687 | [__NR_unshare] = "unshare",
688 | [__NR_set_robust_list] = "set_robust_list",
689 | [__NR_get_robust_list] = "get_robust_list",
690 | [__NR_splice] = "splice",
691 | [__NR_arm_sync_file_range] = "arm_sync_file_range",
692 | [__NR_tee] = "tee",
693 | [__NR_vmsplice] = "vmsplice",
694 | [__NR_move_pages] = "move_pages",
695 | [__NR_getcpu] = "getcpu",
696 | [__NR_epoll_pwait] = "epoll_pwait",
697 | [__NR_kexec_load] = "kexec_load",
698 | [__NR_utimensat] = "utimensat",
699 | [__NR_signalfd] = "signalfd",
700 | [__NR_timerfd_create] = "timerfd_create",
701 | [__NR_eventfd] = "eventfd",
702 | [__NR_fallocate] = "fallocate",
703 | [__NR_timerfd_settime] = "timerfd_settime",
704 | [__NR_timerfd_gettime] = "timerfd_gettime",
705 | [__NR_signalfd4] = "signalfd4",
706 | [__NR_eventfd2] = "eventfd2",
707 | [__NR_epoll_create1] = "epoll_create1",
708 | [__NR_dup3] = "dup3",
709 | [__NR_pipe2] = "pipe2",
710 | [__NR_inotify_init1] = "inotify_init1",
711 | [__NR_preadv] = "preadv",
712 | [__NR_pwritev] = "pwritev",
713 | [__NR_rt_tgsigqueueinfo] = "rt_tgsigqueueinfo",
714 | [__NR_perf_event_open] = "perf_event_open",
715 | [__NR_recvmmsg] = "recvmmsg",
716 | [__NR_accept4] = "accept4",
717 | [__NR_fanotify_init] = "fanotify_init",
718 | [__NR_fanotify_mark] = "fanotify_mark",
719 | [__NR_prlimit64] = "prlimit64",
720 | [__NR_name_to_handle_at] = "name_to_handle_at",
721 | [__NR_open_by_handle_at] = "open_by_handle_at",
722 | [__NR_clock_adjtime] = "clock_adjtime",
723 | [__NR_syncfs] = "syncfs",
724 | [__NR_sendmmsg] = "sendmmsg",
725 | [__NR_setns] = "setns",
726 | [__NR_process_vm_readv] = "process_vm_readv",
727 | [__NR_process_vm_writev] = "process_vm_writev"
728 | };
729 |
730 | #endif /* _SCNUMS_ARM_H */
731 |
--------------------------------------------------------------------------------
/src/scnums_x86.h:
--------------------------------------------------------------------------------
1 | #ifndef _SCNUMS_X86_H
2 | #define _SCNUMS_X86_H
3 | /*
4 | Derived from kernel syscall_32.tbl
5 |
6 | cat linux/arch/x86/syscalls/syscall_32.tbl| \
7 | egrep -v "^#"| \
8 | sed 's|^\([0-9]\+\)\s\+\w\+\s\+\(\w\+\).*$|#define __NR_\2\t\t\t\1|g' \
9 | > scnums-x86.h
10 |
11 | cat linux/arch/x86/syscalls/syscall_32.tbl| \
12 | egrep -v "^#"| \
13 | sed 's|^\([0-9]\+\)\s\+\w\+\s\+\(\w\+\).*$|\t[__NR_\2] = "\2",|g' \
14 | >> scnums-x86.h
15 | */
16 |
17 | #define __NR_restart_syscall 0
18 | #define __NR_exit 1
19 | #define __NR_fork 2
20 | #define __NR_read 3
21 | #define __NR_write 4
22 | #define __NR_open 5
23 | #define __NR_close 6
24 | #define __NR_waitpid 7
25 | #define __NR_creat 8
26 | #define __NR_link 9
27 | #define __NR_unlink 10
28 | #define __NR_execve 11
29 | #define __NR_chdir 12
30 | #define __NR_time 13
31 | #define __NR_mknod 14
32 | #define __NR_chmod 15
33 | #define __NR_lchown 16
34 | #define __NR_break 17
35 | #define __NR_oldstat 18
36 | #define __NR_lseek 19
37 | #define __NR_getpid 20
38 | #define __NR_mount 21
39 | #define __NR_umount 22
40 | #define __NR_setuid 23
41 | #define __NR_getuid 24
42 | #define __NR_stime 25
43 | #define __NR_ptrace 26
44 | #define __NR_alarm 27
45 | #define __NR_oldfstat 28
46 | #define __NR_pause 29
47 | #define __NR_utime 30
48 | #define __NR_stty 31
49 | #define __NR_gtty 32
50 | #define __NR_access 33
51 | #define __NR_nice 34
52 | #define __NR_ftime 35
53 | #define __NR_sync 36
54 | #define __NR_kill 37
55 | #define __NR_rename 38
56 | #define __NR_mkdir 39
57 | #define __NR_rmdir 40
58 | #define __NR_dup 41
59 | #define __NR_pipe 42
60 | #define __NR_times 43
61 | #define __NR_prof 44
62 | #define __NR_brk 45
63 | #define __NR_setgid 46
64 | #define __NR_getgid 47
65 | #define __NR_signal 48
66 | #define __NR_geteuid 49
67 | #define __NR_getegid 50
68 | #define __NR_acct 51
69 | #define __NR_umount2 52
70 | #define __NR_lock 53
71 | #define __NR_ioctl 54
72 | #define __NR_fcntl 55
73 | #define __NR_mpx 56
74 | #define __NR_setpgid 57
75 | #define __NR_ulimit 58
76 | #define __NR_oldolduname 59
77 | #define __NR_umask 60
78 | #define __NR_chroot 61
79 | #define __NR_ustat 62
80 | #define __NR_dup2 63
81 | #define __NR_getppid 64
82 | #define __NR_getpgrp 65
83 | #define __NR_setsid 66
84 | #define __NR_sigaction 67
85 | #define __NR_sgetmask 68
86 | #define __NR_ssetmask 69
87 | #define __NR_setreuid 70
88 | #define __NR_setregid 71
89 | #define __NR_sigsuspend 72
90 | #define __NR_sigpending 73
91 | #define __NR_sethostname 74
92 | #define __NR_setrlimit 75
93 | #define __NR_getrlimit 76
94 | #define __NR_getrusage 77
95 | #define __NR_gettimeofday 78
96 | #define __NR_settimeofday 79
97 | #define __NR_getgroups 80
98 | #define __NR_setgroups 81
99 | #define __NR_select 82
100 | #define __NR_symlink 83
101 | #define __NR_oldlstat 84
102 | #define __NR_readlink 85
103 | #define __NR_uselib 86
104 | #define __NR_swapon 87
105 | #define __NR_reboot 88
106 | #define __NR_readdir 89
107 | #define __NR_mmap 90
108 | #define __NR_munmap 91
109 | #define __NR_truncate 92
110 | #define __NR_ftruncate 93
111 | #define __NR_fchmod 94
112 | #define __NR_fchown 95
113 | #define __NR_getpriority 96
114 | #define __NR_setpriority 97
115 | #define __NR_profil 98
116 | #define __NR_statfs 99
117 | #define __NR_fstatfs 100
118 | #define __NR_ioperm 101
119 | #define __NR_socketcall 102
120 | #define __NR_syslog 103
121 | #define __NR_setitimer 104
122 | #define __NR_getitimer 105
123 | #define __NR_stat 106
124 | #define __NR_lstat 107
125 | #define __NR_fstat 108
126 | #define __NR_olduname 109
127 | #define __NR_iopl 110
128 | #define __NR_vhangup 111
129 | #define __NR_idle 112
130 | #define __NR_vm86old 113
131 | #define __NR_wait4 114
132 | #define __NR_swapoff 115
133 | #define __NR_sysinfo 116
134 | #define __NR_ipc 117
135 | #define __NR_fsync 118
136 | #define __NR_sigreturn 119
137 | #define __NR_clone 120
138 | #define __NR_setdomainname 121
139 | #define __NR_uname 122
140 | #define __NR_modify_ldt 123
141 | #define __NR_adjtimex 124
142 | #define __NR_mprotect 125
143 | #define __NR_sigprocmask 126
144 | #define __NR_create_module 127
145 | #define __NR_init_module 128
146 | #define __NR_delete_module 129
147 | #define __NR_get_kernel_syms 130
148 | #define __NR_quotactl 131
149 | #define __NR_getpgid 132
150 | #define __NR_fchdir 133
151 | #define __NR_bdflush 134
152 | #define __NR_sysfs 135
153 | #define __NR_personality 136
154 | #define __NR_afs_syscall 137
155 | #define __NR_setfsuid 138
156 | #define __NR_setfsgid 139
157 | #define __NR__llseek 140
158 | #define __NR_getdents 141
159 | #define __NR__newselect 142
160 | #define __NR_flock 143
161 | #define __NR_msync 144
162 | #define __NR_readv 145
163 | #define __NR_writev 146
164 | #define __NR_getsid 147
165 | #define __NR_fdatasync 148
166 | #define __NR__sysctl 149
167 | #define __NR_mlock 150
168 | #define __NR_munlock 151
169 | #define __NR_mlockall 152
170 | #define __NR_munlockall 153
171 | #define __NR_sched_setparam 154
172 | #define __NR_sched_getparam 155
173 | #define __NR_sched_setscheduler 156
174 | #define __NR_sched_getscheduler 157
175 | #define __NR_sched_yield 158
176 | #define __NR_sched_get_priority_max 159
177 | #define __NR_sched_get_priority_min 160
178 | #define __NR_sched_rr_get_interval 161
179 | #define __NR_nanosleep 162
180 | #define __NR_mremap 163
181 | #define __NR_setresuid 164
182 | #define __NR_getresuid 165
183 | #define __NR_vm86 166
184 | #define __NR_query_module 167
185 | #define __NR_poll 168
186 | #define __NR_nfsservctl 169
187 | #define __NR_setresgid 170
188 | #define __NR_getresgid 171
189 | #define __NR_prctl 172
190 | #define __NR_rt_sigreturn 173
191 | #define __NR_rt_sigaction 174
192 | #define __NR_rt_sigprocmask 175
193 | #define __NR_rt_sigpending 176
194 | #define __NR_rt_sigtimedwait 177
195 | #define __NR_rt_sigqueueinfo 178
196 | #define __NR_rt_sigsuspend 179
197 | #define __NR_pread64 180
198 | #define __NR_pwrite64 181
199 | #define __NR_chown 182
200 | #define __NR_getcwd 183
201 | #define __NR_capget 184
202 | #define __NR_capset 185
203 | #define __NR_sigaltstack 186
204 | #define __NR_sendfile 187
205 | #define __NR_getpmsg 188
206 | #define __NR_putpmsg 189
207 | #define __NR_vfork 190
208 | #define __NR_ugetrlimit 191
209 | #define __NR_mmap2 192
210 | #define __NR_truncate64 193
211 | #define __NR_ftruncate64 194
212 | #define __NR_stat64 195
213 | #define __NR_lstat64 196
214 | #define __NR_fstat64 197
215 | #define __NR_lchown32 198
216 | #define __NR_getuid32 199
217 | #define __NR_getgid32 200
218 | #define __NR_geteuid32 201
219 | #define __NR_getegid32 202
220 | #define __NR_setreuid32 203
221 | #define __NR_setregid32 204
222 | #define __NR_getgroups32 205
223 | #define __NR_setgroups32 206
224 | #define __NR_fchown32 207
225 | #define __NR_setresuid32 208
226 | #define __NR_getresuid32 209
227 | #define __NR_setresgid32 210
228 | #define __NR_getresgid32 211
229 | #define __NR_chown32 212
230 | #define __NR_setuid32 213
231 | #define __NR_setgid32 214
232 | #define __NR_setfsuid32 215
233 | #define __NR_setfsgid32 216
234 | #define __NR_pivot_root 217
235 | #define __NR_mincore 218
236 | #define __NR_madvise 219
237 | #define __NR_getdents64 220
238 | #define __NR_fcntl64 221
239 | #define __NR_gettid 224
240 | #define __NR_readahead 225
241 | #define __NR_setxattr 226
242 | #define __NR_lsetxattr 227
243 | #define __NR_fsetxattr 228
244 | #define __NR_getxattr 229
245 | #define __NR_lgetxattr 230
246 | #define __NR_fgetxattr 231
247 | #define __NR_listxattr 232
248 | #define __NR_llistxattr 233
249 | #define __NR_flistxattr 234
250 | #define __NR_removexattr 235
251 | #define __NR_lremovexattr 236
252 | #define __NR_fremovexattr 237
253 | #define __NR_tkill 238
254 | #define __NR_sendfile64 239
255 | #define __NR_futex 240
256 | #define __NR_sched_setaffinity 241
257 | #define __NR_sched_getaffinity 242
258 | #define __NR_set_thread_area 243
259 | #define __NR_get_thread_area 244
260 | #define __NR_io_setup 245
261 | #define __NR_io_destroy 246
262 | #define __NR_io_getevents 247
263 | #define __NR_io_submit 248
264 | #define __NR_io_cancel 249
265 | #define __NR_fadvise64 250
266 | #define __NR_exit_group 252
267 | #define __NR_lookup_dcookie 253
268 | #define __NR_epoll_create 254
269 | #define __NR_epoll_ctl 255
270 | #define __NR_epoll_wait 256
271 | #define __NR_remap_file_pages 257
272 | #define __NR_set_tid_address 258
273 | #define __NR_timer_create 259
274 | #define __NR_timer_settime 260
275 | #define __NR_timer_gettime 261
276 | #define __NR_timer_getoverrun 262
277 | #define __NR_timer_delete 263
278 | #define __NR_clock_settime 264
279 | #define __NR_clock_gettime 265
280 | #define __NR_clock_getres 266
281 | #define __NR_clock_nanosleep 267
282 | #define __NR_statfs64 268
283 | #define __NR_fstatfs64 269
284 | #define __NR_tgkill 270
285 | #define __NR_utimes 271
286 | #define __NR_fadvise64_64 272
287 | #define __NR_vserver 273
288 | #define __NR_mbind 274
289 | #define __NR_get_mempolicy 275
290 | #define __NR_set_mempolicy 276
291 | #define __NR_mq_open 277
292 | #define __NR_mq_unlink 278
293 | #define __NR_mq_timedsend 279
294 | #define __NR_mq_timedreceive 280
295 | #define __NR_mq_notify 281
296 | #define __NR_mq_getsetattr 282
297 | #define __NR_kexec_load 283
298 | #define __NR_waitid 284
299 | #define __NR_add_key 286
300 | #define __NR_request_key 287
301 | #define __NR_keyctl 288
302 | #define __NR_ioprio_set 289
303 | #define __NR_ioprio_get 290
304 | #define __NR_inotify_init 291
305 | #define __NR_inotify_add_watch 292
306 | #define __NR_inotify_rm_watch 293
307 | #define __NR_migrate_pages 294
308 | #define __NR_openat 295
309 | #define __NR_mkdirat 296
310 | #define __NR_mknodat 297
311 | #define __NR_fchownat 298
312 | #define __NR_futimesat 299
313 | #define __NR_fstatat64 300
314 | #define __NR_unlinkat 301
315 | #define __NR_renameat 302
316 | #define __NR_linkat 303
317 | #define __NR_symlinkat 304
318 | #define __NR_readlinkat 305
319 | #define __NR_fchmodat 306
320 | #define __NR_faccessat 307
321 | #define __NR_pselect6 308
322 | #define __NR_ppoll 309
323 | #define __NR_unshare 310
324 | #define __NR_set_robust_list 311
325 | #define __NR_get_robust_list 312
326 | #define __NR_splice 313
327 | #define __NR_sync_file_range 314
328 | #define __NR_tee 315
329 | #define __NR_vmsplice 316
330 | #define __NR_move_pages 317
331 | #define __NR_getcpu 318
332 | #define __NR_epoll_pwait 319
333 | #define __NR_utimensat 320
334 | #define __NR_signalfd 321
335 | #define __NR_timerfd_create 322
336 | #define __NR_eventfd 323
337 | #define __NR_fallocate 324
338 | #define __NR_timerfd_settime 325
339 | #define __NR_timerfd_gettime 326
340 | #define __NR_signalfd4 327
341 | #define __NR_eventfd2 328
342 | #define __NR_epoll_create1 329
343 | #define __NR_dup3 330
344 | #define __NR_pipe2 331
345 | #define __NR_inotify_init1 332
346 | #define __NR_preadv 333
347 | #define __NR_pwritev 334
348 | #define __NR_rt_tgsigqueueinfo 335
349 | #define __NR_perf_event_open 336
350 | #define __NR_recvmmsg 337
351 | #define __NR_fanotify_init 338
352 | #define __NR_fanotify_mark 339
353 | #define __NR_prlimit64 340
354 | #define __NR_name_to_handle_at 341
355 | #define __NR_open_by_handle_at 342
356 | #define __NR_clock_adjtime 343
357 | #define __NR_syncfs 344
358 | #define __NR_sendmmsg 345
359 | #define __NR_setns 346
360 | #define __NR_process_vm_readv 347
361 | #define __NR_process_vm_writev 348
362 | #define __NR_kcmp 349
363 |
364 | static const char *const syscall_to_str_map[] = {
365 | [__NR_restart_syscall] = "restart_syscall",
366 | [__NR_exit] = "exit",
367 | [__NR_fork] = "fork",
368 | [__NR_read] = "read",
369 | [__NR_write] = "write",
370 | [__NR_open] = "open",
371 | [__NR_close] = "close",
372 | [__NR_waitpid] = "waitpid",
373 | [__NR_creat] = "creat",
374 | [__NR_link] = "link",
375 | [__NR_unlink] = "unlink",
376 | [__NR_execve] = "execve",
377 | [__NR_chdir] = "chdir",
378 | [__NR_time] = "time",
379 | [__NR_mknod] = "mknod",
380 | [__NR_chmod] = "chmod",
381 | [__NR_lchown] = "lchown",
382 | [__NR_break] = "break",
383 | [__NR_oldstat] = "oldstat",
384 | [__NR_lseek] = "lseek",
385 | [__NR_getpid] = "getpid",
386 | [__NR_mount] = "mount",
387 | [__NR_umount] = "umount",
388 | [__NR_setuid] = "setuid",
389 | [__NR_getuid] = "getuid",
390 | [__NR_stime] = "stime",
391 | [__NR_ptrace] = "ptrace",
392 | [__NR_alarm] = "alarm",
393 | [__NR_oldfstat] = "oldfstat",
394 | [__NR_pause] = "pause",
395 | [__NR_utime] = "utime",
396 | [__NR_stty] = "stty",
397 | [__NR_gtty] = "gtty",
398 | [__NR_access] = "access",
399 | [__NR_nice] = "nice",
400 | [__NR_ftime] = "ftime",
401 | [__NR_sync] = "sync",
402 | [__NR_kill] = "kill",
403 | [__NR_rename] = "rename",
404 | [__NR_mkdir] = "mkdir",
405 | [__NR_rmdir] = "rmdir",
406 | [__NR_dup] = "dup",
407 | [__NR_pipe] = "pipe",
408 | [__NR_times] = "times",
409 | [__NR_prof] = "prof",
410 | [__NR_brk] = "brk",
411 | [__NR_setgid] = "setgid",
412 | [__NR_getgid] = "getgid",
413 | [__NR_signal] = "signal",
414 | [__NR_geteuid] = "geteuid",
415 | [__NR_getegid] = "getegid",
416 | [__NR_acct] = "acct",
417 | [__NR_umount2] = "umount2",
418 | [__NR_lock] = "lock",
419 | [__NR_ioctl] = "ioctl",
420 | [__NR_fcntl] = "fcntl",
421 | [__NR_mpx] = "mpx",
422 | [__NR_setpgid] = "setpgid",
423 | [__NR_ulimit] = "ulimit",
424 | [__NR_oldolduname] = "oldolduname",
425 | [__NR_umask] = "umask",
426 | [__NR_chroot] = "chroot",
427 | [__NR_ustat] = "ustat",
428 | [__NR_dup2] = "dup2",
429 | [__NR_getppid] = "getppid",
430 | [__NR_getpgrp] = "getpgrp",
431 | [__NR_setsid] = "setsid",
432 | [__NR_sigaction] = "sigaction",
433 | [__NR_sgetmask] = "sgetmask",
434 | [__NR_ssetmask] = "ssetmask",
435 | [__NR_setreuid] = "setreuid",
436 | [__NR_setregid] = "setregid",
437 | [__NR_sigsuspend] = "sigsuspend",
438 | [__NR_sigpending] = "sigpending",
439 | [__NR_sethostname] = "sethostname",
440 | [__NR_setrlimit] = "setrlimit",
441 | [__NR_getrlimit] = "getrlimit",
442 | [__NR_getrusage] = "getrusage",
443 | [__NR_gettimeofday] = "gettimeofday",
444 | [__NR_settimeofday] = "settimeofday",
445 | [__NR_getgroups] = "getgroups",
446 | [__NR_setgroups] = "setgroups",
447 | [__NR_select] = "select",
448 | [__NR_symlink] = "symlink",
449 | [__NR_oldlstat] = "oldlstat",
450 | [__NR_readlink] = "readlink",
451 | [__NR_uselib] = "uselib",
452 | [__NR_swapon] = "swapon",
453 | [__NR_reboot] = "reboot",
454 | [__NR_readdir] = "readdir",
455 | [__NR_mmap] = "mmap",
456 | [__NR_munmap] = "munmap",
457 | [__NR_truncate] = "truncate",
458 | [__NR_ftruncate] = "ftruncate",
459 | [__NR_fchmod] = "fchmod",
460 | [__NR_fchown] = "fchown",
461 | [__NR_getpriority] = "getpriority",
462 | [__NR_setpriority] = "setpriority",
463 | [__NR_profil] = "profil",
464 | [__NR_statfs] = "statfs",
465 | [__NR_fstatfs] = "fstatfs",
466 | [__NR_ioperm] = "ioperm",
467 | [__NR_socketcall] = "socketcall",
468 | [__NR_syslog] = "syslog",
469 | [__NR_setitimer] = "setitimer",
470 | [__NR_getitimer] = "getitimer",
471 | [__NR_stat] = "stat",
472 | [__NR_lstat] = "lstat",
473 | [__NR_fstat] = "fstat",
474 | [__NR_olduname] = "olduname",
475 | [__NR_iopl] = "iopl",
476 | [__NR_vhangup] = "vhangup",
477 | [__NR_idle] = "idle",
478 | [__NR_vm86old] = "vm86old",
479 | [__NR_wait4] = "wait4",
480 | [__NR_swapoff] = "swapoff",
481 | [__NR_sysinfo] = "sysinfo",
482 | [__NR_ipc] = "ipc",
483 | [__NR_fsync] = "fsync",
484 | [__NR_sigreturn] = "sigreturn",
485 | [__NR_clone] = "clone",
486 | [__NR_setdomainname] = "setdomainname",
487 | [__NR_uname] = "uname",
488 | [__NR_modify_ldt] = "modify_ldt",
489 | [__NR_adjtimex] = "adjtimex",
490 | [__NR_mprotect] = "mprotect",
491 | [__NR_sigprocmask] = "sigprocmask",
492 | [__NR_create_module] = "create_module",
493 | [__NR_init_module] = "init_module",
494 | [__NR_delete_module] = "delete_module",
495 | [__NR_get_kernel_syms] = "get_kernel_syms",
496 | [__NR_quotactl] = "quotactl",
497 | [__NR_getpgid] = "getpgid",
498 | [__NR_fchdir] = "fchdir",
499 | [__NR_bdflush] = "bdflush",
500 | [__NR_sysfs] = "sysfs",
501 | [__NR_personality] = "personality",
502 | [__NR_afs_syscall] = "afs_syscall",
503 | [__NR_setfsuid] = "setfsuid",
504 | [__NR_setfsgid] = "setfsgid",
505 | [__NR__llseek] = "_llseek",
506 | [__NR_getdents] = "getdents",
507 | [__NR__newselect] = "_newselect",
508 | [__NR_flock] = "flock",
509 | [__NR_msync] = "msync",
510 | [__NR_readv] = "readv",
511 | [__NR_writev] = "writev",
512 | [__NR_getsid] = "getsid",
513 | [__NR_fdatasync] = "fdatasync",
514 | [__NR__sysctl] = "_sysctl",
515 | [__NR_mlock] = "mlock",
516 | [__NR_munlock] = "munlock",
517 | [__NR_mlockall] = "mlockall",
518 | [__NR_munlockall] = "munlockall",
519 | [__NR_sched_setparam] = "sched_setparam",
520 | [__NR_sched_getparam] = "sched_getparam",
521 | [__NR_sched_setscheduler] = "sched_setscheduler",
522 | [__NR_sched_getscheduler] = "sched_getscheduler",
523 | [__NR_sched_yield] = "sched_yield",
524 | [__NR_sched_get_priority_max] = "sched_get_priority_max",
525 | [__NR_sched_get_priority_min] = "sched_get_priority_min",
526 | [__NR_sched_rr_get_interval] = "sched_rr_get_interval",
527 | [__NR_nanosleep] = "nanosleep",
528 | [__NR_mremap] = "mremap",
529 | [__NR_setresuid] = "setresuid",
530 | [__NR_getresuid] = "getresuid",
531 | [__NR_vm86] = "vm86",
532 | [__NR_query_module] = "query_module",
533 | [__NR_poll] = "poll",
534 | [__NR_nfsservctl] = "nfsservctl",
535 | [__NR_setresgid] = "setresgid",
536 | [__NR_getresgid] = "getresgid",
537 | [__NR_prctl] = "prctl",
538 | [__NR_rt_sigreturn] = "rt_sigreturn",
539 | [__NR_rt_sigaction] = "rt_sigaction",
540 | [__NR_rt_sigprocmask] = "rt_sigprocmask",
541 | [__NR_rt_sigpending] = "rt_sigpending",
542 | [__NR_rt_sigtimedwait] = "rt_sigtimedwait",
543 | [__NR_rt_sigqueueinfo] = "rt_sigqueueinfo",
544 | [__NR_rt_sigsuspend] = "rt_sigsuspend",
545 | [__NR_pread64] = "pread64",
546 | [__NR_pwrite64] = "pwrite64",
547 | [__NR_chown] = "chown",
548 | [__NR_getcwd] = "getcwd",
549 | [__NR_capget] = "capget",
550 | [__NR_capset] = "capset",
551 | [__NR_sigaltstack] = "sigaltstack",
552 | [__NR_sendfile] = "sendfile",
553 | [__NR_getpmsg] = "getpmsg",
554 | [__NR_putpmsg] = "putpmsg",
555 | [__NR_vfork] = "vfork",
556 | [__NR_ugetrlimit] = "ugetrlimit",
557 | [__NR_mmap2] = "mmap2",
558 | [__NR_truncate64] = "truncate64",
559 | [__NR_ftruncate64] = "ftruncate64",
560 | [__NR_stat64] = "stat64",
561 | [__NR_lstat64] = "lstat64",
562 | [__NR_fstat64] = "fstat64",
563 | [__NR_lchown32] = "lchown32",
564 | [__NR_getuid32] = "getuid32",
565 | [__NR_getgid32] = "getgid32",
566 | [__NR_geteuid32] = "geteuid32",
567 | [__NR_getegid32] = "getegid32",
568 | [__NR_setreuid32] = "setreuid32",
569 | [__NR_setregid32] = "setregid32",
570 | [__NR_getgroups32] = "getgroups32",
571 | [__NR_setgroups32] = "setgroups32",
572 | [__NR_fchown32] = "fchown32",
573 | [__NR_setresuid32] = "setresuid32",
574 | [__NR_getresuid32] = "getresuid32",
575 | [__NR_setresgid32] = "setresgid32",
576 | [__NR_getresgid32] = "getresgid32",
577 | [__NR_chown32] = "chown32",
578 | [__NR_setuid32] = "setuid32",
579 | [__NR_setgid32] = "setgid32",
580 | [__NR_setfsuid32] = "setfsuid32",
581 | [__NR_setfsgid32] = "setfsgid32",
582 | [__NR_pivot_root] = "pivot_root",
583 | [__NR_mincore] = "mincore",
584 | [__NR_madvise] = "madvise",
585 | [__NR_getdents64] = "getdents64",
586 | [__NR_fcntl64] = "fcntl64",
587 | [__NR_gettid] = "gettid",
588 | [__NR_readahead] = "readahead",
589 | [__NR_setxattr] = "setxattr",
590 | [__NR_lsetxattr] = "lsetxattr",
591 | [__NR_fsetxattr] = "fsetxattr",
592 | [__NR_getxattr] = "getxattr",
593 | [__NR_lgetxattr] = "lgetxattr",
594 | [__NR_fgetxattr] = "fgetxattr",
595 | [__NR_listxattr] = "listxattr",
596 | [__NR_llistxattr] = "llistxattr",
597 | [__NR_flistxattr] = "flistxattr",
598 | [__NR_removexattr] = "removexattr",
599 | [__NR_lremovexattr] = "lremovexattr",
600 | [__NR_fremovexattr] = "fremovexattr",
601 | [__NR_tkill] = "tkill",
602 | [__NR_sendfile64] = "sendfile64",
603 | [__NR_futex] = "futex",
604 | [__NR_sched_setaffinity] = "sched_setaffinity",
605 | [__NR_sched_getaffinity] = "sched_getaffinity",
606 | [__NR_set_thread_area] = "set_thread_area",
607 | [__NR_get_thread_area] = "get_thread_area",
608 | [__NR_io_setup] = "io_setup",
609 | [__NR_io_destroy] = "io_destroy",
610 | [__NR_io_getevents] = "io_getevents",
611 | [__NR_io_submit] = "io_submit",
612 | [__NR_io_cancel] = "io_cancel",
613 | [__NR_fadvise64] = "fadvise64",
614 | [__NR_exit_group] = "exit_group",
615 | [__NR_lookup_dcookie] = "lookup_dcookie",
616 | [__NR_epoll_create] = "epoll_create",
617 | [__NR_epoll_ctl] = "epoll_ctl",
618 | [__NR_epoll_wait] = "epoll_wait",
619 | [__NR_remap_file_pages] = "remap_file_pages",
620 | [__NR_set_tid_address] = "set_tid_address",
621 | [__NR_timer_create] = "timer_create",
622 | [__NR_timer_settime] = "timer_settime",
623 | [__NR_timer_gettime] = "timer_gettime",
624 | [__NR_timer_getoverrun] = "timer_getoverrun",
625 | [__NR_timer_delete] = "timer_delete",
626 | [__NR_clock_settime] = "clock_settime",
627 | [__NR_clock_gettime] = "clock_gettime",
628 | [__NR_clock_getres] = "clock_getres",
629 | [__NR_clock_nanosleep] = "clock_nanosleep",
630 | [__NR_statfs64] = "statfs64",
631 | [__NR_fstatfs64] = "fstatfs64",
632 | [__NR_tgkill] = "tgkill",
633 | [__NR_utimes] = "utimes",
634 | [__NR_fadvise64_64] = "fadvise64_64",
635 | [__NR_vserver] = "vserver",
636 | [__NR_mbind] = "mbind",
637 | [__NR_get_mempolicy] = "get_mempolicy",
638 | [__NR_set_mempolicy] = "set_mempolicy",
639 | [__NR_mq_open] = "mq_open",
640 | [__NR_mq_unlink] = "mq_unlink",
641 | [__NR_mq_timedsend] = "mq_timedsend",
642 | [__NR_mq_timedreceive] = "mq_timedreceive",
643 | [__NR_mq_notify] = "mq_notify",
644 | [__NR_mq_getsetattr] = "mq_getsetattr",
645 | [__NR_kexec_load] = "kexec_load",
646 | [__NR_waitid] = "waitid",
647 | [__NR_add_key] = "add_key",
648 | [__NR_request_key] = "request_key",
649 | [__NR_keyctl] = "keyctl",
650 | [__NR_ioprio_set] = "ioprio_set",
651 | [__NR_ioprio_get] = "ioprio_get",
652 | [__NR_inotify_init] = "inotify_init",
653 | [__NR_inotify_add_watch] = "inotify_add_watch",
654 | [__NR_inotify_rm_watch] = "inotify_rm_watch",
655 | [__NR_migrate_pages] = "migrate_pages",
656 | [__NR_openat] = "openat",
657 | [__NR_mkdirat] = "mkdirat",
658 | [__NR_mknodat] = "mknodat",
659 | [__NR_fchownat] = "fchownat",
660 | [__NR_futimesat] = "futimesat",
661 | [__NR_fstatat64] = "fstatat64",
662 | [__NR_unlinkat] = "unlinkat",
663 | [__NR_renameat] = "renameat",
664 | [__NR_linkat] = "linkat",
665 | [__NR_symlinkat] = "symlinkat",
666 | [__NR_readlinkat] = "readlinkat",
667 | [__NR_fchmodat] = "fchmodat",
668 | [__NR_faccessat] = "faccessat",
669 | [__NR_pselect6] = "pselect6",
670 | [__NR_ppoll] = "ppoll",
671 | [__NR_unshare] = "unshare",
672 | [__NR_set_robust_list] = "set_robust_list",
673 | [__NR_get_robust_list] = "get_robust_list",
674 | [__NR_splice] = "splice",
675 | [__NR_sync_file_range] = "sync_file_range",
676 | [__NR_tee] = "tee",
677 | [__NR_vmsplice] = "vmsplice",
678 | [__NR_move_pages] = "move_pages",
679 | [__NR_getcpu] = "getcpu",
680 | [__NR_epoll_pwait] = "epoll_pwait",
681 | [__NR_utimensat] = "utimensat",
682 | [__NR_signalfd] = "signalfd",
683 | [__NR_timerfd_create] = "timerfd_create",
684 | [__NR_eventfd] = "eventfd",
685 | [__NR_fallocate] = "fallocate",
686 | [__NR_timerfd_settime] = "timerfd_settime",
687 | [__NR_timerfd_gettime] = "timerfd_gettime",
688 | [__NR_signalfd4] = "signalfd4",
689 | [__NR_eventfd2] = "eventfd2",
690 | [__NR_epoll_create1] = "epoll_create1",
691 | [__NR_dup3] = "dup3",
692 | [__NR_pipe2] = "pipe2",
693 | [__NR_inotify_init1] = "inotify_init1",
694 | [__NR_preadv] = "preadv",
695 | [__NR_pwritev] = "pwritev",
696 | [__NR_rt_tgsigqueueinfo] = "rt_tgsigqueueinfo",
697 | [__NR_perf_event_open] = "perf_event_open",
698 | [__NR_recvmmsg] = "recvmmsg",
699 | [__NR_fanotify_init] = "fanotify_init",
700 | [__NR_fanotify_mark] = "fanotify_mark",
701 | [__NR_prlimit64] = "prlimit64",
702 | [__NR_name_to_handle_at] = "name_to_handle_at",
703 | [__NR_open_by_handle_at] = "open_by_handle_at",
704 | [__NR_clock_adjtime] = "clock_adjtime",
705 | [__NR_syncfs] = "syncfs",
706 | [__NR_sendmmsg] = "sendmmsg",
707 | [__NR_setns] = "setns",
708 | [__NR_process_vm_readv] = "process_vm_readv",
709 | [__NR_process_vm_writev] = "process_vm_writev",
710 | [__NR_kcmp] = "kcmp"
711 | };
712 |
713 | #endif /* _SCNUMS_X86_H */
714 |
--------------------------------------------------------------------------------
/src/testlib.c:
--------------------------------------------------------------------------------
1 | /* No need to export any objects. This lib will only be used to check
2 | if dlopen() works. */
3 |
4 | static void __attribute__ ((constructor)) my_init(void) {
5 | }
6 |
--------------------------------------------------------------------------------
/src/trace.c:
--------------------------------------------------------------------------------
1 | /*
2 | References:
3 |
4 | https://idea.popcount.org/2012-12-11-linux-process-states/
5 | http://strace.git.sourceforge.net/git/gitweb.cgi?p=strace/strace;a=blob;f=README-linux-ptrace;hb=HEAD
6 | http://hssl.cs.jhu.edu/~neal/woodchuck/src/commits/c8a6c6c6d28c87e2ef99e21cf76c4ea90a7e11ad/src/process-monitor-ptrace.c.raw.html
7 | http://www.linuxjournal.com/article/6210?page=0,1
8 | */
9 |
10 | /* required for pread() */
11 | #define _XOPEN_SOURCE 500
12 | /* required for long offsets for pread */
13 | #define _FILE_OFFSET_BITS 64
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 |
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | #include "list.h"
31 | #include "trace.h"
32 | #include "types.h"
33 | #include "fluxcapacitor.h"
34 |
35 |
36 | extern struct options options;
37 |
38 |
39 | #define HPIDS_SIZE 51
40 |
41 |
42 | #if defined(__x86_64__)
43 |
44 | /* On x86-64, RAX is set to -ENOSYS on system call entry. How
45 | do we distinguish this from a system call that returns
46 | ENOSYS? (marek: we don't) */
47 | # define SYSCALL_ENTRY ((long)RET == -ENOSYS)
48 | # define REGS_STRUCT struct user_regs_struct
49 |
50 | # define SYSCALL (regs.orig_rax)
51 | # define ARG1 (regs.rdi)
52 | # define ARG2 (regs.rsi)
53 | # define ARG3 (regs.rdx)
54 | # define ARG4 (regs.r10)
55 | # define ARG5 (regs.r8)
56 | # define ARG6 (regs.r9)
57 | # define RET (regs.rax)
58 |
59 | #elif defined(__i386__)
60 |
61 | # define SYSCALL_ENTRY (RET == -ENOSYS)
62 | # define REGS_STRUCT struct user_regs_struct
63 | # define SYSCALL (regs.orig_eax)
64 | # define ARG1 (regs.ebx)
65 | # define ARG2 (regs.ecx)
66 | # define ARG3 (regs.edx)
67 | # define ARG4 (regs.esi)
68 | # define ARG5 (regs.edi)
69 | # define ARG6 (regs.ebp)
70 | # define RET (regs.eax)
71 |
72 | #elif defined(__arm__)
73 |
74 | /*
75 | * This struct defines the way the registers are stored on the
76 | * stack during a system call. Note that sizeof(struct pt_regs)
77 | * has to be a multiple of 8.
78 | */
79 |
80 | # define REGS_STRUCT struct pt_regs
81 | /* ip is set to 0 on system call entry, 1 on exit. */
82 | # define SYSCALL_ENTRY (regs.ARM_ip == 0)
83 |
84 | /* This layout assumes that there are no 64-bit parameters. See
85 | http://lkml.org/lkml/2006/1/12/175 for the complications. */
86 | # define SYSCALL (regs.ARM_r7)
87 | # define ARG1 (regs.ARM_ORIG_r0)
88 | # define ARG2 (regs.ARM_r1)
89 | # define ARG3 (regs.ARM_r2)
90 | # define ARG4 (regs.ARM_r3)
91 | # define ARG5 (regs.ARM_r4)
92 | # define ARG6 (regs.ARM_r5)
93 | # define RET (regs.ARM_r0)
94 |
95 | #else
96 |
97 | # error Not ported to your architecture.
98 |
99 | #endif
100 |
101 |
102 | struct trace {
103 | int sfd;
104 | int process_count;
105 | struct hlist_head hpids[HPIDS_SIZE];
106 |
107 | trace_callback callback;
108 | void *userdata;
109 |
110 | struct list_head list_of_waitpid_reports;
111 | };
112 |
113 | struct trace_process {
114 | struct trace *trace;
115 | struct hlist_node node;
116 |
117 | pid_t pid;
118 | int initialized;
119 | int within_syscall;
120 | int mem_fd;
121 | REGS_STRUCT regs;
122 |
123 | trace_callback callback;
124 | void *userdata;
125 | };
126 |
127 | struct waitpid_report {
128 | struct list_head in_list;
129 |
130 | int pid;
131 | int status;
132 | };
133 |
134 | static void trace_process_del(struct trace *trace, struct trace_process *process);
135 |
136 | struct trace *trace_new(trace_callback callback, void *userdata) {
137 | struct trace *trace = calloc(1, sizeof(struct trace));
138 |
139 | sigset_t mask;
140 | sigemptyset(&mask);
141 | sigaddset(&mask, SIGCHLD);
142 |
143 | if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
144 | PFATAL("sigprocmask(SIG_BLOCK, [SIGCHLD])");
145 |
146 | trace->sfd = signalfd(-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK);
147 | if (trace->sfd == -1)
148 | PFATAL("signalfd()");
149 | int i;
150 | for (i=0; i < HPIDS_SIZE; i++)
151 | INIT_HLIST_HEAD(&trace->hpids[i]);
152 |
153 | trace->callback = callback;
154 | trace->userdata = userdata;
155 |
156 | INIT_LIST_HEAD(&trace->list_of_waitpid_reports);
157 | return trace;
158 | }
159 |
160 | void trace_free(struct trace *trace) {
161 | close(trace->sfd);
162 | trace->sfd = -1;
163 |
164 | int i;
165 | for (i=0; i < HPIDS_SIZE; i++) {
166 | struct hlist_node *pos;
167 | hlist_for_each(pos, &trace->hpids[i]) {
168 | struct trace_process *process =
169 | hlist_entry(pos, struct trace_process, node);
170 | ptrace(PTRACE_DETACH, process->pid, NULL, NULL);
171 | trace_process_del(trace, process);
172 | }
173 | }
174 | free(trace);
175 | }
176 |
177 | int trace_continue(struct trace_process *process,
178 | trace_callback callback, void *userdata) {
179 | process->callback = callback;
180 | process->userdata = userdata;
181 | return 0;
182 | }
183 |
184 | int trace_sfd(struct trace *trace) {
185 | return trace->sfd;
186 | }
187 |
188 | int trace_process_count(struct trace *trace) {
189 | return trace->process_count;
190 | }
191 |
192 | /* It's okay to return -1, we can use memcpy using ptrace. */
193 | static int mem_fd_open(int pid) {
194 | char path[64];
195 | snprintf(path, sizeof(path), "/proc/%i/mem", pid);
196 | int fd = open(path, O_RDONLY);
197 | if (fd == -1)
198 | PFATAL("open(%s, O_RDONLY)\n%s", path,
199 | "\t\t\tThis may be caused by trying to ptrace a detached\n"
200 | "\t\t\tprocess. Consider disabling the 'ptrace_scope'\n"
201 | "\t\t\tprotection. You may do this by running:\n"
202 | "\t\t\t $ sudo sysctl kernel.yama.ptrace_scope=0");
203 | if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
204 | PFATAL("fcntl(FD_CLOEXEC)");
205 | return fd;
206 | }
207 |
208 | static struct trace_process *trace_process_new(struct trace *trace, int pid) {
209 | struct trace_process *process = calloc(1, sizeof(struct trace_process));
210 | process->pid = pid;
211 | process->mem_fd = mem_fd_open(pid);
212 | trace->process_count += 1;
213 | hlist_add_head(&process->node, &trace->hpids[pid % HPIDS_SIZE]);
214 | return process;
215 | }
216 |
217 | static void trace_process_del(struct trace *trace, struct trace_process *process) {
218 | hlist_del(&process->node);
219 | trace->process_count -= 1;
220 | if (process->mem_fd != -1)
221 | close(process->mem_fd);
222 | free(process);
223 | }
224 |
225 | int trace_execvp(struct trace *trace, char **argv) {
226 | int pid = fork();
227 | if (pid == -1)
228 | PFATAL("fork()");
229 |
230 | if (pid == 0) {
231 | // Make sure no descriptors leak (did you use O_CLOEXEC?)
232 | // Restore default sigprocmask
233 | sigset_t mask;
234 | sigemptyset(&mask);
235 | sigaddset(&mask, SIGCHLD);
236 | sigprocmask(SIG_UNBLOCK, &mask, NULL);
237 |
238 | int r = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
239 | if (r < 0)
240 | PFATAL("ptrace(PTRACE_TRACEME)");
241 | // Wait for the parent to catch up.
242 | raise(SIGSTOP);
243 |
244 | execvp(argv[0], argv);
245 |
246 | char *flat_argv = argv_join(argv, " ");
247 | PFATAL("execvp(\"%s\")", flat_argv);
248 | }
249 |
250 | struct trace_process *process = trace_process_new(trace, pid);
251 | /* On new process call trace->callback, not process->callback. */
252 | trace->callback(process, TRACE_ENTER, (void*)(long)pid, trace->userdata);
253 | return pid;
254 | }
255 |
256 | static struct trace_process *process_by_pid(struct trace *trace, int pid) {
257 | struct hlist_node *pos;
258 | hlist_for_each(pos, &trace->hpids[pid % HPIDS_SIZE]) {
259 | struct trace_process *process = \
260 | hlist_entry(pos, struct trace_process, node);
261 | if (process->pid == pid)
262 | return process;
263 | }
264 | return NULL;
265 | }
266 |
267 | static void ptrace_prepare(int pid) {
268 | int r = ptrace(PTRACE_SETOPTIONS, pid, 0,
269 | PTRACE_O_TRACESYSGOOD |
270 | PTRACE_O_TRACEFORK |
271 | PTRACE_O_TRACEVFORK |
272 | PTRACE_O_TRACECLONE |
273 | PTRACE_O_TRACEEXEC |
274 | PTRACE_O_TRACEEXIT);
275 | if (r != 0)
276 | PFATAL("ptrace(PTRACE_SETOPTIONS)");
277 | }
278 |
279 | static int process_stopped(struct trace *trace, struct trace_process *process,
280 | int signal) {
281 |
282 | int pid = process->pid;
283 | int inject_signal = 0;
284 |
285 | switch (signal) {
286 |
287 | case SIGTRAP | 0x80: { // assuming PTRACE_O_SYSGOOD
288 | REGS_STRUCT regs;
289 | if (ptrace(PTRACE_GETREGS, pid, 0, ®s) < 0)
290 | PFATAL("ptrace(PTRACE_GETREGS)");
291 | int syscall_entry = SYSCALL_ENTRY;
292 | struct trace_sysarg sysarg = {SYSCALL, ARG1, ARG2,
293 | ARG3, ARG4, ARG5, ARG6, RET};
294 | process->regs = regs;
295 | if (syscall_entry != !process->within_syscall)
296 | FATAL("syscall entry - exit desynchronizaion");
297 |
298 | int type = syscall_entry ? TRACE_SYSCALL_ENTER
299 | : TRACE_SYSCALL_EXIT;
300 | process->callback(process, type, &sysarg,
301 | process->userdata);
302 | process->within_syscall = !process->within_syscall;
303 | break; }
304 |
305 | case SIGTRAP | (PTRACE_EVENT_FORK << 8):
306 | case SIGTRAP | (PTRACE_EVENT_VFORK << 8):
307 | case SIGTRAP | (PTRACE_EVENT_CLONE << 8): {
308 | unsigned long child_pid;
309 | if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, &child_pid) < 0)
310 | PFATAL("ptrace(PTRACE_GETEVENTMSG)");
311 | struct trace_process *child_process =
312 | trace_process_new(trace, child_pid);
313 | trace->callback(child_process, TRACE_ENTER,
314 | (void*)child_pid, trace->userdata);
315 | break; }
316 |
317 | case SIGTRAP | PTRACE_EVENT_EXEC << 8: {
318 | // /proc//mem must be re-opened after exec.
319 | if (process->mem_fd != -1)
320 | close(process->mem_fd);
321 | process->mem_fd = mem_fd_open(pid);
322 | break; }
323 |
324 | case SIGTRAP | PTRACE_EVENT_EXIT << 8:
325 | // exit() called, we'll see the process again during WIFEXITED()
326 | break;
327 |
328 | case SIGTRAP:
329 | /* Got a pure SIGTRAP - Why? Let's assume it's
330 | just a normal signal. */
331 | // fall through...
332 | default:
333 | inject_signal = signal;
334 | process->callback(process, TRACE_SIGNAL, &inject_signal,
335 | process->userdata);
336 | break;
337 |
338 | }
339 |
340 | return inject_signal;
341 | }
342 |
343 | static void process_evaluate(struct trace *trace,
344 | struct trace_process *process, int status) {
345 |
346 | int inject_signal = 0;
347 |
348 | if (!process->initialized) {
349 | /* First child SIGSTOPs itself after calling TRACEME,
350 | descendants are STOPPED due to TRACEFORK. */
351 | if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) {
352 | PFATAL("Process in a wrong state! wifstopped=%i wsigstop=%i",
353 | WIFSTOPPED(status), WSTOPSIG(status));
354 | }
355 | ptrace_prepare(process->pid);
356 | process->initialized = 1;
357 | } else {
358 | if (WIFSTOPPED(status)) {
359 | /* We can't use WSTOPSIG(status) - it cuts high bits. */
360 | int signal = (status >> 8) & 0xffff;
361 | inject_signal = process_stopped(trace, process, signal);
362 | } else
363 | if (WIFSIGNALED(status) || WIFEXITED(status)) {
364 | struct trace_exitarg exitarg;
365 | if (WIFSIGNALED(status)) {
366 | exitarg = (struct trace_exitarg){
367 | TRACE_EXIT_SIGNAL, WTERMSIG(status)};
368 | } else {
369 | exitarg = (struct trace_exitarg){
370 | TRACE_EXIT_NORMAL, WEXITSTATUS(status)};
371 | }
372 | process->callback(process, TRACE_EXIT, &exitarg,
373 | process->userdata);
374 | trace_process_del(trace, process);
375 | return;
376 | } else {
377 | SHOUT("%i status 0x%x not understood!", process->pid, status);
378 | }
379 | }
380 |
381 | int r = ptrace(PTRACE_SYSCALL, process->pid, 0, inject_signal);
382 | if (r < 0)
383 | PFATAL("ptrace(PTRACE_SYSCALL)");
384 | }
385 |
386 |
387 | /* Call this method when sfd is readable */
388 | int trace_read(struct trace *trace) {
389 | struct signalfd_siginfo sinfo[4];
390 |
391 | int r = read(trace->sfd, &sinfo, sizeof(sinfo));
392 | if (r < 0) {
393 | if (errno == EWOULDBLOCK) {
394 | r = 0;
395 | } else {
396 | PFATAL("read(signal_fd)");
397 | }
398 | }
399 |
400 | if (r % sizeof(struct signalfd_siginfo) != 0)
401 | PFATAL("read(signal_fd) not aligned to signalfd_siginfo");
402 |
403 | /* Although signalfd() socket is capable of buffering signals,
404 | * losing one is still very much possible. Therefore it makes
405 | * no sense to actually look at the results of read(). */
406 |
407 | // int sinfo_sz = r / sizeof(struct signalfd_siginfo);
408 |
409 | /* Unfortunately waitpid(*) is O(n), but by running
410 | * waitpid(-1) we might starve processes with higher pids
411 | * (further down the child list in the kernel). But this is
412 | * not a big deal for us. */
413 |
414 | int counter = 0;
415 |
416 | while ( 1 ) {
417 | int status;
418 | int pid = waitpid(-1, &status, WNOHANG | __WALL);
419 | if (pid == -1) {
420 | if (errno != ECHILD)
421 | PFATAL("waitpid()");
422 | break;
423 | }
424 | if (pid == 0) {
425 | break;
426 | }
427 |
428 | struct trace_process *process = process_by_pid(trace, pid);
429 | if (process) {
430 | /* Process it immediately. The same pid can be
431 | * handled in this loop many times. */
432 | process_evaluate(trace, process, status);
433 | } else {
434 | struct waitpid_report *sr =
435 | calloc(1, sizeof(struct waitpid_report));
436 | sr->pid = pid;
437 | sr->status = status;
438 | list_add(&sr->in_list, &trace->list_of_waitpid_reports);
439 | }
440 | counter += 1;
441 | }
442 |
443 | /* Process waitpids from processes we don't know only after
444 | * all known processes were handled. This is required due to a
445 | * race: we might get info from a new child process before
446 | * parent tells us he did clone/fork. We end up in a report
447 | * from an unknown process in such case. */
448 | struct list_head *pos, *tmp;
449 | list_for_each_safe(pos, tmp, &trace->list_of_waitpid_reports) {
450 |
451 | struct waitpid_report *sr =
452 | hlist_entry(pos, struct waitpid_report, in_list);
453 |
454 | list_del(&sr->in_list);
455 | struct trace_process *process = process_by_pid(trace, sr->pid);
456 | if (!process) {
457 | SHOUT("waitpid() returned unknown process pid=%i status=0x%x",
458 | sr->pid, sr->status);
459 | } else {
460 | process_evaluate(trace, process, sr->status);
461 | }
462 |
463 | free(sr);
464 | }
465 |
466 | return counter;
467 | }
468 |
469 | void trace_setregs(struct trace_process *process, struct trace_sysarg *sysarg) {
470 | REGS_STRUCT regs = process->regs;
471 | SYSCALL = sysarg->number;
472 | ARG1 = sysarg->arg1;
473 | ARG2 = sysarg->arg2;
474 | ARG3 = sysarg->arg3;
475 | ARG4 = sysarg->arg4;
476 | ARG5 = sysarg->arg5;
477 | ARG6 = sysarg->arg6;
478 | RET = sysarg->ret;
479 | if (ptrace(PTRACE_SETREGS, process->pid, 0, ®s) < 0)
480 | PFATAL("ptrace(PTRACE_SETREGS)");
481 | }
482 |
483 | static int copy_from_user_ptrace(struct trace_process *process, void *dst,
484 | unsigned long src, size_t len) {
485 | size_t words = len / sizeof(long);
486 | long *word_src = (long*)src;
487 | long *word_dst = dst;
488 | unsigned faults = 0;
489 | unsigned i;
490 | for (i = 0; i < words; i++) {
491 | if (errno)
492 | errno = 0;
493 | word_dst[i] = ptrace(PTRACE_PEEKDATA, process->pid,
494 | &word_src[i], NULL);
495 | if (errno) {
496 | if (errno == EIO || errno == EFAULT)
497 | faults += 1;
498 | else
499 | PFATAL("ptrace(PTRACE_PEEKDATA)");
500 | }
501 | }
502 | return faults * sizeof(long);
503 | }
504 |
505 | static int copy_to_user_ptrace(struct trace_process *process, unsigned long dst,
506 | void *src, size_t len) {
507 | size_t words = len / sizeof(long);
508 | long *qword_src = src;
509 | long *qword_dst = (long*)dst;
510 | unsigned faults = 0;
511 | unsigned i;
512 | for (i = 0; i < words; i++) {
513 | int r = ptrace(PTRACE_POKEDATA, process->pid,
514 | &qword_dst[i], qword_src[i]);
515 | if (r == -1) {
516 | if (errno == EIO || errno == EFAULT)
517 | faults += 1;
518 | else
519 | PFATAL("ptrace(PTRACE_POKEDATA)");
520 | }
521 | }
522 | return faults * sizeof(long);
523 | }
524 |
525 | static int copy_from_user_fd(struct trace_process *process, void *dst,
526 | unsigned long src, unsigned len) {
527 | int r = pread(process->mem_fd, dst, len, src);
528 | if (r < 0)
529 | PFATAL("pread(\"/proc/%i/mem\", offset=0x%lx, len=%u) = %i",
530 | process->pid, src, len, r);
531 | return len - (unsigned)r;
532 | }
533 |
534 | int copy_from_user(struct trace_process *process, void *dst,
535 | unsigned long src, size_t len) {
536 | if (src % sizeof(long) || len % sizeof(long))
537 | PFATAL("unaligned");
538 |
539 | if (process->mem_fd != -1)
540 | return copy_from_user_fd(process, dst, src, len);
541 | return copy_from_user_ptrace(process, dst, src, len);
542 | }
543 |
544 | int copy_to_user(struct trace_process *process, unsigned long dst,
545 | void *src, size_t len) {
546 | if (dst % sizeof(long) || len % sizeof(long))
547 | PFATAL("unaligned");
548 |
549 | return copy_to_user_ptrace(process, dst, src, len);
550 | }
551 |
--------------------------------------------------------------------------------
/src/trace.h:
--------------------------------------------------------------------------------
1 | enum trace_types {
2 | TRACE_ENTER, /* arg = (void*)pid */
3 | TRACE_EXIT, /* arg = ptr to trace_exitarg */
4 | TRACE_SYSCALL_ENTER, /* arg = ptr to trace_sysarg */
5 | TRACE_SYSCALL_EXIT, /* arg = ptr to trace_sysarg */
6 | TRACE_SIGNAL /* arg = ptr to signal number */
7 | };
8 |
9 | enum {
10 | TRACE_EXIT_NORMAL,
11 | TRACE_EXIT_SIGNAL
12 | };
13 |
14 | struct trace_exitarg {
15 | int type; /* normal exit or signal */
16 | int value; /* signal no or exit status */
17 | };
18 |
19 | struct trace_sysarg {
20 | int number;
21 | long arg1;
22 | long arg2;
23 | long arg3;
24 | long arg4;
25 | long arg5;
26 | long arg6;
27 | long ret;
28 | };
29 |
30 |
31 | struct trace;
32 | struct trace_process;
33 | typedef int (*trace_callback)(struct trace_process *process,
34 | int type, void *arg, void *userdata);
35 |
36 | /* Allocate and initialize `struct trace`. `callback` with `tracedata`
37 | * will be called on the arrival of a new process. */
38 | struct trace *trace_new(trace_callback callback, void *userdata);
39 |
40 | /* Release `struct trace`, stop tracing processes (PTRACE_DETACH). */
41 | void trace_free(struct trace *trace);
42 |
43 | /* Run a traced process. */
44 | int trace_execvp(struct trace *trace, char **argv);
45 |
46 | /* Get a signal file descriptor. If readable call `trace_read`. */
47 | int trace_sfd(struct trace *trace);
48 |
49 | /* Number of actively traced processes. */
50 | int trace_process_count(struct trace *trace);
51 |
52 | /* Main loop, call it when `sfd` is readable. */
53 | int trace_read(struct trace *trace);
54 |
55 | /* Set process callback. */
56 | int trace_continue(struct trace_process *process,
57 | trace_callback callback, void *userdata);
58 |
59 | /* Set registers back in the process. Only makes sense during
60 | * TRACE_SYSCALL_* callback. */
61 | void trace_setregs(struct trace_process *process, struct trace_sysarg *sysarg);
62 |
63 | /* Copy data to and from a process. Data length and address must be
64 | word-aligned. */
65 | int copy_from_user(struct trace_process *process, void *dst,
66 | unsigned long src, size_t len);
67 | int copy_to_user(struct trace_process *process, unsigned long dst,
68 | void *src, size_t len);
69 |
--------------------------------------------------------------------------------
/src/types.h:
--------------------------------------------------------------------------------
1 | #ifndef _HAVE_TYPES_H
2 | #define _HAVE_TYPES_H
3 |
4 | #include
5 |
6 | typedef uint8_t u8;
7 | typedef uint16_t u16;
8 | typedef uint32_t u32;
9 | typedef uint64_t u64;
10 |
11 | typedef int8_t s8;
12 | typedef int16_t s16;
13 | typedef int32_t s32;
14 | typedef int64_t s64;
15 |
16 | #if defined(__x86_64__)
17 | typedef __int128 s128;
18 | typedef s128 flux_time;
19 | #else
20 | typedef u64 flux_time;
21 | #endif
22 |
23 |
24 | #ifndef MIN
25 | # define MIN(_a,_b) ((_a) > (_b) ? (_b) : (_a))
26 | #endif /* !MIN */
27 |
28 | #ifndef MAX
29 | # define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b))
30 | #endif /* !MAX */
31 |
32 | #endif /* ^_HAVE_TYPES_H */
33 |
--------------------------------------------------------------------------------
/src/uevent.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include "uevent.h"
10 |
11 | struct timespec uevent_now;
12 |
13 |
14 | struct uevent *uevent_new(struct uevent *uevent) {
15 | if (!uevent)
16 | uevent = malloc(sizeof(struct uevent));
17 | memset(uevent, 0, sizeof(struct uevent));
18 | uevent->used_slots = 0;
19 | uevent->max_fd = 0;
20 | FD_ZERO(&uevent->readfds);
21 | FD_ZERO(&uevent->writefds);
22 | return uevent;
23 | }
24 |
25 | int uevent_select(struct uevent *uevent, struct timeval *timeout) {
26 | fd_set rfds;
27 | fd_set wfds;
28 | memcpy(&rfds, &uevent->readfds, sizeof(fd_set));
29 | memcpy(&wfds, &uevent->writefds, sizeof(fd_set));
30 | int r = select(uevent->max_fd + 1, &rfds, &wfds, NULL, timeout);
31 | if (-1 == r) {
32 | if (EINTR != errno) {
33 | perror("select()");
34 | abort();
35 | }
36 | }
37 |
38 | clock_gettime(CLOCK_REALTIME, &uevent_now);
39 |
40 | int i;
41 | for (i=0; i < uevent->max_fd+1; i++) {
42 | int mask = 0;
43 | if (FD_ISSET(i, &rfds)) {
44 | mask |= UEVENT_READ;
45 | }
46 | if (FD_ISSET(i, &wfds)) {
47 | mask |= UEVENT_WRITE;
48 | }
49 | if (mask) {
50 | uevent->fdmap[i].callback(uevent, i, mask,
51 | uevent->fdmap[i].userdata);
52 | }
53 | }
54 | return r;
55 | }
56 |
57 | int uevent_loop(struct uevent *uevent) {
58 | int counter = 0;
59 | while (uevent->used_slots) {
60 | uevent_select(uevent, NULL);
61 | counter++;
62 | }
63 | return counter;
64 | }
65 |
66 |
67 | int uevent_yield(struct uevent *uevent, int fd, int mask,
68 | uevent_callback_t callback, void *userdata) {
69 | if (fd >= __FD_SETSIZE) {
70 | fprintf(stderr, "Can't handle more than %i descriptors.",
71 | __FD_SETSIZE);
72 | abort();
73 | }
74 | if (!callback) {
75 | abort();
76 | }
77 |
78 | if (mask & UEVENT_READ) {
79 | FD_SET(fd, &uevent->readfds);
80 | }
81 | if (mask & UEVENT_WRITE) {
82 | FD_SET(fd, &uevent->writefds);
83 | }
84 | if (!uevent->fdmap[fd].callback) {
85 | uevent->used_slots++;
86 | if (uevent->max_fd < fd) {
87 | uevent->max_fd = fd;
88 | }
89 | }
90 | uevent->fdmap[fd].callback = callback;
91 | uevent->fdmap[fd].userdata = userdata;
92 | return 1;
93 | }
94 |
95 | void uevent_clear(struct uevent *uevent, int fd) {
96 | FD_CLR(fd, &uevent->readfds);
97 | FD_CLR(fd, &uevent->writefds);
98 | uevent->fdmap[fd].callback = NULL;
99 | uevent->fdmap[fd].userdata = NULL;
100 | uevent->used_slots--;
101 | }
102 |
103 |
--------------------------------------------------------------------------------
/src/uevent.h:
--------------------------------------------------------------------------------
1 | #ifndef _UEVENT_H
2 | #define _UEVENT_H
3 |
4 | struct uevent;
5 |
6 | typedef int (*uevent_callback_t)(struct uevent *uevent, int sd, int mask, void *userdata);
7 |
8 | struct uevent {
9 | int max_slots;
10 | int curr_slot;
11 | int used_slots;
12 |
13 | struct {
14 | uevent_callback_t callback;
15 | void *userdata;
16 | } fdmap[__FD_SETSIZE];
17 |
18 | fd_set readfds;
19 | fd_set writefds;
20 | int max_fd;
21 |
22 | };
23 |
24 | enum {
25 | UEVENT_WRITE = 1 << 0,
26 | UEVENT_READ = 1 << 1
27 | };
28 |
29 |
30 | struct uevent *uevent_new(struct uevent *uevent);
31 | int uevent_loop(struct uevent *uevent);
32 | int uevent_select(struct uevent *uevent, struct timeval *timeout);
33 |
34 | int uevent_yield(struct uevent *uevent, int fd, int mask, uevent_callback_t callback, void *userdata);
35 | void uevent_clear(struct uevent *uevent, int fd);
36 |
37 |
38 | #endif // _UEVENT_H
39 |
--------------------------------------------------------------------------------
/src/wrapper.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "list.h"
8 | #include "types.h"
9 | #include "trace.h"
10 | #include "fluxcapacitor.h"
11 | #include "scnums.h"
12 |
13 | extern struct options options;
14 |
15 |
16 | enum {
17 | TYPE_MSEC = 1,
18 | TYPE_TIMEVAL,
19 | TYPE_TIMESPEC,
20 | TYPE_FOREVER
21 | };
22 |
23 | /* Responsibilities:
24 | * - save child->blocked_time if syscall is recognized
25 | * - work together with preload.c to simplify syscall parameters
26 | */
27 | void wrapper_syscall_enter(struct child *child, struct trace_sysarg *sysarg) {
28 |
29 | int type = 0;
30 | long value = 0;
31 |
32 | switch ((unsigned short)sysarg->number) {
33 | case __NR_epoll_wait:
34 | case __NR_epoll_pwait:
35 | type = TYPE_MSEC; value = sysarg->arg4; break;
36 |
37 | #ifdef __NR_select
38 | case __NR_select:
39 | #endif
40 | #ifdef __NR__newselect
41 | case __NR__newselect:
42 | type = TYPE_TIMEVAL; value = sysarg->arg5; break;
43 | #endif
44 | case __NR_pselect6:
45 | type = TYPE_TIMESPEC; value = sysarg->arg5; break;
46 |
47 | case __NR_poll:
48 | type = TYPE_MSEC; value = sysarg->arg3; break;
49 | case __NR_ppoll:
50 | type = TYPE_TIMESPEC; value = sysarg->arg3; break;
51 |
52 | case __NR_clock_nanosleep:
53 | FATAL("clock_nanosleep() unsupported");
54 |
55 | case __NR_nanosleep:
56 | /* Second argument to nanosleep() can be ignored, it's
57 | only supposed to be set on EINTR. */
58 | type = TYPE_TIMESPEC; value = sysarg->arg1;
59 | break;
60 |
61 | /* Anti-debugging machinery. Prevent processes from disabling ptrace. */
62 | case __NR_prctl:
63 | if (sysarg->arg1 == PR_SET_DUMPABLE && sysarg->arg2 == 0) {
64 | SHOUT("[ ] %i pacyfying prctl(PR_SET_DUMPABLE, 0)",
65 | child->pid);
66 | sysarg->arg2 = 1;
67 | trace_setregs(child->process, sysarg);
68 | }
69 | break;
70 | }
71 |
72 | if (!type)
73 | return;
74 |
75 | flux_time timeout = TIMEOUT_UNKNOWN;
76 | switch (type) {
77 | case TYPE_MSEC:
78 | if (value < 0) {
79 | timeout = TIMEOUT_FOREVER;
80 | } else {
81 | timeout = MSEC_NSEC(value);
82 | }
83 | break;
84 |
85 | case TYPE_TIMEVAL:
86 | if (value == 0 ) { /* NULL */
87 | timeout = TIMEOUT_FOREVER;
88 | } else {
89 | struct timeval tv;
90 | copy_from_user(child->process, &tv, value, sizeof(struct timeval));
91 | timeout = TIMEVAL_NSEC(&tv);
92 | }
93 | break;
94 |
95 | case TYPE_TIMESPEC:
96 | if (value == 0) { /* NULL */
97 | timeout = TIMEOUT_FOREVER;
98 | } else {
99 | struct timespec ts;
100 | copy_from_user(child->process, &ts, value, sizeof(struct timespec));
101 | timeout = TIMESPEC_NSEC(&ts);
102 | }
103 | break;
104 |
105 | case TYPE_FOREVER:
106 | timeout = TIMEOUT_FOREVER;
107 | break;
108 |
109 | default:
110 | FATAL("");
111 | }
112 |
113 | switch (timeout) {
114 | case TIMEOUT_UNKNOWN:
115 | case TIMEOUT_FOREVER:
116 | PRINT(" ~ %i blocking on %s() %s",
117 | child->pid, syscall_to_str(sysarg->number),
118 | timeout == TIMEOUT_FOREVER ? "forever" : "unknown timeout");
119 | child->blocked_until = timeout;
120 | break;
121 | default:
122 | PRINT(" ~ %i blocking on %s() for %.3f sec",
123 | child->pid, syscall_to_str(sysarg->number),
124 | timeout / 1000000000.);
125 | child->blocked_until = (flux_time)TIMESPEC_NSEC(&uevent_now) +
126 | child->parent->time_drift + (flux_time)timeout;
127 | }
128 | child->syscall_no = sysarg->number;
129 | }
130 |
131 | int wrapper_syscall_exit(struct child *child, struct trace_sysarg *sysarg) {
132 |
133 | child->syscall_no = 0;
134 |
135 | switch (sysarg->number) {
136 |
137 | case __NR_clock_gettime: {
138 | if (sysarg->ret == 0) {
139 | if (sysarg->arg1 != CLOCK_REALTIME && sysarg->arg1 != CLOCK_MONOTONIC)
140 | FATAL("%li ", sysarg->arg1);
141 | struct timespec ts;
142 | clock_gettime(CLOCK_REALTIME, &ts);
143 | flux_time newtime = TIMESPEC_NSEC(&ts) + child->parent->time_drift;
144 | ts = NSEC_TIMESPEC(newtime);
145 | copy_to_user(child->process, sysarg->arg2, &ts,
146 | sizeof(struct timespec));
147 | }
148 | break;}
149 |
150 | }
151 | return 0;
152 |
153 | }
154 |
155 |
156 | /* When we break a syscall by sending a signal, kernel returns
157 | * ERESTART_RESTARTBLOCK or similar error. Here we rewrite this value
158 | * to a result that will read: "timeout". */
159 | void wrapper_pacify_signal(struct child *child, struct trace_sysarg *sysarg) {
160 |
161 | long orig_ret = sysarg->ret;
162 |
163 | switch (sysarg->number) {
164 | case __NR_epoll_wait:
165 | case __NR_epoll_pwait:
166 | #ifdef __NR__newselect
167 | case __NR__newselect:
168 | #endif
169 | #ifdef __NR_select
170 | case __NR_select:
171 | #endif
172 | case __NR_nanosleep:
173 | case __NR_pselect6:
174 | case __NR_poll:
175 | case __NR_ppoll:
176 | if (sysarg->ret == -EINTR) {
177 | sysarg->ret = 0;
178 | }
179 | if (-512 >= sysarg->ret && sysarg->ret >= -517) { // ERESTART_RESTARTBLOCK
180 | sysarg->ret = 0;
181 | }
182 | break;
183 | default:
184 | return;
185 | }
186 | PRINT(" ~ %i restarting %s(). kernel returned %li, changed to %li",
187 | child->pid, syscall_to_str(sysarg->number), orig_ret, sysarg->ret);
188 |
189 | trace_setregs(child->process, sysarg);
190 | }
191 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/majek/fluxcapacitor/b4e646e3048a317b33f5a84741b7962fd69cdc61/tests/__init__.py
--------------------------------------------------------------------------------
/tests/tests.py:
--------------------------------------------------------------------------------
1 | import functools
2 | import unittest
3 | import time
4 | import os
5 | import subprocess
6 | import tempfile
7 |
8 | debug = False
9 |
10 | class TestCase(unittest.TestCase):
11 | def setUp(self):
12 | self.fcpath = os.getenv('FCPATH', None)
13 | assert self.fcpath is not None, "Set FCPATH environment variable first!"
14 |
15 | def tearDown(self):
16 | pass
17 |
18 | def do_system(self, cmd, returncode=0):
19 | rc = subprocess.call(cmd, shell=True)
20 | self.assertEqual(rc, returncode)
21 | return True
22 |
23 | def system(self, cmd, returncode=0, ignore_stderr=False, capture_stdout=False):
24 | if self.fcpath:
25 | final_cmd = "%s -- %s" % (self.fcpath, cmd)
26 | else:
27 | final_cmd = cmd
28 | if ignore_stderr:
29 | final_cmd += ' 2>/dev/null'
30 | if debug:
31 | print "debug: %r" % (final_cmd,)
32 |
33 | if capture_stdout:
34 | stdout = tempfile.TemporaryFile()
35 | else:
36 | stdout = None
37 |
38 | rc = subprocess.call(final_cmd, shell=True, stdout=stdout)
39 | self.assertEqual(rc, returncode)
40 |
41 | if capture_stdout:
42 | stdout.seek(0)
43 | return stdout.read()
44 | return True
45 |
46 |
47 | def at_most(seconds=None):
48 | def decorator(fn):
49 | @functools.wraps(fn)
50 | def wrapper(self, *args, **kwargs):
51 | t0 = time.time()
52 | ret = fn(self, *args, **kwargs)
53 | t1 = time.time()
54 | td = t1 - t0
55 | self.assertTrue(td <= seconds,
56 | "Task took %.1f, not %.1f seconds" \
57 | % (td, seconds))
58 | return ret
59 | return wrapper
60 | return decorator
61 |
62 |
63 | def compile(code=None):
64 | def decorator(fn):
65 | @functools.wraps(fn)
66 | def wrapper(self, *args, **kwargs):
67 | (fd, compiled) = tempfile.mkstemp()
68 | os.close(fd)
69 | (fd, source) = tempfile.mkstemp(suffix=".c")
70 | os.write(fd, code + '\n')
71 | os.close(fd)
72 | try:
73 | cc_cmd = "%s %s -Os -Wall %s -o %s" \
74 | % (os.getenv('CC', 'cc'), os.getenv('CFLAGS', ''),
75 | source, compiled)
76 | rc = subprocess.call(cc_cmd, shell=True)
77 | self.assertEqual(rc, 0)
78 |
79 | kwargs['compiled'] = compiled
80 | ret = fn(self, *args, **kwargs)
81 | finally:
82 | if not debug:
83 | os.unlink(source)
84 | os.unlink(compiled)
85 | else:
86 | print "debug: not unlinked %s %s" % (source, compiled)
87 | return ret
88 | return wrapper
89 | return decorator
90 |
91 |
92 | def savefile(text=None, suffix="txt"):
93 | def decorator(fn):
94 | @functools.wraps(fn)
95 | def wrapper(self, *args, **kwargs):
96 | (fd, compiled) = tempfile.mkstemp()
97 | os.close(fd)
98 | (fd, filename) = tempfile.mkstemp(suffix="." + suffix)
99 | os.write(fd, text.lstrip() + '\n')
100 | os.close(fd)
101 | try:
102 | kwargs['filename'] = filename
103 | ret = fn(self, *args, **kwargs)
104 | finally:
105 | if not debug:
106 | os.unlink(filename)
107 | else:
108 | print "debug: not unlinked %s" % (filename,)
109 | return ret
110 | return wrapper
111 | return decorator
112 |
--------------------------------------------------------------------------------
/tests/tests_basic.py:
--------------------------------------------------------------------------------
1 | import os
2 | import tests
3 | from tests import at_most, compile, savefile
4 | import subprocess
5 |
6 |
7 | node_present = True
8 | erlang_present = True
9 |
10 | if os.system("node -v >/dev/null 2>/dev/null") != 0:
11 | print " [!] ignoring nodejs tests"
12 | node_present = False
13 |
14 | if (os.system("erl -version >/dev/null 2>/dev/null") != 0 or
15 | os.system("which escript >/dev/null 2>/dev/null") != 0):
16 | print " [!] ignoring erlang tests"
17 | erlang_present = False
18 |
19 |
20 | sleep_sort_script='''\
21 | #!/bin/bash
22 | echo "Unsorted: $*"
23 | function f() {
24 | sleep "$1"
25 | echo -n "$1 "
26 | }
27 | while [ -n "$1" ]; do
28 | f "$1" &
29 | shift
30 | done
31 | wait
32 | echo
33 | '''
34 |
35 | class SingleProcess(tests.TestCase):
36 | @at_most(seconds=2)
37 | def test_bash_sleep(self):
38 | self.system("sleep 10")
39 |
40 | @at_most(seconds=2)
41 | def test_bash_bash_sleep(self):
42 | self.system("bash -c 'sleep 120;'")
43 |
44 |
45 | @at_most(seconds=2)
46 | def test_python2_sleep(self):
47 | self.system('python2 -c "import time; time.sleep(10)"')
48 |
49 | @at_most(seconds=2)
50 | def test_python2_select(self):
51 | self.system('python2 -c "import select; select.select([],[],[], 10)"')
52 |
53 | @at_most(seconds=2)
54 | def test_python2_poll(self):
55 | self.system('python2 -c "import select; select.poll().poll(10000)"')
56 |
57 | @at_most(seconds=2)
58 | def test_python2_epoll(self):
59 | self.system('python2 -c "import select; select.epoll().poll(10000)"')
60 |
61 |
62 | @at_most(seconds=2)
63 | def test_node_epoll(self):
64 | if node_present:
65 | self.system('node -e "setTimeout(function(){},10000);"')
66 |
67 |
68 | def test_bad_command(self):
69 | self.system('command_that_doesnt exist',
70 | returncode=127, ignore_stderr=True)
71 |
72 | def test_return_status(self):
73 | self.system('python2 -c "import sys; sys.exit(188)"', returncode=188)
74 | self.system('python2 -c "import sys; sys.exit(-1)"', returncode=255)
75 |
76 |
77 | @at_most(seconds=2)
78 | @compile(code='''
79 | #include
80 | int main() {
81 | sleep(10);
82 | return(0);
83 | }''')
84 | def test_c_sleep(self, compiled=None):
85 | self.system(compiled)
86 |
87 |
88 | @at_most(seconds=2)
89 | @compile(code='''
90 | #include
91 | int main() {
92 | struct timespec ts = {1, 0};
93 | nanosleep(&ts, NULL);
94 | return(0);
95 | }''')
96 | def test_c_nanosleep(self, compiled=None):
97 | self.system(compiled)
98 |
99 |
100 |
101 | @at_most(seconds=5)
102 | @savefile(suffix="erl", text='''\
103 | #!/usr/bin/env escript
104 | %%! -smp disable +A1 +K true -noinput
105 | -export([main/1]).
106 | main(_) ->
107 | timer:sleep(10*1000),
108 | halt(0).
109 | ''')
110 | def test_erlang_sleep(self, filename=None):
111 | if erlang_present:
112 | self.system("escript %s" % (filename,))
113 |
114 | @at_most(seconds=5)
115 | @savefile(suffix="erl", text='''\
116 | #!/usr/bin/env escript
117 | %%! -smp enable +A30 +K true -noinput
118 | -export([main/1]).
119 | main(_) ->
120 | timer:sleep(10*1000),
121 | halt(0).
122 | ''')
123 | def test_erlang_sleep_smp(self, filename=None):
124 | if erlang_present:
125 | self.system("escript %s" % (filename,))
126 |
127 | @at_most(seconds=5)
128 | @savefile(suffix="erl", text='''\
129 | #!/usr/bin/env escript
130 | %%! -smp enable +A30 +K false -noinput
131 | -export([main/1]).
132 | main(_) ->
133 | timer:sleep(10*1000),
134 | halt(0).
135 | ''')
136 | def test_erlang_sleep_smp_no_epoll(self, filename=None):
137 | if erlang_present:
138 | self.system("escript %s" % (filename,))
139 |
140 |
141 | @at_most(seconds=5)
142 | @savefile(suffix="erl", text='''\
143 | #!/usr/bin/env escript
144 | %%! -smp disable +A1 +K true -noinput
145 | -export([main/1]).
146 | main(_) ->
147 | self() ! msg,
148 | proc(10),
149 | receive
150 | _ -> ok
151 | end.
152 |
153 | proc(0) ->
154 | receive
155 | _ -> halt(0)
156 | end;
157 | proc(N) ->
158 | Pid = spawn(fun () -> proc(N-1) end),
159 | receive
160 | _ -> timer:sleep(1000),
161 | Pid ! msg
162 | end.
163 | ''')
164 | def test_erlang_process_staircase(self, filename=None):
165 | if erlang_present:
166 | self.system("escript %s" % (filename,))
167 |
168 |
169 | @at_most(seconds=2)
170 | def test_perl_sleep(self):
171 | self.system("perl -e 'sleep 10'")
172 |
173 |
174 | @at_most(seconds=5)
175 | @savefile(suffix="sh", text=sleep_sort_script)
176 | def test_sleep_sort(self, filename=None):
177 | self.system("bash %s 1 12 1231 123213 13212 > /dev/null" % (filename,))
178 |
179 | @at_most(seconds=5)
180 | @savefile(suffix="sh", text=sleep_sort_script)
181 | def test_sleep_sort(self, filename=None):
182 | self.system("bash %s 5 3 6 3 6 3 1 4 7 > /dev/null" % (filename,))
183 |
184 | @at_most(seconds=10)
185 | def test_parallel_sleeps(self):
186 | for i in range(10):
187 | stdout = self.system(' -- '.join(['bash -c "date +%s"',
188 | 'bash -c "sleep 60; date +%s"',
189 | 'bash -c "sleep 120; date +%s"']),
190 | capture_stdout=True)
191 | a, b, c = [int(l) for l in stdout.split()]
192 | assert 55 < (b - a) < 65, str(b-a)
193 | assert 55 < (c - b) < 65, str(c-b)
194 | assert 110 < (c - a) < 130, str(c-a)
195 |
196 | @at_most(seconds=3)
197 | def test_file_descriptor_leak(self):
198 | out = subprocess.check_output("ls /proc/self/fd", shell=True)
199 | normal_fds = len(out.split('\n'))
200 | stdout = self.system(' -- '.join(['sleep 1',
201 | 'sleep 60',
202 | 'sleep 120',
203 | 'bash -c "sleep 180; ls /proc/self/fd"']),
204 | capture_stdout=True)
205 | after_fork_fds = len(stdout.split('\n'))
206 | assert normal_fds == after_fork_fds
207 |
208 |
209 | @at_most(seconds=4)
210 | def test_2546_wraparound(self):
211 | if os.uname()[4] == "x86_64":
212 | stdout = self.system("bash -c 'for i in `seq 1 55`; do sleep 315360000; done; date +%Y'",
213 | capture_stdout=True)
214 | assert int(stdout) > 2500
215 |
216 |
217 | if __name__ == '__main__':
218 | import unittest
219 | unittest.main()
220 |
--------------------------------------------------------------------------------