├── .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 | [![Build Status](https://travis-ci.org/majek/fluxcapacitor.png)](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 | --------------------------------------------------------------------------------