You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
LibSee overrides LibC symbols using LD_PRELOAD, profiling the most commonly used functions, and, optionally, fuzzing their behavior for testing.
The library yields a few binaries when compiled:
There are several things worth knowing, that came handy implementing this.
One way to implement this library would be to override the _start symbols, but implementing correct loading sequence for a binary is tricky, so I use conventional dlsym to lookup the symbols on first function invocation.
On x86_64 architecture, the rdtscp instruction yields both the CPU cycle and also the unique identifier of the core. Very handy if you are profiling a multi-threaded application.
Once the unloading sequence reaches libsee.so, the STDOUT is already closed. So if you want to print to the console, you may want to reopen the /dev/tty device before printing usage stats.
Calling convention for system calls on Aarch64 and x86 differs significantly. On Aarch64 I use the generalized openat with opcode 56. On x86 it's opcode 2.
On MacOS the sprintf, vsprintf, snprintf, vsnprintf are macros. You have to #undef them.
On Release builds compilers love replacing your code with memset and memcpy calls. As the symbol can't be found from inside LibSee, it will SEGFAULT so don't forget to disable such optimizations for built-ins -fno-builtin.
No symbol versioning is implemented, vanilla dlsym is used over the dlvsym.
Coverage
LibC standard is surprisingly long, so not all of the functions are covered.
Feel free to suggest PRs covering the rest: