The purpose of this library is to resolve the target addresses of an indirect jump in the purpose of dynamic binary instrumentation.
There exist multiple dynamic tracing methods. One of them is to replace, or patch, the instruction while the program is running. This is usually done by replacing one or more instructions by a jump that change the flow of the program to execute instrumentation code. A relevant implementation of such instrumentation technique exist in the Linux kernel under the name of Kprobes.
For optimised x86 Kprobes, where instructions are replaced by a jump and not a trap, it may be necessary to replace multiple instructions to fit a 5-bytes jump. In that case, it is crucial that the second or third instruction replaced are not executed directly. Kprobe analyses the instructions at the function-level to make sure that no jump lands in those instructions.
There exist two kind of jumps: direct (immediate) jump or
indirect (register or memory) jump. Checking where a direct
jump (e.g. jmpq 0x142
) lands can be done simply by looking
at the instruction. This is much harder for the indirect jump (e.g. jmpq %rax
) case. Just by looking at the
instruction, it may jump anywhere in the entire address
space of the program.
Kprobe doesn't overwrite multiple instructions if an indirect jump is present in the function since it can't tell where it is going to land.
The goal of this work is to offer a reliable and efficient way of computing where an indirect jump may land so that dynamic tracing application may use optimal probe even if an indirect jump is found.
For more informations, you can visit the following documentation files:
- Source of indirect jump.
- Description of the algorithm.
- Limitations of the algorithm.
- Possible improvements to the algorithm.
The library requires a compiler that supports C++20. With minimal work, it should be possible to downgrade this requirement to C++17 or even C++14 if needed.
The project is built with the Meson build system.
The following libraries are required:
To build the library, create a build directory. The project
is then configure using meson
and built with ninja
.
$ mkdir build && cd build
$ meson ..
$ ninja
After configuration, tests can be executed using the following command.
$ ninja check
This project can be easily included in another Meson project. You can read more about Meson subprojects here.
The easiest way is to create a
Wrap file
named libresolver.wrap
in your subprojects/
directory
containing the following.
[wrap-git]
url = https://github.com/gpollo/libresolver.git
revision = head
The subproject can then be imported in your meson.build
file using the following declarations.
libresolver_project = subproject('libresolver')
libresolver_dep = libresolver_project.get_variable('libresolver_dep')
Finally, it can be linked with your executable or library using declarations similar to the following.
my_executable = executable(
…,
dependencies: […, libresolver_dep, …],
…,
)