# Developer's Guide for Debugging Radare2 This document explains common development practices used to debug radare2 in order to find, identify and fix bugs, memory corruptions, leaks or race conditions. ## Compilation When changing your code you need to rebuild r2 to test it. In case you use ACR/Make you just need to type `make` in the directory where you changed the code. But if you use `meson` you must run `ninja -C ../../b` instead. Bear in mind that meson tracks source dependencies more deeply than acr/make, so it's possible that for some changes in `.h` files `meson` builds will require a full recompilation, while `make` could just be faster and handier. The reason why source build changes are available system wide is because the default installation method `./sys/install.sh` uses `sudo make symstall` which creates symlinks instead of copying the executables, libraries and support files to $PREFIX. Other important `CFLAGS` are: * `-Wall` - show more warnings useful to improve code quality * `-Wshadow` - show if you have variables with the same name in nested scopes * `-w` - in case `-Werror` is set, stop treating warnings as errors ## Multiple r2 In order to develop for r2 it is common to have two or more builds of radare2, so you can compare `master` behaviour with your patched code at any time. You can achieve this in different ways, but bear in mind that using `--with-rpath` for meson or acr builds is important to avoid having one r2 using the other r2's libraries. * Use ACR source build for your patched code * Keep a --with-rpath meson build in a custom directory for running it * Statically build r2 (`sys/static.sh`) * Use `r2env` to switch between release or git builds ## Symbols By default radare2 is compiled with debug symbols, but in case the source-line information is not available you may want to set the `CFLAGS=-g` before calling `./configure` or `meson b`. ## ASAN Stands for Address Sanitizer and it's a compiler plugin available for clang, gcc and msvc that adds extra checks in the generated binary, which permits to identify many types of bugs. * undefined: behaviour (binary operations on signed variable) * memory: uninitialized variables (compiler warnings may catch that too) * thread: sanitizer - detect race conditions and deadlocks * address: memory corruption, read and write overflows * leak: track memory usage and detect memory leaks In case you are coming from another branch or another non-sanitized build you may want to have a clean build dir. To do this, reset your git state into a clean state. ``` $ make mrproper $ git clean -xdf $ rm -rf shlr/capstone ``` Works like valgrind, but faster. Use `sys/sanitize.sh` to get that build ready to use. ``` $ export SANITIZE=$leak memory address" $ sys/sanitize.sh ``` Now you can just run `r2` and get a nice crash report without the need of a debugger. But it is also compatible with any debugger like `gdb` or `lldb`. ## Valgrind It's a Linux tool that pseudo-emulates programs in order to detect runtime memory corruption problems and other types (like the ones listed above). Valgrind was working on macOS and other BSDs, but it lacks for that porting. So we may want to use it only when we are on Linux and we dont want to modify the binary we want to execute. There are different *plugins* that can be used for different purposes: ### Memory Profiling By default *valgrind* will identify `undefined behaviour`, `memory corruptions`, `race conditions` and more. Just call it like this: ``` $ valgrind r2 /bin/ls ``` ### Time Profiling Identifying bottlenecks is an important thing to do when looking for optimizations. This can be achieved with `callgrind` which is a plugin for tracing function calls and profile the time spent on them, specifying how many times are called. ``` $ valgrind --tool=callgrind --dump-instr=yes --simulate-cache=yes --collect-jumps=yes \ /usr/local/bin/r2 /bin/ls ``` To visualize the generated logs use `kcachegrind` ``` kcachegrind callgrind.* ``` ## GPerfTools This package can be used on macOS or Linux systems and uses *tcmalloc* to track heap allocations and create a graph with the memory allocated by each function during the execution. ``` $ brew ls gperftools $ DYLD_INSERT_LIBRARIES=/opt/homebrew/Cellar/gperftools/2.9.1_1/lib/libtcmalloc.4.dylib \ HEAPPROFILE=/tmp/b.txt \ r2 /bin/ls $ pprof --web /usr/local/bin/radare2 /tmp/b.txt* ``` ## Frida-Trace One of the tools shipped with `frida` is `frida-trace`, and allows us to trace function calls easily, and visualize their arguments, what they return and its backtraec. ``` $ frida-trace -i 'r_core_cmd*' r2 /bin/ls ``` ## Debuggers You can also debug r2 using `gdb`, `lldb`, `x64dbg` or any other debugger you like. Launching lldb and r2 in the same terminal it's usually handy, unless you are going to debug a bug in visual or panels mode, because the terminal configuration may be different. In those cases you may want to attach to the process by calling it with `lldb -p ` ## PD Read the `DEVELOPERS.md` document for more development and debugging tips! --pancake