integration ¤
Provides decompiler integration by leveraging decomp2dbg (mahaloz/decomp2dbg).
Communicates with the decomp2dbg decompiler plugins by following the API laid out in https://github.com/mahaloz/decomp2dbg/blob/main/decompilers/server_template.py.
Code used as reference: + https://github.com/mahaloz/decomp2dbg/blob/main/decomp2dbg/clients/client.py + https://github.com/mahaloz/decomp2dbg/blob/main/decomp2dbg/clients/gdb/gdb_client.py
Classes:
-
GlobalVariable– -
GlobalVariables– -
FunctionHeader– -
FunctionHeaders– -
RegisterVariable– -
StackVariable– -
RebasedStackVariable– -
FuncVariables– -
RebasedFuncVariables– -
FuncDecompilationResult– -
DecompilerID– -
DecompilerConnection–Allows communication with the decompiler.
-
IntegrationManager–A singleton class that manages all integration-related stuff.
Attributes:
-
manual_binary_address(int) – -
manager(IntegrationManager) –
GlobalVariable dataclass ¤
GlobalVariables dataclass ¤
GlobalVariables(vars: list[GlobalVariable])
FunctionHeader dataclass ¤
FunctionHeaders dataclass ¤
FunctionHeaders(funcs: list[FunctionHeader])
RegisterVariable dataclass ¤
StackVariable dataclass ¤
RebasedStackVariable dataclass ¤
FuncVariables dataclass ¤
FuncVariables(
stack_vars: list[StackVariable], reg_vars: list[RegisterVariable]
)
RebasedFuncVariables dataclass ¤
RebasedFuncVariables(
stack_vars: list[RebasedStackVariable], reg_vars: list[RegisterVariable]
)
FuncDecompilationResult dataclass ¤
DecompilerID ¤
DecompilerConnection ¤
Allows communication with the decompiler.
The lifecycle of this object is tied to the connection to the compiler. It is only constructed after a successful connection, and must not be used after the connection dies.
You should expect every function here to be able to throw ConnectionRefusedError.
Methods:
-
addr_to_mapped–Takes an address relative to the image/file base and
-
addr_to_relative–Takes an address from the live process' address space and returns
-
disconnect–Disconnects from the XML RPC server.
-
decompile–See IntegrationManager.decompile() for the function description.
-
function_data–See IntegrationManager.function_data() for the function description.
-
function_headers–See IntegrationManager.function_headers() for the function description.
-
global_vars–See IntegrationManager.global_vars() for the function description.
-
structs– -
breakpoints– -
focus_address–See IntegrationManager.focus_address() for the function description.
Attributes:
-
server(ServerProxy) –The (host filesystem) path of the binary loaded in the decompiler.
-
binary_path(str) –Version information about the decompiler we are connected to. See
-
versions(dict[str, str]) –The address of the start of the binary in the live process address space.
-
binary_base_addr(int) –
server instance-attribute ¤
The (host filesystem) path of the binary loaded in the decompiler. It can be both an executable and a shared library.
binary_path instance-attribute ¤
Version information about the decompiler we are connected to. See plugin server_template.py for the format.
versions instance-attribute ¤
The address of the start of the binary in the live process address space. Has value -1 if the process is not live or if the binary is not loaded yet.
addr_to_mapped ¤
Takes an address relative to the image/file base and returns the actual address in the process' address space.
self.binary_base_addr must be valid before calling this.
addr_to_relative ¤
Takes an address from the live process' address space and returns the relative offset from the the image/file base.
self.binary_base_addr must be valid before calling this.
Assumes that this address is actually in the self.binary_path image rather than somewhere else. If you don't want to check this beforehand (because of performance), you at the very least need to check that the value returned here doesn't exceed XML-RPC int limits.
disconnect ¤
Disconnects from the XML RPC server.
Delete this object after running this function.
decompile ¤
decompile(mapped_addr: int) -> FuncDecompilationResult | None
See IntegrationManager.decompile() for the function description.
function_data ¤
function_data(mapped_addr: int) -> FuncVariables | None
See IntegrationManager.function_data() for the function description.
function_headers ¤
function_headers() -> FunctionHeaders | None
See IntegrationManager.function_headers() for the function description.
global_vars ¤
global_vars() -> GlobalVariables | None
See IntegrationManager.global_vars() for the function description.
focus_address ¤
See IntegrationManager.focus_address() for the function description.
IntegrationManager ¤
A singleton class that manages all integration-related stuff.
We can connect to only one decompiler at a time, and acknowledge only one file that decompiler is decompiling. (Could be relaxed in the future! Especially the latter.)
All functions except connect() and disconnect() are no-op if we aren't connected.
Methods:
-
invalidate_caches– -
connect–Connects to the remote decompiler.
-
remove_symbols–Remove the decompiler symbols that we added latest.
-
disconnect– -
update_symbols–Update global variables and functions in the debugger.
-
update_function_variables–Update debugger convnience varibles based on the function variables in the currently
-
is_connected–Are we connected to a decompiler?
-
decompiler_id–Which decompiler are we connected to?
-
decompiler_name–If we are connected, will return the name of the decompiler we are connected to.
-
version_string–Get a string with version information about the decompiler environment.
-
get_function_vars_rebased_from_frame–Get function variables for the passed frame. Stack variables will have valid addresses rather than offsets.
-
get_stack_var_dict_from_frame–Ask the decompiler for stack variable offsets in this frame and resolve
-
get_stack_var_dict_all–Take all valid stack frames (from the whole backtrace), ask the decompiler to
-
decompile_pretty–Get the prettified decompilation of a function.
-
symbol_at_address–Returns name of a symbol (function or global variable) at given address,
-
decompile_raw–Returns the decompilation of the function which contains address
mapped_addr. -
function_data–Returns the variables of the function which contains address
mapped_addr. -
function_headers–Returns the name, address and size off all functions in the binary, sorted
-
global_vars–Returns the name and address of all global variables in the binary, sorted
-
structs– -
breakpoints– -
focus_address–Focus (jump to) this address in the decompiler.
connect ¤
Connects to the remote decompiler.
Always invalidates the previous connection. This manager saves the new connection internally only if it succeeds.
Returns True if the connection succeeded, otherwise False.
remove_symbols ¤
remove_symbols(inf: Process | None = None) -> bool
Remove the decompiler symbols that we added latest.
Returns whether we suceeded. Resets self._latest_symbol_file_path regardless of success.
FIXME: Only works for GDB :(
update_symbols ¤
Update global variables and functions in the debugger.
This always invalidates the cache for global variables and function headers, and requests them from the plugin.
Returns the amount of synced symbols.
FIXME: Currently they are all 8 bytes in size.
update_function_variables ¤
Update debugger convnience varibles based on the function variables in the currently selected frame.
This always fully invalidates the cache for function variables and requests them from the plugin.
Returns:
-
int–The number of variables we successfully updated in the debugger.
FIXME: Currently this kinda doesn't work if it runs while we are in the function prologue. We should ideally run it only when we enter new functions and are past their prologues.
is_connected ¤
Are we connected to a decompiler?
Lightweight check, use a ping for an actual check.
decompiler_name ¤
If we are connected, will return the name of the decompiler we are connected to.
If we are not connected, will return "???".
version_string ¤
Get a string with version information about the decompiler environment.
get_function_vars_rebased_from_frame ¤
get_function_vars_rebased_from_frame(
frame: Frame,
) -> RebasedFuncVariables | None
Get function variables for the passed frame. Stack variables will have valid addresses rather than offsets.
frame.pc() will be used to ask the debugger for the valid function variables. Note that it is possible that the same function returns different sets of variables at different PC's.
frame.sp() and frame.start() are used to rebase stack variables based on decompiler-returned offsets. Register variables are unmodified.
The RPC call to the decompiler when asking for variables is cached, but the rebasing is not, ergo this function call is relatively expensive.
Parameters:
-
frame(Frame) –The frame to use for fetching variables.
get_stack_var_dict_from_frame ¤
get_stack_var_dict_from_frame(frame: Frame) -> dict[int, str]
Ask the decompiler for stack variable offsets in this frame and resolve each variable to an actual address.
The RPC call to the decompiler when asking for variables is cached, but the rebasing is not, and dict creating is not, ergo this function call is relatively expensive.
Returns:
-
dict[int, str]–A dictionary that maps (stack variable address) -> (stack variable name)
-
dict[int, str]–for all variables in the given frame.
get_stack_var_dict_all ¤
Take all valid stack frames (from the whole backtrace), ask the decompiler to figure out where they are, and map them to their actual addresses.
You must not modify the object you got from this function (because of caching).
Returns:
-
dict[int, str]–A dictionary that maps (stack variable address) -> (stack variable name)
-
dict[int, str]–for all currently valid stack frames.
decompile_pretty ¤
Get the prettified decompilation of a function.
The following things are done: + syntax highlighting + '►' indicator at the current line + trimmed to only return nlines lines (surrounding the mapped_addr) (returns all lines if nlines == -1)
Returns a list of strings each representing one line of the decompilation.
symbol_at_address ¤
Returns name of a symbol (function or global variable) at given address, or None if there is nothing there.
FIXME: Currently, global variables don't acknowledge their actual size. FIXME2: After update_symbols() is updated to acknowledge symbol sizes, this will be obsolete.
decompile_raw ¤
decompile_raw(mapped_addr: int) -> FuncDecompilationResult | None
Returns the decompilation of the function which contains address mapped_addr.
Generally you should use self.decompile_pretty().
function_data ¤
function_data(mapped_addr: int) -> FuncVariables | None
Returns the variables of the function which contains address mapped_addr.
The "offset" field of the stack variables is poorly defined.
The register variables are quite best effort and do not actually take the asked for address into account. In other words, the output for these may be just plain wrong.
Function arguments are included in these variables.
function_headers ¤
function_headers() -> FunctionHeaders | None
Returns the name, address and size off all functions in the binary, sorted by address.
global_vars ¤
global_vars() -> GlobalVariables | None
Returns the name and address of all global variables in the binary, sorted by address.
focus_address ¤
Focus (jump to) this address in the decompiler.