Skip to content

Python scripting#

This page describes the rev.ng Python scripting capabilities.

Creating a project#

There two project classes to use rev.ng from Python: CLIProject, which spawns revng as a subprocess for each command, and DaemonProject, which interacts with revng daemon over the network using the GraphQL API. Apart from this difference, they offer the same programming interface.

First, import the project of choice:

>>> from revng.project import CLIProject     # for cli
>>> from revng.project import DaemonProject  # for daemon

>>> project = CLIProject()

You can provide a path to the resume directory (similar to revng [command] --resume). This useful if you want to persist changes for loading the project again in the future:

>>> resume = "path/to/resume/dir"
>>> project = CLIProject(resume)

After that, you can to import a binary and run the initial auto analyses, we have a method that does just that:

>>> from revng.support import get_example_binary_path
>>> binary_path = get_example_binary_path()
>>> project.import_and_analyze(binary_path)

Producing artifacts#

Once you have successfully loaded a binary, you can obtain the available artifacts:

# Get artifact through the `project`
>>> project.model.get_artifact("disassemble")

# Pass functions that you want to get artifacts from, the second argument is a
# `list` so you can pass multiple functions
>>> project.model.get_artifact("disassemble", [project.model.Functions[0]])

# Get artifact through a `function`, this is equal to above
>>> project.model.Functions[0].get_artifact("disassemble")

# Get multiple artifacts at once. Pass `None` if you wish to get the artifact
# for all the targets
>>> project.model.get_artifacts({
...    "disassemble": [project.model.Functions[0],
...                    project.model.Functions[1]],
...    "decompile": None
... })

# You can also get the artifact for `TypeDefinitions`
>>> project.model.TypeDefinitions[1].get_artifact("emit-type-definitions")

You can also parse the result with ptml:

>>> result = project.model.Functions[0].get_artifact("disassemble")
>>> result.parse()

LLVM modules can be parsed and explored via the llvmcpy python module:

>>> lifted = project.model.get_artifact("lift")

# Use the parsed IR
>>> for function in lifted.module().iter_functions():
...     for bb in function.iter_basic_blocks():
...         for instruction in bb.iter_instructions():
...             instruction.dump()

Interacting with the model#

In order to access the model, use project.model:

>>> project.model            # Binary
>>> project.model.Functions  # Functions

Beyond inspecting the model, you can change it. For example rename a function:

>>> project.model.Functions[0].Name = "new_function_name"

After you make a change, you need to invoke the commit method in order for the changes to be applied (e.g., to see the new name in an artifact):

>>> project.model.Functions[0].Name = "new_function_name"
>>> project.model.commit()

If you want to run a set of predefined analyses, you can run them with:

>>> project.model.analyses_list("revng-initial-auto-analysis")

If you want to run a specific analysis instead, you can do that too.

>>> project.model.analyze("detect-stack-size")