Triskel is a Control Flow Graph (CFG) layout engine. It provides you with coordinates to draw CFGs in your reverse-engineering tools.
- CFG specific layout, emphasizing Single Entry Single Exit Regions
- Python bindings
- Export to PNG / SVG (with cairo)
- DearImgui integration
- LLVM integration
$ pip install pytriskel
from pytriskel.pytriskel import *
builder = make_layout_builder()
# Build the graph
n1 = builder.make_node("Hello")
n2 = builder.make_node("World")
builder.make_edge(n1, n2)
# Measure node size using font size
png_renderer = make_png_renderer()
builder.measure_nodes(png_renderer)
# Export an image
layout = builder.build()
layout.save(png_renderer, "out.png")
#include <triskel/triskel.hpp>
int main(void) {
auto builder = triskel::make_layout_builder();
auto n1 = builder->make_node("Hello");
auto n2 = builder->make_node("World");
builder->make_edge(n1, n2)
auto renderer = triskel::make_svg_renderer();
builder->measure_nodes(renderer)
auto layout = builder->build();
layout->render_and_save(*renderer, "./out.svg");
return 1;
}
Triskel is the implementation for the paper Towards better CFG layouts.
The key idea behind Triskel is to split the CFG into Single Entry Single Exit regions. We are then able to layout each region taking advantage of a divide and conquer approach.
Initially we have a directed graph
The first step involves identifying Single Entry Single Exit (SESE) regions. (See the implementation here: sese.cpp) In the diagram, the region is in blue. Notice how a single edge enters and exits the blue border.
We can then split each region out of the graph. At this step we have multiple smaller directed graphs. Note that how in the graph of the SESE region, we had to add 2 virtual nodes to represent the entry and exit points. In the other graph, we added an additional node to represent the region (still in blue).
The next step involves laying out each SESE region's graph using Sugiyama algorithm (See the implementation here: sugiyama.cpp). Note how we have to layout the SESE region first in order to know the coordinates of the blue node.
Finally, we can superimpose the layouts to obtain the final layout.
Triskel relies on the following dependencies (the provided binaries also have their own dependencies)
Triskel can then be compiled with cmake
$ git clone https://github.com/triskeles/triskel
$ cd triskel
$ cmake -B build
$ cmake --build build
You can then link to Triskel
target_link_libraries(foo PRIVATE triskel)
To compile with all options and external dependencies check the dockerfile.
Adds LLVM integration.
This also adds LLVM 19
as a dependency.
Adds ImGui integration, used for making GUIs.
This adds the following dependencies:
imgui
(To use compile imgui with CMake you can use the code indocker/fedora/dependencies.sh
)glfw3
OpenGL
GLEW
SDL2
stb_image
Adds Cairo integration, used for exporting images.
Triskel comes with many example binaries to help illustrate usage.
These binaries all require an additional dependency:
Used for testing and evaluation.
This binary lays out each function in an LLVM module and outputs a CSV containing performance reviews.
It can also be used on a single function to analyze the lay out with perf
.
This binary only requires triskel
built with ENABLE_LLVM=ON
.
An example implementation of a GUI using Dear ImGui.
This application has a very limited disassembler for x64 binaries.
This binary requires triskel
built with ENABLE_LLVM=ON
and ENABLE_IMGUI=ON
.
It also needs LIEF and Capstone for the disassembler.
A binary that generates images for CFGs using cairo.
This binary requires triskel
built with ENABLE_LLVM=ON
and ENABLE_CAIRO=ON
.
It also requires capstone
and LIEF
You can download the python bindings using pip:
$ pip install pytriskel
- Discord: Triskel
@inproceedings{royer:hal-04996939,
AUTHOR = {Royer, Jack and Tronel, Fr{\'e}d{\'e}ric and Vin{\c c}ont, Ya{\"e}lle},
TITLE = {{Towards Better CFG Layouts}},
BOOKTITLE = {{Workshop on Binary Analysis Research 2025}},
ADDRESS = {San Diego (CA), United States},
MONTH = Feb,
YEAR = {2025},
URL = {https://hal.science/hal-04996939},
DOI = {10.14722/bar.2025.23011},
}