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")