1. Project Overview & Quickstart (rizinorg/cutter)
File: README.md
Cutter
Cutter is a free and open-source reverse engineering platform powered by rizin. It aims at being an advanced and customizable reverse engineering platform while keeping the user experience in mind. Cutter is created by reverse engineers for reverse engineers.
Learn more at [cutter.re](https://cutter.re).
Getting Cutter
Download
Cutter release binaries for all major platforms (Linux, macOS, Windows) can be downloaded from GitHub Releases.
Linux: If your distribution provides it, check for
cutterpackage in your package manager (orcutter-re/rz-cutter). If not available there, we have setup repositories in OBS for some common distributions. Look at https://software.opensuse.org/package/cutter-re and follow the instructions there. Otherwise download the.AppImagefile from our release, make it executable and run as below or use AppImageLauncher.chmod +x Cutter*.AppImage; ./Cutter*.AppImagemacOS: Download the
.dmgfile or use Homebrew Cask:brew install --cask cutterWindows: Download the
.ziparchive, or use either Chocolatey or Scoop:choco install cutterscoop bucket add extrasfollowed byscoop install cutter
Build from sources
To build Cutter from sources, please check the Building Docs.
Docker image
To deploy cutter using a pre-built Dockerfile, it's possible to use the provided configuration. The corresponding README.md file also contains instructions on how to get started using the docker image with minimal effort.
Documentation
[User Guide](https://cutter.re/docs/user-docs.html)
[Contribution Guidelines](https://cutter.re/docs/contributing.html)
[Developers Docs](https://cutter.re/docs/contributing/code.html)
Plugins
Cutter supports both Python and Native C++ plugins.
Our community has built many plugins and useful scripts for Cutter such as the native integration of Ghidra decompiler or the plugin to visualize DynamoRIO code coverage. You can find a list of cutter plugins linked below. Feel free to extend it with your own plugins and scripts for Cutter.
Getting Help
Please use the following channels to ask for help from Cutter developers and community:
- Telegram: https://t.me/cutter_re
- Mattermost: https://im.rizin.re
- IRC: #cutter on https://web.libera.chat/
- Twitter: @cutter_re
File: docker/README.md
Docker Configuration for Cutter
These files provide an easy way to deploy Cutter in a Docker container. After additional configuration you may want to apply to the Makefile, execute make run. By default, the Cutter image on Docker Hub will be used along with additional UID, capability, X and mount settings:
- Xauthority settings which avoid using potentially insecure
xhostdirectives. The settings have been adapted from this post. - Mount directives to mount a shared folder and rizin configuration files.
- The UID and GID of the user executing
make runwill also be used for the internal container user to avoid permission problems when sharing files.
Mounting and Using a Specific Binary
The Makefile allows mounting a single binary file as read-only, which will also be used as an input for Cutter. To use this feature, execute make run BINARY=/absolute/path/to/binary.
Additional Notes
- The internal container user doesn't use superuser privileges and is called
cutter. - To check for more options of the
Makefile, executemake.
File: docs/source/contributing/code/development-guidelines.rst
Cutter Development Guidelines
.. note::
New to Cutter development? Check out our :doc:tutorial for new developers <getting-started>.
Common Usage
CutterCore Class
This is the main class where every link with Rizin is made. It is *unique*
across the whole process. To access it, simply call ``Core()``.
Example:
.. code:: cpp
Core()->getOffset();
Seek the Current FileTo modify Rizin seek use CutterCore::seek(const RVA offset). This
is important because it will emit aCutterCore::seekChanged(RVA offset) signal. Never ever callcmd("s offset");
Example:
.. code:: cpp
Core()->seek(0x00C0FFEE);
.. note::
Cutter also supports a silent seek which doesn't trigger the seekChanged event and doesn't add new entries to the seek history.
Creating a Widget
Make sure to connect the ``CutterCore::seekChanged(RVA offset)`` signal
so your widget refreshes its output when Rizin seek is modified
(switching to another function, etc.).
Coding Style
------------
clang-format
~~~~~~~~~~~~
In general, we follow a slightly customized version of `the official Qt guidelines <https://wiki.qt.io/Qt_Coding_Style>`__
to format the code. Before sending a pull request, you will need to use `clang-format <https://clang.llvm.org/docs/ClangFormat.html>`__ (version 8 or newer)
to format the code. The command line for formatting the code according
to the style is:
.. code:: bash
clang-format -style=file -i src/filename.cpp
If your changes were done on many files across the codebase, you can use this oneliner to run ``clang-format`` on the entire ``src`` directory:
.. code:: bash
find ./src -regex '.*\.\(cpp\|h\)' -exec clang-format -style=file -i {} \;
clang-tidy
~~~~~~~~~~
Beyond formatting, we use `clang-tidy <https://clang.llvm.org/extra/clang-tidy/>`__ (version 13 or newer) to catch potential style violations.
To run ``clang-tidy``, first configure your build to generate ``compile_commands.json`` and run the autogen tools:
.. code:: bash
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCUTTER_QT=6 -DCUTTER_USE_BUNDLED_RIZIN=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
cmake --build build --target Cutter_autogen
Run ``clang-tidy`` on modified files relative to the latest commit
.. code:: bash
git diff -U0 --no-color HEAD~1 | clang-tidy-diff.py -p1 -path build/
Similar to ``clang-format``, If your changes were done on many files across the codebase, you can use this oneliner to run ``clang-tidy`` on the entire 'src' directory. The following command excludes third-party and auto generated files:
.. code:: bash
run-clang-tidy -p build ".*src/(?!(themes|bindings|fonts|img|translations|Cutter_autogen)).*\.(cpp|h)$"
``clang-tidy`` can also attempt to fix style violations using the ``-fix`` flag. However these may not always be perfect. Make sure to verify the fixes before opening a pull request:
.. code:: bash
git diff -U0 --no-color HEAD~1 | clang-tidy-diff.py -fix -p1 -path build/
Python scripts
~~~~~~~~~~~~~~
If you don't want to run manual commands, cutter also provides scripts for running ``clang-format`` and ``clang-tidy`` in the ``scripts`` directory
.. code:: bash
python scripts/clang-format.py -h
usage: clang-format.py [-h] [-C CLANG_FORMAT] [-c] [-v] [-f FILE] [-d DIFF]
Clang format the cutter project
options:
-h, --help show this help message and exit
-C, --clang-format CLANG_FORMAT
path of clang-format
-c, --check enable the check mode
-v, --verbose use verbose output
-f, --file FILE formats (or checks) only the given file
-d, --diff DIFF format all modified file related to branch
.. code:: bash
usage: clang-tidy.py [-h] [-T RUN_CLANG_TIDY] [-p BUILD_PATH] [-j JOBS] [-r REGEX] [-i] [-q]
clang-tidy regex wrapper
options:
-h, --help show this help message and exit
-T, --run-clang-tidy RUN_CLANG_TIDY
Path of run-clang-tidy binary
-p, --build-path BUILD_PATH
Path to the build directory
-j, --jobs JOBS Number of parallel execution jobs
-r, --regex REGEX Regex pattern for filtering files
-i, --fix Apply fixes automatically
-q, --quiet Suppress configuration logs
Below are some of the low level coding conventions that we follow
Variables
~~~~~~~~~
Variable names start with a lowercase letter with each consecutive word starting with an uppercase letter. (**camelBack** case)
.. code:: cpp
int Height // Wrong
string name_of_widget // Wrong
int height; // Correct
string nameOfWidget // Correct
Avoid meaningless variable names
.. code:: cpp
int a, b; // Wrong
string c; // Wrong
int height, width; // Correct
string nameOfThis; // Correct
Object obj; // Also Correct
Only first letter of an acronym is uppercase
.. code:: cpp
CutterJsonWigdet cutterJSONWidget; // Wrong
CutterJsonWigdet cutterJsonWigdet; // Correct
Variable names don't use leading/trailing underscores, including prefixes like m\_
.. code:: cpp
class Example {
private:
int index_; // Wrong
int m_index; // Wrong
int index; // Correct
};
Global variables follow the same naming conventions
Anonymous NamespaceGlobal entities (variables, functions, structs...) private to a source file (internal linkage) are defined in an anonymous namespace
.. code:: cpp
namespace {
int globalCounter = 0;
bool doSomething() {
...
return true;
}};
Functions
Function names follow the same naming convention as `variables`_. (**camelBack** casing)
.. code:: cpp
void do_something() {} // Wrong
void DoSomething() {} // Wrong
void doSomething() {} // Correct
Unused parameters inside a function are omitted in the definition either by commenting out the parameter name or not writing the name at all.
Avoid using ``Q_UNUSED``
.. code:: cpp
// Bad
void doSomething(int one, int two) {
Q_UNUSED(one)
...
}
// Good
void doSomething(int /*one*/, int two) {
...
}
// Good
void doSomething(int, int two) {
...
}
Avoid the use of automatic name based connections. See `Connecting Qt Signals`_.
Classes
~~~~~~~~
First letter of each word is uppercased. (**CamelCase**)
.. code:: cpp
class memory_dock_widget; // Wrong
class memoryDockWidget; // Wrong
class MemoryDockWidget; // Correct
Only first letter of an acronym is uppercase
.. code:: cpp
class CutterJSONWidget // Wrong
class CutterJsonWidget // Correct
Member variables follow the same naming conventions defined in `variables`_ that means no leading/trailing underscores or m\_ prefixes
Casting
~~~~~~~
Avoid the use of C style casts, prefer C++ casts (``static_cast``, ``const_cast`` ...)
Use ``qobject_cast`` for ``QObjects``
Smart PointersPrefer the use of C++ smart pointers (unique_ptr, shared_ptr...)
.. code:: cpp
RegisterProfileDialog *ui; // Bad
std::unique_ptr ui; // GoodBraces
In contrast to the official guidelines of Qt, in Cutter we always use curly braces in conditional statements, even if the body of a conditional statement contains only one line.
.. code:: cpp
// Wrong
if (address.isEmpty())
return false;
// Correct
if (address.isEmpty()) {
return false;
}
// Wrong
for (int i = 0; i < 10; ++i)
qDebug("%i", i);
// Correct
for (int i = 0; i < 10; ++i) {
qDebug("%i", i);
}
Loops
~~~~~
We use the C++11 foreach loop style, which means any βforeachβ loop should
look like:
.. code:: cpp
// Good - If a copy of each element is required
for (auto import : importsArray) {
doSomething(import);
}
// Good - If copy is not required
for (auto &import : importsArray) {
doSomething(import);
}
// Good - If no modification is required
for (const auto &import : importsArray) {
doSomething(import);
}
auto
~~~~
Prefer the use of ``auto`` keyword when working with the following:
.. code:: cpp
// Iterators
auto it = myMap.find(key);
for (const auto &import : importsArray) { ... }
// Lambdas
auto multiply = [](int a, int b) -> int { return a * b; };
// Casting
auto myFloat = static_cast<float>(myInt);
// Initializing using new
auto *item = new QListWidgetItem(text);
nullptrPlease do not use 0 nor Q_NULLPTR, only use nullptr.
Example:
.. code:: cpp
std::unique_ptr<QObject> obj = nullptr;
// Note that this is just an example, unique_ptr constructor initializes the internal pointer to nullptr by defaultConnecting Qt Signals
Use one of the following methods for connecting signals to slots:
.. code:: cpp
// typically you will make connection in the constructor to a member of current class
connect(this->ui->button1, &QPushButton::clicked,
this, &MyObject::buttonClicked); // Good
// you can also connect directly other object slots
connect(checkbox, &QCheckBox::toggled, widget, &QWidget::setEnabled); // Good
// use lambda for passing extra arguments
connect(button1, &QPushButton::clicked, this, [this](){ foo(getBar()); }); // Good
This syntax performs compile-time type checks and allows the use of lambda
functions. Other approaches for connecting signals can silently break at runtime.
Don't use the older macro based syntax or automatic name based connections.
.. code:: cpp
// SIGNAL and SLOT macros
connect(sender, SIGNAL(clicked), this, SLOT(buttonClicked)); // BAD
// automatic name based connection
slot:
void on_actionNew_triggered(); // BAD
// 3 argument connect without receiver object
connect(sender, &SomeObject::signal, [this](){ this->foo(getBar()); }); // BAD
Includes
~~~~~~~~
Strive to include only **required** definitions inside header files.
This will avoid triggering additional unnecessary compilations.
If you only need to know that a class exists but don't need the prototype,
you can declare the class like this:
.. code:: cpp
class MyClassThatExists;
/** ... **/
private:
std::unqiue_ptr<MyClassThatExists> classInstance;
And then include the class header inside your .cpp so you can use that class.
If you need something in the source file (.cpp) that is not a class member,
then add the include in the source file.
The includes must be ordered from local to global. That is, first include
any local header file (with double quotes like `#include "common/Helpers.h"`.
Then, after an empty newline, include Qt definitions like
`#include <QShortcut>`.
Finally, include the standard C++ headers you need.
Includes must be sorted by alphabetical order.
This is automatically handled by running ``clang-format``
Docstrings
~~~~~~~~~~
Our API reference is generated using Doxygen, so when it comes to
function documentation, please use the following format:
.. code:: cpp
/**
* @brief Add new parameters to the accumulator
* @param params The parameters to add
* @return True if the parameters were added, false otherwise
*/
bool accumulate(RefreshDeferrerParams params) { ... };
Documenting every function is generally not required. Only document those functions whose purpose is not immediately understandable just by looking at the function name.
.. code:: cpp
// No need for docs
int getCount() const;
// Should provide docs
bool syncRemote();
It is preferred for classes to have documentation just above the definition, explaining their purpose.
.. code:: cpp
/**
* @brief A short description about SomeDialog
*/
class SomeDialog {
...
};
General Coding Advices
----------------------
Functions DocumentationYou can find the class documentation in the API Reference <https://cutter.re/docs/api.html>__ menu item.
Updating the Git Submodules
Git submodules play a major part in Cutter. This, because Cutter is powered
by Rizin, its parent project, and it tries to stay up-to-date with its
recent version, which allows us to implement new features, and enjoy bug
fixes and performance improvements on Rizin. Often, we need to update
the Rizin submodule or the others, to push their most recent
version to Cutter.
You can view the list of all the submodules from the cutter root folder with:
.. code:: sh
git config --file .gitmodules --get-regexp path | awk '{ print $2 }'
To update all the submodules at once, run these commands from the
cutter root folder:
.. code:: sh
git submodule foreach git pull origin master
git add submodule_name_1 submodule_name_2
git commit -m "Update submodules"
More likely, you'll only need to update the *rizin* submodule.
In order to update one submodule individually, use the following code:
.. code:: sh
cd rizin
git checkout dev && git pull
cd ..
git add rizin
git commit -m "Update rizin submodule"
Useful Resources (Qt Development)Signals & Slots <https://doc.qt.io/qt-6/signalsandslots.html>__Model/View Programming <https://doc.qt.io/qt-6/model-view-programming.html>__ - read this if you are going to work with a list or table-like widgetsQAction <https://doc.qt.io/qt-6/qaction.html#details>__
File: docs/source/contributing/code/getting-started.rst
Contributing code to Cutter
Thank you so much for your interest in contributing to Cutter! Contributors like you are a treasured resource for Cutter and their contributions have made the project what it is. And so, we appreciate everyone who gives the community the gift of their time <3.
The following section in our documentation is not intended to be comprehensive but rather a quick guide to walk you through the basic flow of contributing to Cutter. For more thorough documentation, follow the links on this page and read our Development Guidelines.
Clone and compile Cutter
The first step before starting to add code to Cutter is to build it on your environment. Whether it is Linux, Windows, or macOS, we have you covered and detailed the instructions to compile Cutter on our :doc:/building. Once you are done and Cutter is built successfully, test that it works correctly and continue to the next steps.
.. tip::
If you are facing issues with building Cutter on your environment, make sure you didn't miss anything in the documentation. Specifically, check the :ref:Building:Troubleshooting section.
.. tip::
If you need help configuring your development environment, make sure to read our :doc:instructions, recommendations and tips for setting up a Cutter development environment for popular IDEs.
Find something to work on
Some will reach this page with a clear idea of what issue they want to fix or what feature they wish to implement. But some would simply want to help Cutter getting better while doing open-source, without having a specific thing in mind. If you already have something in mind - great! Move forward to the next section. If you don't have anything specific, stick with us a little bit more.
The issues and the feature-requests of Cutter are listed and tracked on our Github Issues <https://github.com/rizinorg/cutter/issues>_ page. Don't get scared by the number of issues open, we will learn how to filter them to find those which fit you best.
.. tip::
Fix your pet peeve! Anything specific that annoys you about Cutter? Fantastic! This can be a great place to start.
Organizing issues
In order to organize the hundreds of Issues opened on Cutter, we use several features of Github for project management. Get yourself familiar with the following features, it will help you filter the issues.
Labels
^^^^^^
Tagging issues and pull requests with labels allows us to quickly search for them later. We use labels to describe the type of the issue, the feature it belongs to, the difficulty, and even its priority. We recommend you to start from issues labeled as good-first-issue <https://github.com/rizinorg/cutter/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22>_. These issues were tagged by us as suitable for new contributors.
Projects
^^^^^^^^
We use project boards <https://github.com/rizinorg/cutter/projects>_ to gather together tasks and issues for specific features or problems. For example, we have dedicated project boards for Debugger, Hexdump widget, Decompiler widget, and High DPI support. If you are interested to take part in developing a major feature, or you want to get a broader look at a progress of a specific part in Cutter, this can be a good place to visit.
Milestones
^^^^^^^^^^
When starting working on a new release, we gather together the bug and feature-requests that we consider of high-priority into a Milestone <https://github.com/rizinorg/cutter/milestones>_. If you want to work on a feature or fix a bug that is needed and prioritized for the next release, then check out the open Milestone,.
Assigning Issues
^^^^^^^^^^^^^^^^
Before choosing an issue to work on, make sure it is not assigned to anyone. If it is, you can comment and ask if this person is intended to work on the issue. Some assigned issues are abandoned by their assignee and can be picked up by other contributors.
Get familiar with the current situation
Run Cutter and get familiar with how the functionality you want to modify works currently. For example, if it is a dialog, make sure you understand its role and how our users are using it. If it is a bug, try to repeat it using the instructions from the bug report.
.. tip::
If you are inexperienced with binary analysis tasks, you can always ask other developers in the team about the feature and how it should be used. The team and the community will be happy to help and instruct you with everything you need to know.
Find the source files implementing the feature you want to work on. By doing this, practice searching code in your editor, this is an important skill. We suggest searching for files with the name of the feature. For example, if you are interested in improving the "Sections" widget, you can find the source code of this feature in SectionsWidget.cpp and SectionsWidget.h. Alternatively, you can try and look for specific unique strings that exist in the dialog, widget, or feature you want to improve. Usually, when searching the entire code base for these strings, you'll land on a file related to this feature, whether it is a .cpp file or a .ui file. From there it will be easy to navigate your way to the right place.
Work on your feature or bug-fix
If you are experienced with such tasks, go ahead - we leave this in your hands. Otherwise, we recommend you come up with a plan for things that need to be done to solve this bug or implement this feature. Discuss your plan in the relevant issue on GitHub.
.. important::
Before starting coding, make sure to get yourself familiar with our comprehensive documentation for our coding style, conventions, and guidelines <development-guidelines.html>_.
If you don't know how to implement something, check if any of the existing code implements similar behavior in the same widget or similar widgets. If you do copy an existing code consider why it did things the way it did, the same factors might not apply in your case or the old code was poorly written from the first place.
Open a Pull request
When you are done, and the additions and modifications to the code are in place, commit your changes, and get your code reviewed by opening a new Pull Request. Please remember to follow the Pull Request template.
In the Pull Request template you will be required to add a "Test plan". For example, if you performed GUI changes, demonstrate it by posting a screenshot. Make a list of steps to be taken by the reviewers to verify that the changes are working as expected. This is also a good point to consider any potential edge-cases or different kinds of inputs if you didn't already do it while writing the code. Perform the steps you described when making the PR even if they seem trivial and you did them during development, it helps to catch any mistakes done during the final cleanup and making sure you didn't forget anything.
Repeat
Thank you! You've made your very first contribution, and Cutter is better for it. But don't stop now. Go back to the first steps, as there is plenty more to do. A mentor or other developers might suggest a new issue for you to work on.
More Information
.. important::
We're always in the process of improving the information on this page for newcomers to the Cutter. Please help us by suggesting improvements and tell us about the information that this page lacks.
File: docs/source/contributing/code/ide-setup.rst
Development environment setup
This page contains recommendations and tips on how to better setup different IDEs for Cutter development.
General advice
Everyone has their own preferences for their favorite IDE or code editor.
There are no strict requirements for using a specific one for Cutter development.
Any IDE with good CMake integration should work well.
For most development builds, unless you are working on packaging issues, it is recommended to build Cutter with the bundled version of Rizin. It is the default configuration and the easiest way to ensure that a compatible Rizin version is used and helps you deal with different versions of Rizin when working with multiple Cutter branches. In case you want to build Cutter with a different version of Rizin installed on your system, you can set CUTTER_USE_BUNDLED_RIZIN=OFF. On Linux, in case you have multiple Rizin versions without CUTTER_USE_BUNDLED_RIZIN, the PKG_CONFIG_PATH environment variable can be used to select the desired Rizin installation.
While Qt Creator_ has a builtin visual form and widget editor, not having it in other IDEs is not a major problem. It is also available as a standalone tool called Qt Designer and you can configure the file associations so that .ui files are opened using it. Depending on the .ui file and changes you want to make, it is sometimes easier to perform them by editing the .ui file as a text file. Essentially, .ui files are XML files. Most code editors should have some support for XML highlighting and possibly block folding.
The following instructions and recommendations assume that you have already download Cutter source and obtained required dependencies as described in :doc:/building.
Linux
On a rolling-release distribution or a somewhat recent version of traditional distributions like Ubuntu 18.04, it should be possible to get all the dependencies from the official repository. There might be some problems with PySide2 and Shiboken2 but it can be easily disabled and isn't necessary for most work on Cutter. Don't try to install PySide using pip.
Windows
Assuming you have a sufficiently powerful computer, a nice way of getting and configuring Qt for Cutter is to use vcpkg <https://github.com/Microsoft/vcpkg>.
For a quick test, the exact versions of libraries used by Cutter release packages can be obtained from cutter-deps <https://github.com/rizinorg/cutter-deps/releases> but they don't contain debug
versions of libraries so they are not suitable for more serious Cutter development on Windows.
Qt Creator
QT Creator is an open-source IDE made by the same developers as Qt.
Pros and Cons
- builtin help for Qt API
- builtin .ui file editor (Qt Designer - visual form editor)
- builtin helper for displaying Qt types in the debugger
- Viewing source files that are not directly part of the project (Rizin source code) is somewhat inconvenient.
- The simplest way of installing on non-Linux operating systems require login with Qt account
Project setupThe following instructions were made based on version 4.12.4 of Qt Creator. The steps might slightly differ between the versions.
- Go to :menuselection:
File --> Open File or Project..and select :file:cutter/CMakeList.txt - Select kit and press :guilabel:
Configure Project
Formatting using clang-format
To configure ``clang-format`` for formatting a file you will need to use the built-in Beautifier plugin. `Follow the instructions <https://doc.qt.io/qtcreator/creator-beautifier.html>`_ on Qt Creator's website to enable the plugin and configure it to run ``clang-format`` when saving a file. In the clang-format options page choose "Use predefined style: File".
Changing CMake configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Click on the "Projects" button on the left side of the screen and then select "Build". All the project CMake options are listed and can be edited there in a graphical editor.
Editing Qt .ui files
~~~~~~~~~~~~~~~~~~~~
Double-clicking a ``.ui`` file in a file list opens it inside a visual editor. If you want to make changes that are easier to do by editing ``.ui`` file as text - right-click the file and select :menuselection:`Open With --> Plain Text Editor`. Switching from visual form editor back to code editor mode will open the ``.ui`` file in read-only mode with the following warning "This file can only be edited in Design mode". To edit use the same steps as described before.
VS Code
-------
`VS Code <https://github.com/Microsoft/vscode>`_ is an open-source code editor made by Microsoft.
Pros and Cons
~~~~~~~~~~~~~
- A large number of plugins
- A good fallback mechanism for files that are not directly part of a project.
Recommended plugins
~~~~~~~~~~~~~~~~~~~
- `C/C++ <https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools>`_ - The official C++ support plugin made by Microsoft
- `CMake Tools <https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools>`_ - Provides CMake project integration. Originally developed by vector-of-bool and currently maintained by Microsoft.
- `CMake <https://marketplace.visualstudio.com/items?itemName=twxs.cmake>`_ - CMake language support when editing CMake files. Does not replace the previous CMake plugin. They provide non-overlapping functionality and should be used together.
Project setup
~~~~~~~~~~~~~
- :menuselection:`File --> Open Folder...` and select the folder in which you cloned Cutter
- Install the recommended plugins.
- Once the `CMake Tools` plugin is installed, in the corner you will see a popup asking you "Would you like to configure project 'cutter'? Source: CMake Tools (Extension)". Click Yes.
- In the kit selection popup, choose :guilabel:`[Unspecified]` unless you have more specific needs.
- If you initially dismissed the configuration window or didn't have the plugins installed yet - open command-palette using :kbd:`Ctrl-Shift-P` and select :guilabel:`Cmake: Configure`
Changing CMake configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After the first configuration :kbd:`Ctrl-Shift-P`/:guilabel:`CMake: Edit CMake Cache` opens a text editor with all CMake options. Cutter specific ones mostly start with "CUTTER".
.. _vscode-debug-setup:
Formatting using clang-formatThe C/C++ extension we recommended earlier supports source code formatting using clang-format which is included with the extension. Use :kbd:Ctrl-Shift-I to format the document or :kbd:Ctrl-K Ctrl-F to only format the selection. We recommend to configure auto-formatting via the settings. Follow the instructions <https://code.visualstudio.com/docs/cpp/cpp-ide#_code-formatting>_ on VS Code's website.
Building, Running, Debugging
Build and running commands are available in the status bar at the bottom and in the Command Palette menu (:kbd:`Ctrl-Shift-P`) named ``CMake: Build F7``, ``CMake: Run Without Debugging Shift+F5``, and ``CMake Debug Ctrl + F5``.
Shortcuts can be viewed in the :kbd:`Ctrl-Shift-P` menu. They don't match default VS Code ones since those depend on :file:`tasks.json``.
Running and debugging launches the executable without any arguments. Command-line arguments can be passed to the debug
executable by creating a ``.vscode/launch.json`` configuration. Read the `documentation <https://code.visualstudio.com/docs/cpp/launch-json-reference>`_ for more information. Instead of creating :file:`launch.json` manually it can be created from template: :kbd:`Ctrl-Shift-P`/:menuselection:`Debug: Select and Start Debugging --> Add configuration.. --> C,C++: (gdb) Launch`.
To setup gdb pretty printers for Qt types on Linux, download the scripts from `Kdevelop <https://github.com/KDE/kdevelop/tree/master/plugins/gdb/printers>`_. In the :file:`~/.gdbinit` file add the following code:
.. code-block:: python
python
import sys
sys.path.insert(0, '/path/to/folder/with/pretty_printer_scripts')
from qt import register_qt_printers
register_qt_printers (None)
end
set print pretty 1
CLion
-----
`CLion <https://www.jetbrains.com/clion/>`_ is a C and C++ IDE from the popular software development tool maker - JetBrains.
Pros and Cons
~~~~~~~~~~~~~
- Medium amount of plugins, many first-party plugins made by JetBrains for their IntelliJ based IDE family
- There is no free version
- Takes some time to analyze the files after opening a project. Switching between .cpp and corresponding .h file may for the first time may take a few seconds.
Project setup
~~~~~~~~~~~~~
- Go to :menuselection:`File --> Open` and select the folder in which you cloned Cutter
- Open :file:`cutter/CMakeLists.txt` using the project file list on the left side of the screen
- A yellow bar with a message :guilabel:`CMake project is not loaded` should appear, click :guilabel:`Load CMake project`
Changing CMake configurationGo to :menuselection:File --> Settings --> Build,Execution,Deployment --> CMake. CMake options are specified the same way as on command-line -DOPTION_NAME=VALUE.
Formatting using clang-format
Clion provides you with an easy way to format files with ``clang-format``. Follow the `documentation <https://www.jetbrains.com/help/clion/clangformat-as-alternative-formatter.html>`_ on their website to learn how to enable formatting with ``clang-format``.
Building, Running, Debugging
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Follow the `Clion documentation <https://www.jetbrains.com/help/clion/qt-tutorial.html#debug-renderers>`_ for how to configure Qt type debugger renderers. If you are using the MSVC toolchain
it can use :file:`qt5.natvis`. In rest of the cases you can use ``.gdbinit`` or ``..ldbinit`` based approach similar to one described for :ref:`VSCode setup<vscode-debug-setup>`
Editing Qt .ui files
~~~~~~~~~~~~~~~~~~~~
Default CLion behavior for opening .ui files is `somewhat buggy <https://youtrack.jetbrains.com/issue/CPP-17197>`_. Double-clicking the file does nothing, but it can be opened by dragging it to the text editor side.
This can be somewhat improved by changing `file association <https://www.jetbrains.com/help/clion/creating-and-registering-file-types.html>`_. Open :menuselection:`File --> Settings --> Editor --> File Types` and change type association of \*.ui files from :guilabel:`Qt UI Designer Form` to either "XML" or :guilabel:`Files Opened in Associated Applications`.
The first one will open it within CLion as an XML file and the second will use the operating system configuration.
Visual Studio
-------------
Visual Studio Community edition is available for free and can be used for contributing to open source projects.
It is recommended to use the latest Visual Studio version 2019 because it has the best CMake integration.
Older VS versions can be used but CMake integration isn't as good. With those, it might be better to generate Visual Studio
project from CMake project using the command-line or :command:`cmake-gui` and opening the generated Visual Studio project instead of opening the
CMake project directly.
Visual Studio supports many different languages and use-cases. Full installation takes a lot of space. To keep the size minimal during installation
select only component called "Desktop development with C++". Don't worry too much about missing something.
Additional components can be later added or removed through the VS installer which also serves as an updater and package manager for Visual Studio components.
Pros and Cons
~~~~~~~~~~~~~
- good debugger
- medium amount of plugins
- completely closed source
- Windows only
Project setup
~~~~~~~~~~~~~
- Open folder in which you cloned Cutter source using Visual Studio
- Open CMake settings configurator using either :menuselection:`Project --> CMake Settings` or by clicking :guilabel:`Open the CMake Settings Editor` in the overview page.
- Check options that you want Cutter to be built with, or leave it as-is for the default options.
- If you are using vcpkg, Visual Studio should detect it automatically. The list of CMake options in the configurator should have some referring to vcpkg. If they are not there, specify the path to vcpkg toolchain file in the :guilabel:`CMake toolchain file` field.
- If you are not using vcpkg, configure the path to Qt as mentioned in :ref:`windows CMake instructions`. You can specify the CMake flag in :guilabel:`CMake command arguments:` field.
- To Ensure that VS debugger can display Qt types in a readable way, it is recommended to install `Qt Visual Studio Tools <https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019>`_ plugin. It will create a :file:`Documents/Visual Studio 2019/Visualizers/qt6.natvis` file. Once :file:`qt6.natvis` has been created you can uninstall the plugin.
Changing CMake configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Open :menuselection:`Project --> CMake Settings`. CMake options can be modified either in graphical table editor, as a command-line flag or by switching to the JSON view.
Formatting using clang-formatVisual Studio supports clang-format by default so you should not do anything special. It will simple use the existing _clang-format file from Cutter's root directory. If you wish to configure how and when Visual Studio will use clang-format, you can do this from :menuselection:Tools --> Options --> Text Editor --> C/C++ --> Formatting.
Editing Qt .ui files and Qt integration
By default Visual Studio will open ``.ui`` files as XML text documents. You can configure to open it using Qt Designer by right-clicking and selecting :guilabel:`Open With...`.
There is a Qt plugin for Visual Studio from Qt. It isn't very useful for Cutter development since it is aimed more at helping with Qt integration into Visual Studio projects.
It doesn't do much for CMake based projects. The biggest benefit is that it automatically installs :file:`qt6.natvis` file for more readable displaying of Qt types in the debugger.
---
## File: docs/source/contributing/code/release-procedure.rst
Release Procedure
=================
1. Update translations submodule `<https://github.com/rizinorg/cutter-translations>`_
1. The latest archive from Crowdin should already be in the repository, if not make sure to merge any automated Pull Request from Crowdin (e.g. https://github.com/rizinorg/cutter-translations/pull/9)
2. Update submodule in cutter
2. Merge the current state of dev into stable. This can happen even earlier in order to feature-freeze the release while keeping development on dev alive. The rizin submodule on stable should point to a commit of stable in rizin and dev to a commit in dev.
3. Lock rzghidra and rzdec versions downloaded by packaging scripts. Specify a tag or commit hash.
4. Update version
#. appveyor.yml
#. docs/sourc/conf.py
#. docs/source/index.rst
#. CMakeLists.txt
#. Cutter.appdata.xml
#. To be safe, search the code base for the previous version number.
5. Create a tag for the release candidate. For example, for the `v1.11.0` release you'd do something like this:
#. ``git tag v1.11.0-rc1``
#. ``git tag push origin v1.11.0-rc1``
6. Create a GitHub release, mark it as pre-release save draft, set the tag to v1.11.0-rc1
7. Wait for packages to build
8. On all operating systems do the `Basic testing procedure`_ to ensure nothing badly broken.
9. If any major problems are found, open an issue and fix them in dev and cherry pick into release branch. If the amount of changes is sufficiently large repeat from step 3. increasing rc number by one.
10. Update version to 1.11.0
11. Create tag
12. Create release
* Fill the release notes in the Release description. Preparing release notes can begin earlier. Compare current dev branch against previous release to find all the changes. Choose the most important ones. Don't duplicate the commit log. Release notes should be a summary for people who don't want to read whole commit log. Group related changes together under titles such as "New features", "Bug Fixes", "Decompiler", "Rizin" and similar.
13. Prepare announcement tweets and messages to send in the Telegram group, reddit, and others.
14. Close milestone if there was one
Bugfix Release
--------------
The process for bugfix release is similar no normal release procedure described above with some differences.
* Cherry pick required bugfixes from dev into the stable.
* Increase the third version number x.y.n into x.y.(n+1) .
Basic testing procedure
-----------------------
This isn't intended as exhaustive testing process, just some simple steps to make sure nothing is badly broken.
If it makes sense repeat the step multiple times at different offsets and click around increase the chance of noticing common problems that doesn't happen 100% of time.
* Open a simple executable like ``/bin/ls`` or ``calc.exe``
* Make sure that the upgraded layout isn't completely broken
* The Disassembly widget shows proper disassembly.
* Bundled plugins work
* Open decompiler and select ghidra, it shows some C code at least for some functions
* Open rzdec in decompiler widget, make sure it shows code
* Test that sample python plugin works
* Try debugger
* Insert breakpoint in main
* Start debugging
* Go to main using function widget, make sure relocation was done correctly and you see code instead of unmapped memory and breakpoint is where you placed
* Click continue until you hit breakpoint in main
* Delete cutter settings file, and test that clean start works and layout isn't broken
---
## File: docs/source/contributing/docs/building-docs.rst
Building docs
=======================
This page explains the steps that are needed to build Cutter's documentation.
Requirements
------------
You will need:
* doxygen
* python3
* pip3
* sphinx
* breathe
* recommonmark
On Debian-based Linux distributions, the packages above can be installed with the following command.
.. code:: sh
sudo apt install make doxygen python3-pip doxygen
sudo pip3 install sphinx breathe recommonmark
Then, you can build the documentation with the following commands:
.. code:: sh
cd cutter/docs/
make html
.. tip::
If you do not need API documentation, type ``make quick`` instead of ``make html``.
You can find the generated html files at ``cutter/docs/build``. Open ``cutter/docs/build/html/index.html`` with your browser to visit the index file of your local copy of the documentation.
---
## File: docs/source/contributing/docs/getting-started.rst
Contributing documentation to Cutter
====================================
If you reached this place you were probably looking to help and improve Cutter's documentation - Fantastic, welcome aboard!
As many other young projects, Cutter has a problem - it lacks comprehensive documentation and written content. Thankfully, contributing to Cutter's documentation doesnβt require you to have a deep knowledge about the internals of the project. Writing, reviewing, and editing the documentation are great ways to learn about Cutter.
Donβt like the way something reads? Discover some information that wasnβt documented? Your pull request will be gleefully embraced.
.. note::
The documentation of Cutter is written using `Sphinx and reStructuredText <https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html>`_. The syntax is quite straight forward and very similar to Markdown. In the future, we hope to move completely to Markdown as it is more popular.
How can you help?
-----------------
The following sections suggest ways you can contribute to Cutter's documentation. The list isn't complete as the possibilities are limitless.
The source for this documentation is available in the `docs directory <https://github.com/rizinorg/cutter/tree/dev/docs>`_ on Cutter's repository. This source can be generated according to the steps described in the :ref:`building docs page<contributing/docs/building-docs:Building docs>`. When the docs are updated, they are generated and pushed directly to the website at <https://cutter.re/docs>. The source for the website and blog are available on the `cutter.re's repository <https://github.com/rizinorg/cutter.re>`_ and are served from the ``gh-pages`` branch.
.. tip::
Document what you wished to see. If you are a user of Cutter, try to think what things you would want to see documented when you started using the project. Sometimes, the best contributions are coming from your own needs.
User documentation
^^^^^^^^^^^^^^^^^^
The documentation for users describes how to use Cutter and what the different features in Cutter do. The possibilities for contributing are endless since there are so many features that weren't even described on our docs yet. To contribute to our user documentation, all you need to do is pick a subject, widget, or functionality and document it. Describe the different visual components, how to use them, and what this feature even does.
Common Errors and Troubleshooting
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As our community gets bigger, more and more people are using, installing or building Cutter on different setups. Naturally, different environments might cause different issues. The :ref:`common issues` section in our docs aims to go over the most popular issues that you might face while using Cutter and the :ref:`building errors troubleshooting` section goes over common errors that you might face while building Cutter from sources. These docs sections also explain what causes these issues and how to solve them.
If you know of such a common issue, whether you faced it yourself or noticed it on our community chats, it will be very helpful if you could document it and possible solutions for it.
Developers documentation
^^^^^^^^^^^^^^^^^^^^^^^^
The documentation for Cutter developers aims to instruct new contributors on how to get started with developing to Cutter's codebase. It also describes best practices and development guidelines for all developers in the project. Think you have something to add to the developers' docs? We would love you to contribute.
API documentation
^^^^^^^^^^^^^^^^^
The documentation for Cutter's API is an important reference for Cutter developers as well as Plugin developers. It thoroughly describes for developers how some functions and features work. While some of the functions are thoroughly documented, most of them aren't. Any help with improving these documentations will be blessed.
Blog posts
^^^^^^^^^^
We would love to see people writing and sharing their experiences with Cutter. Whether you are solving CTF challenges with Cutter, analyzing malware, finding vulnerabilities, or working on personal projects - we would love to see these published. If you have a personal blog, we would be proud to share and retweet your Cutter-related publications on our profiles, bringing you more engagement and followers. If you don't have a personal blog, we would love to host your publication on our community blog over at https://cutter.re/blog.
---
## File: docs/source/contributing/plugins/getting-started.rst
Getting Started with Python Plugins
===================================
This article provides a step-by-step guide on how to write a simple Python plugin for Cutter.
Create a python file, called ``myplugin.py`` for example, and add the following contents:
.. code-block:: python
import cutter
class MyCutterPlugin(cutter.CutterPlugin):
name = "My Plugin"
description = "This plugin does awesome things!"
version = "1.0"
author = "1337 h4x0r"
def setupPlugin(self):
pass
def setupInterface(self, main):
pass
def terminate(self):
pass
def create_cutter_plugin():
return MyCutterPlugin()
This is the most basic code that makes up a plugin.
Python plugins in Cutter are regular Python modules that are imported automatically on startup.
In order to load the plugin, Cutter will call the function ``create_cutter_plugin()`` located
in the root of the module and expects it to return an instance of ``cutter.CutterPlugin``.
Normally, you shouldn't have to do anything else in this function.
.. note::
The Cutter API is exposed through the ``cutter`` module.
This consists mostly of direct bindings of the original C++ classes, generated with Shiboken6.
For more detail about this API, see the Cutter C++ code or :ref:`api`.
The ``CutterPlugin`` subclass contains some meta-info and two callback methods:
* ``setupPlugin()`` is called right after the plugin is loaded and can be used to initialize the plugin itself.
* ``setupInterface()`` is called with the instance of MainWindow as an argument and should create and register any UI components.
* ``terminate()`` is called on shutdown and should clean up any resources used by the plugin.
Copy this file into the ``python`` subdirectory located under the plugins directory of Cutter and start the application.
You should see an entry for your plugin in the list under Edit -> Preferences -> Plugins.
Here, the absolute path to the plugins directory is shown too if you are unsure where to put your plugin:
.. image:: preferences-plugins.png
.. note::
As mentioned, plugins are Python modules. This means, instead of only a single .py file, you can also
use a directory containing multiple python files and an ``__init__.py`` file that defines or imports the
``create_cutter_plugin()`` function.
.. note::
If you are working on a Unix-like system, instead of copying, you can also symlink your plugin into the plugins
directory, which lets you store the plugin somewhere else without having to copy the files over and over again.
Creating a Widget
-----------------
Next, we are going to add a simple dock widget. Extend the code as follows:
.. code-block:: python
import cutter
from PySide6.QtWidgets import QAction, QLabel
class MyDockWidget(cutter.CutterDockWidget):
def __init__(self, parent, action):
super(MyDockWidget, self).__init__(parent, action)
self.setObjectName("MyDockWidget")
self.setWindowTitle("My cool DockWidget")
label = QLabel(self)
self.setWidget(label)
label.setText("Hello World")
class MyCutterPlugin(cutter.CutterPlugin):
# ...
def setupInterface(self, main):
action = QAction("My Plugin", main)
action.setCheckable(True)
widget = MyDockWidget(main, action)
main.addPluginDockWidget(widget, action)
# ...
We are subclassing ``cutter.CutterDockWidget``, which is the base class for all dock widgets in Cutter,
and adding a label to it.
.. note::
You can access the whole Qt6 API from Python, which is exposed by PySide6. For more information about this, refer to the
Documentation of `Qt <https://doc.qt.io/qt-6/reference-overview.html>`_ and `PySide6 <https://wiki.qt.io/Qt_for_Python>`_.
.. note::
Main cutter packages are now using QT6, but Qt5 builds are still provided for compatibilty with older OS versions. If you
want your plugin to support both, Qt usage process is a bit more complicated.
In our ``setupInterface()`` method, we create an instance of our dock widget and an action to be
added to the menu for showing and hiding the widget.
MainWindow provides a helper method called ``addPluginDockWidget()`` to easily register these.
When running Cutter now, you should see the widget:
.. image:: mydockwidget.png
... as well as the action:
.. image:: mydockwidget-action.png
Fetching Data
-------------
Next, we want to show some actual data from the binary in our widget.
As an example, we will display the instruction and instruction size at the current position.
Extend the code as follows:
.. code-block:: python
# ...
class MyDockWidget(cutter.CutterDockWidget):
def __init__(self, parent, action):
# ...
label = QLabel(self)
self.setWidget(label)
disasm = cutter.cmd("pd 1").strip()
instruction = cutter.cmdj("pdj 1")
size = instruction[0]["size"]
label.setText("Current disassembly:\n{}\nwith size {}".format(disasm, size))
# ...
We can access the data by calling Rizin commands and utilizing their output.
This is done by using the two functions ``cmd()`` and ``cmdj()``, which behave just as they
do in `rz-pipe <https://book.rizin.re/scripting/rz-pipe.html>`_.
Many commands in Rizin can be suffixed with a ``j`` to return JSON output.
``cmdj()`` will automatically deserialize the JSON into python dicts and lists, so the
information can be easily accessed.
.. warning::
When fetching data that is not meant to be used only as readable text, **always** use the JSON variant of a command!
Regular command output is not meant to be parsed and is subject to change at any time, which will break your code.
In our case, we use the two commands ``pd`` (Print Disassembly) and ``pdj`` (Print Disassembly as JSON)
with a parameter of 1 to fetch a single line of disassembly.
.. note::
To try out commands, you can use the Console widget in Cutter. Almost all commands support a ``?`` suffix, like in
``pd?``, to show help and available sub-commands.
To get a general overview, enter a single ``?``.
The result will look like the following:
.. image:: disasm-static.png
Of course, since we only fetch the info once during the creation of the widget, the content never updates.
We are going to change that in the next section.
Reacting to Events
------------------
We want to update the content of our widget on every seek.
This can be done like the following:
.. code-block:: python
# ...
from PySide6.QtCore import QObject, SIGNAL
# ...
class MyDockWidget(cutter.CutterDockWidget):
def __init__(self, parent, action):
# ...
self._label = QLabel(self)
self.setWidget(self._label)
QObject.connect(cutter.core(), SIGNAL("seekChanged(RVA)"), self.update_contents)
def update_contents(self):
disasm = cutter.cmd("pd 1").strip()
instruction = cutter.cmdj("pdj 1")
size = instruction[0]["size"]
self._label.setText("Current disassembly:\n{}\nwith size {}".format(disasm, size))
First, we move the update code to a separate method.
Then we call ``cutter.core()``, which returns the global instance of ``CutterCore``.
This class provides the Qt signal ``seekChanged(RVA)``, which is emitted every time the current seek changes.
We can simply connect this signal to our method and our widget will update as we expect it to:
.. image:: disasm-dynamic.png
For more information about Qt signals and slots, refer to `<https://doc.qt.io/qt-6/signalsandslots.html>`_.
Full Code
---------
.. code-block:: python
import cutter
from PySide6.QtCore import QObject, SIGNAL
from PySide6.QtWidgets import QLabel
from PySide6.QtGui import QAction
class MyDockWidget(cutter.CutterDockWidget):
def __init__(self, parent, action):
super(MyDockWidget, self).__init__(parent, action)
self.setObjectName("MyDockWidget")
self.setWindowTitle("My cool DockWidget")
self._label = QLabel(self)
self.setWidget(self._label)
QObject.connect(cutter.core(), SIGNAL("seekChanged(RVA)"), self.update_contents)
def update_contents(self):
disasm = cutter.cmd("pd 1").strip()
instruction = cutter.cmdj("pdj 1")
size = instruction[0]["size"]
self._label.setText("Current disassembly:\n{}\nwith size {}".format(disasm, size))
class MyCutterPlugin(cutter.CutterPlugin):
name = "My Plugin"
description = "This plugin does awesome things!"
version = "1.0"
author = "1337 h4x0r"
def setupPlugin(self):
pass
def setupInterface(self, main):
action = QAction("My Plugin", main)
action.setCheckable(True)
widget = MyDockWidget(main, action)
main.addPluginDockWidget(widget, action)
def terminate(self):
pass
def create_cutter_plugin():
return MyCutterPlugin()
---
## File: docs/source/contributing/code.rst
Developer Documentation
=======================
.. note::
New to Cutter development? Check out our :doc:`tutorial for new developers <code/getting-started>`.
.. toctree::
:maxdepth: 2
:glob:
Getting Started <code/getting-started>
code/development-guidelines
code/ide-setup
code/*
## 2. Official Technical Reference & Guides (rizinorg/website)
# Rizin Website
## Local Installation
1. Install or download the **Extended** version of [Hugo](https://gohugo.io/getting-started/installing/)
- Newer version of Hugo might not work. The version used here is [v0.111.3](https://github.com/gohugoio/hugo/releases/tag/v0.111.3)
2. Clone this repository and its submodules:
```
$ git clone --recurse-submodules https://github.com/rizinorg/website
```
3. Enter the cloned repository and "serve" the website using Hugo
```bash
$ cd website
# Check hugo version
$ hugo version
hugo v0.111.3-5d4eb5154e1fed125ca8e9b5a0315c4180dab192+extended linux/amd64 BuildDate=2023-03-12T11:40:50Z VendorInfo=gohugoio
$ hugo serve
```
## File tree description
```
.
βββ assets
β βββ css
β βββ custom
β βββ rizin.css <--- Edit CSS here
βββ config.yml <--- Hugo Config for the website
βββ content <--- Markdown files for single pages
β βββ archives.md
β βββ code-of-conduct.md
β βββ organization.md
β βββ posts <--- Markdown blog posts
β β βββ example
β β βββ index.md
β βββ teams <--- Special folder for team pages
β βββ community.md
β βββ core.md
β βββ Distributions and Packaging.md
β βββ package-manager-and-plugins.md
β βββ . . .
βββ data
β βββ teams.json <--- JSON with teams data and descriptions
βββ layouts <--- Special layouts
β βββ _default
β β βββ organization.html
β β βββ team.html
β βββ index.html <--- Main page
β βββ partials <--- override theme or introduce new partials
β βββ extend_head.html
β βββ header.html
β βββ main-page.html
βββ static
β βββ images
β βββ rizin.svg
|
|
βββ themes <--- The base theme. Don't touch files in here
βββ hugo-PaperMod
```
## Demo GIF
When showing Rizin demos the GIF are generated with
[Terminalizer](https://www.terminalizer.com/) by using this [config
file](https://github.com/rizinorg/website/blob/main/.terminalizer-config).