# Development information This file aims to introduce developers to conventions for working on the code base of radare2. The GitHub issues page contains a list of all the bugs that have been reported, with labels to classify them by difficulty, type, milestone, etc. It is a good place to start if you are looking to contribute. For information about the git process, see [CONTRIBUTING.md](CONTRIBUTING.md#How_to_contribute). ## Documentation Functions should have descriptive names and parameters. It should be clear what the function and its arguments do from the declaration. Comments should be used to explain purpose or clarify something that may not be immediately apparent or relatively complicated. ```c /* Find the min and max addresses in an RList of maps. Returns (max-min)/width. */ static int findMinMax(RList *maps, ut64 *min, ut64 *max, int skip, int width); ``` ## Error diagnosis There are several utilities that can be used to diagnose errors in r2, whether they are related to memory (segfaults, uninitialized read, etc.) or problems with features. ### Compilation options * `sys/sanitize.sh`: Compile with ASan, the address sanitizer. Provides detailed backtraces for memory errors. * `R2_DEBUG_ASSERT=1`: Provides a backtrace when a debug assert (typically a `r_return_` macro) fails. * `R2_DEBUG=1`: Show error messages and crash signal. Used for debugging plugin loading issues. ### Useful macros from [r\_types.h](libr/include/r_types.h) * `EPRINT_*`: Allows you to quickly add or remove a debug print without worrying about format specifiers. #### Parameter marking r2 provides several empty macros to make function signatures more informative. * `R_OUT`: Parameter is output - written to instead of read. * `R_INOUT`: Parameter is read/write. * `R_OWN`: Pointer ownership is transferred from the caller. * `R_BORROW`: The caller retains ownership of the pointer - the reciever must not free it. * `R_NONNULL`: Pointer must not be null. * `R_NULLABLE`: Pointer may ne null. * `R_DEPRECATE`: Do not use in new code and will be removed in the future. * `R_IFNULL(x)`: Default value for a pointer when null. * `R_UNUSED`: Not used. ## Code style ### C In order to contribute patches or plugins, we encourage you to use the same coding style as the rest of the code base. * Please use `./sys/clang-format-diff.py` before submitting a PR to be sure you are following the coding style, as described in [CONTRIBUTING.md](CONTRIBUTING.md#Getting Started). If you find a bug in this script, please submit a bug report issue. A detailed style guide can be found below. * See `sys/indent.sh` for indenting your code automatically. * A pre-commit hook to check coding style is located at `sys/pre-commit-indent.sh`. You can install it by copying it to `.git/hooks/pre-commit`. To preserve your existing pre-commit hook, use `cat sys/pre-commit-indent.sh >> .git/hooks/pre-commit` instead. * For a premade `.vimrc`, see `doc/vim`. * See `.clang-format` for work-in-progress support for automated indentation. #### Guidelines The following guidelines apply to code that we must maintain. Generally, they will not apply to copy-paste external code that will not be touched. * Tabs are used for indentation. In a switch statement, the cases are indented at the switch level. * Switch-cases where local variables are needed should be refactored into separate functions instead of using braces. If braced scope syntax is used, put `break;` statements inside the scope. ```c switch (n) { case 1: break; case 2: { break; } default: } ``` * Lines should be at most 140 characters in length. Considering tabs are 8 characters long. Originally this limit was 78, and it's still considered as a good practice, try to keep your functions short and readable, with minimum number of function arguments and not much nesting. * Braces open on the same line as the for/while/if/else/function/etc. Closing braces are put on a line of their own, except in the else of an if statement or in the while of a do-while statement. ```c if (a == b) { ... } if (a == b) { ... } else if (a > b) { ... } if (a == b) { ... } else { do_something_else (); } do { do_something (); } while (cond); if (a == b) { b = 3; } ``` * Always use braces for if and while. ```diff -if (a == b) - return; +if (a == b) { + return; +} ``` * In general, avoid `goto`. The `goto` statement only comes in handy when a function exits from multiple locations and some common work such as cleanup has to be done. If there is no cleanup needed, then just return directly. Choose label names which say what the `goto` does or why it exists. An example of a good name could be `out_buffer:` if the `goto` frees `buffer`. Avoid using GW-BASIC names like `err1:` and `err2:`. * Use `r_return_*` macros to check for conditions that are caused by programming errors or bugs; i.e.: conditions that should **never** happen. Do not use them when checking for runtime error conditions, such as a `NULL` value being returned from `malloc()`. Use a standard if statement for these cases. ```c int check(RCore *c, int a, int b) { /* check for programming errors */ r_return_val_if_fail (c, false); r_return_val_if_fail (a >= 0, b >= 1, false); /* check for runtime errors */ ut8 *buf = calloc (b, sizeof (a)); if (!buf) { return -1; } /* continue... */ } ``` * Use spaces after keywords and around operators. ```c a = b + 3; a = (b << 3) * 5; a = sizeof (b) * 4; ``` * Multiline ternary operator conditionals are indented in JavaScript style: ```diff -ret = over ? - r_debug_step_over (dbg, 1) : - r_debug_step (dbg, 1); +ret = over + ? r_debug_step_over (dbg, 1) + : r_debug_step (dbg, 1); ``` * When breaking up a long line, use a single additional tab if the current and next lines are aligned. Do not align start of line using spaces. ```diff -x = function_with_long_signature_and_many_args (arg1, arg2, arg3, arg4, arg5, - arg6, arg7, arg8); -y = z; +x = function_with_long_signature_and_many_args (arg1, arg2, arg3, arg4, arg5, + arg6, arg7, arg8); +y = z; ``` * Use two additional tabs if the next line is indented to avoid confusion with control flow. ```diff if (function_with_long_signature_and_many_args (arg1, arg2, arg3, arg4, arg5, - arg6, arg7, arg8)) { + arg6, arg7, arg8)) { do_stuff (); } ``` * When following the above guideline, if additional indentation is needed on consecutive lines, use a single tab for each nested level. Avoid heavy nesting in this manner. ```diff if (condition_1 && condition_2 && condition_3 && (condition_4 - || condition_5)) { + || condition_5)) { do_stuff (); } ``` * Split long conditional expressions into small `static inline` functions to make them more readable. ```diff +static inline bool inRange(RBreakpointItem *b, ut64 addr) { + return (addr >= b->addr && addr < (b->addr + b->size)); +} + +static inline bool matchProt(RBreakpointItem *b, int rwx) { + return (!rwx || (rwx && b->rwx)); +} + R_API RBreakpointItem *r_bp_get_in(RBreakpoint *bp, ut64 addr, int rwx) { RBreakpointItem *b; RListIter *iter; r_list_foreach (bp->bps, iter, b) { - if (addr >= b->addr && addr < (b->addr+b->size) && \ - (!rwx || rwx&b->rwx)) { + if (inRange (b, addr) && matchProt (b, rwx)) { return b; } } return NULL; } ``` * Use `R_API` to mark exportable (public) methods for module APIs. * Use `R_IPI` to mark functions internal to a library. * Other functions should be `static` to avoid polluting the global namespace. * The structure of C files in r2 should be as follows: ```c /* Copyright ... */ // copyright #include // includes static int globals // const, define, global variables static void helper(void) {} // static functions R_IPI void internal(void) {} // internal apis (used only inside the library) R_API void public(void) {} // public apis starting with constructor/destructor ``` * Why do we return `int` instead of `enum`? The reason why many r2 functions return int instead of an enum type is because enums can't be OR'ed; additionally, it breaks the usage within a switch statement and swig can't handle it. ``` r_core_wrap.cxx:28612:60: error: assigning to 'RRegisterType' from incompatible type 'long' arg2 = static_cast< long >(val2); if (arg1) (arg1)->type = arg2; resultobj = SWIG_Py_Void(); return resultobj; fail: ^ ~~~~ r_core_wrap.cxx:32103:61: error: assigning to 'RDebugReasonType' from incompatible type 'int' arg2 = static_cast< int >(val2); if (arg1) (arg1)->type = arg2; resultobj = SWIG_Py_Void(); return resultobj; fail: ^ ~~~~ ``` * Do not leave trailing whitespaces at end-of-line. * Do not use ``. Use `"r_util/r_assert.h"` instead. * You can use `export R2_DEBUG_ASSERT=1` to set a breakpoint when hitting an assert. * Declare variables at the beginning of code blocks - use C89 declaration instead of C99. In other words, do not mix declarations and code. This helps reduce the number of local variables per function and makes it easier to find which variables are used where. * Always put a space before an opening parenthesis (function calls, conditionals, for loops, etc.) except when defining a function signature. This is useful for searching the code base with `grep`. ```c -if(a == b){ +if (a == b) { ``` ```c -static int check(RCore *core, int a); +static int check (RCore *core, int a); ``` * Where is `function_name()` defined? ```sh grep -R 'function_name(' libr ``` * Where is `function_name()` used? ```sh grep -R 'function_name (' libr ``` * Function names should be explicit enough to not require a comment explaining what it does when seen elsewhere in code. * **Do not use global variables**. The only acceptable time to use them is for singletons and WIP code. Make a comment explaining why it is needed. * Commenting out code should be avoided because it reduces readability. If you *really* need to comment out code, use `#if 0` and `#endif`. * Avoid very long functions; split it into multiple sub-functions or simplify your approach. * Use types from `` instead of the ones in ``, which are known to cause some portability issues. Replace `uint8_t` with `ut8`, etc. * Never use `%lld` or `%llx`, which are not portable. Use the `PFMT64` macros from ``. ### Shell scripts * Use `#!/bin/sh`. * Do not use BASH-only features; `[[`, `$'...'`, etc. * Use `sys/shellcheck.sh` to check for problems and BASH-only features. ## Managing endianness Endianness is a common stumbling block when processing buffers or streams and storing intermediate values as integers larger than one byte. ### Problem The following code may seem intuitively correct: ```c ut8 opcode[4] = {0x10, 0x20, 0x30, 0x40}; ut32 value = *(ut32*)opcode; ``` However, when `opcode` is cast to `ut32`, the compiler interprets the memory layout based on the host CPU's endianness. On little-endian architectures such as x86, the least-signficiant byte comes first, so `value` contains `0x40302010`. On a big-endian architecture, the most-significant byte comes first, so `value` contains `0x10203040`. This implementation-defined behavior is inherently unstable and should be avoided. ### Solution To avoid dependency on endianness, use bit-shifting and bitwise OR instructions. Instead of casting streams of bytes to larger width integers, do the following for little endian: ```c ut8 opcode[4] = {0x10, 0x20, 0x30, 0x40}; ut32 value = opcode[0] | opcode[1] << 8 | opcode[2] << 16 | opcode[3] << 24; ``` And do the following for big endian: ```c ut32 value = opcode[3] | opcode[2] << 8 | opcode[1] << 16 | opcode[0] << 24; ``` This behavior is not dependent on architecture, and will act consistently between any standard compilers regardless of host endianness. ### Endian helper functions The above is not very easy to read. Within radare2, use endianness helper functions to interpret byte streams in a given endianness. ```c val32 = r_read_be32(buffer) // reads 4 bytes from a stream in BE val32 = r_read_le32(buffer) // reads 4 bytes from a stream in LE val32 = r_read_ble32(buffer, isbig) // reads 4 bytes from a stream: // if isbig is true, reads in BE // otherwise reads in LE ``` Such helper functions exist for 64, 32, 16, and 8 bit reads and writes. * Note that 8 bit reads are equivalent to casting a single byte of the buffer to a `ut8` value, i.e.: endian is irrelevant. ## Editor configuration Vim/Neovim: ```vim setl cindent setl tabstop=8 setl noexpandtab setl cino=:0,+0,(2,J0,{1,}0,>8,)1,m1 ``` Emacs: ```elisp (c-add-style "radare2" '((c-basic-offset . 8) (tab-width . 8) (indent-tabs-mode . t) ;;;; You would need (put 'c-auto-align-backslashes 'safe-local-variable 'booleanp) to enable this ;; (c-auto-align-backslashes . nil) (c-offsets-alist (arglist-intro . ++) (arglist-cont . ++) (arglist-cont-nonempty . ++) (statement-cont . ++) ))) ``` You may use directory-local variables by adding the following to `.dir-locals.el`. ```elisp ((c-mode . ((c-file-style . "radare2")))) ``` ## Packed structures Due to standards differing between compilers, radare2 provides a portable helper macro for packed structures: `R_PACKED()`, which will automatically utilize the correct compiler-dependent macro. Do not use `#pragma pack` or `__attribute__((packed))`. Place the packed structure inside `R_PACKED()` like so: ```c R_PACKED (struct mystruct { int a; char b; }); ``` If you are using `typedef`, do not encapsulate the type name. ```c R_PACKED (typedef struct mystruct_t { int a; char b; }) mystruct; ``` ## Modules radare2 is split into modular libraries in the `libr/` directory. The `binr/` directory contains programs which use these libraries. The libraries can be built individually, PIC or non-PIC. You can also create a single static library archive (`.a`) which you can link your own programs against to use radare2's libraries without depending on an existing system installation. See [doc/static.md](doc/static.md) for more info. [This presentation](http://radare.org/get/lacon-radare-2009/) gives a good overview of the libraries. ## API The external API is maintained in a different repository. The API function definitions in C header files are derived from and documented in the `radare2-bindings` repository, found [here](https://github.com/radareorg/radare2-bindings). Currently, the process of updating the header files from changed API bindings requires human intervention, to ensure that proper review occurs. Incorrect definitions in the C header files will trigger a build failure in the bindings repository. If you are able to write a plugin for various IDE that can associate the bindings with the header files, such a contribution would be very welcome. ## Dependencies and installation radare2 does not require external dependencies. On \*nix-like systems, it requires only a standard C compiler and GNU `make`. For compiling on Windows, see [doc/windows.md](doc/windows.md). Browse the [doc/](doc/) folder for other architectures. For cross-compilation, see [doc/cross-compile.md](doc/cross-compile.md). ## Recompiling and Outdated Dependencies When recompiling code, ensure that you recompile all dependent modules (or simply recompile the entire project). If a module's dependency is not recompiled and relinked, it may cause segmentation faults due to outdated structures and libraries. Such errors are not handles automatically, so if you are not sure, recompile all modules. To speed up frequent recompilation, you can use `ccache` like so: ```sh export CC="ccache gcc" ``` This will automatically detect when files do not need to recompiled and avoid unnecessary work. ## Repeated installation There is an alternative installation method for radare2 to make it easier to repeatedly install while making changes. The `symstall` target creates a single system-wide installation using symlinks instead of copies, making repeated builds faster. ```sh sudo make symstall ``` ## Source repository The source for radare2 can be found in the following GitHub repository: ```sh git clone https://github.com/radareorg/radare2 ``` Other packages radare2 depends on, such as Capstone, are pulled from their git repository as required. To get an up-to-date copy of the repository, you should perform the following while on the `master` branch: ```sh git pull ``` If your local git repository is not tracking upstream, you may need to use the following: ```sh git pull https://github.com:radareorg/radare2 master ``` The installation scripts `sys/user.sh`, `sys/install.sh`, `sys/meson.py`, and `sys/termux.sh` will automatically identify and update using an existing upstream remote, if one exists. If not, it will pull using a direct URL. If you have modified files on the `master` branch, you may encounter conflicts that must be resolved manually. To save your changes, work on a different branch as described in [CONTRIBUTING.md](CONTRIBUTING.md). If you wish to discard your current work, use the following commands: ```sh git clean -xdf git reset --hard ``` ## Regression testing Use `r2r` to run the radare2 regression test suite, e.g.: ```sh sys/install.sh r2r ``` r2r's source can be found in the `test/` directory, while binaries used for tests are located in the following GitHub repository: ```sh git clone https://github.com/radareorg/radare2-testbins ``` These can be found in `test/bins/` after being downloaded by r2r. For more information, see [r2r's README](https://github.com/radareorg/radare2-testbins/blob/master/README). The test files can be found in `test/db/`. Each test consists of a unique name, an input file, a list of input commands, and the expected output. The test must be terminated with a line consisting only of `RUN`. Testing can always be improved. If you can contribute additional tests or fix existing tests, it is greatly appreciated. ## Reporting bugs If you encounter a broken feature, issue, error, problem, or it is unclear how to do something that should be covered by radare2's functionality, report an issue on the GitHub repository [here](https://github.com/radareorg/radare2/issues). If you are looking for feedback, check out the [Community section in the README](README.md#Community) for places where you can contact other r2 devs. # HOW TO RELEASE - Set `RELEASE=1` in global.mk and r2-bindings/config.mk.acr. - Use `bsdtar` from libarchive package. GNU tar is broken. RADARE2 --- - bump revision - `./configure` - `make dist` R2-BINDINGS --- - `./configure --enable-devel` - `make` - `make dist` - Update the [paths on the website](https://github.com/radareorg/radareorg/blob/master/source/download_paths.rst) # Additional resources * [CONTRIBUTING.md](CONTRIBUTING.md) * [README.md](README.md) * [USAGE.md](USAGE.md)