pyplugins.wrappers.ptregs_wrap module¶
ptregs_wrap.py - Architecture-agnostic wrappers for Linux pt_regs structures¶
This module provides Pythonic, type-annotated wrappers for Linux kernel pt_regs structures across multiple CPU architectures. It enables convenient, architecture-independent access to process register state, such as that captured at system call entry/exit, exceptions, or context switches. The wrappers abstract away the raw struct layout and provide a unified interface for reading/writing registers, extracting syscall arguments, and handling calling conventions.
Overview¶
The module defines a base PtRegsWrapper class and a set of subclasses for each supported architecture (x86, x86_64, ARM, AArch64, MIPS, PowerPC, LoongArch64, RISC-V, etc). Each subclass knows how to access registers and arguments according to its architecture’s ABI and pt_regs layout. The wrappers can be used with PANDA or other emulation/analysis frameworks that expose pt_regs-like objects.
The module also provides a get_pt_regs_wrapper() factory function to select the correct wrapper for a given architecture.
Typical Usage¶
Suppose you have a PANDA plugin or other tool that provides a pt_regs struct (e.g., at a syscall, exception, or context switch):
from wrappers.ptregs_wrap import get_pt_regs_wrapper
# Assume 'regs' is a pt_regs struct and 'panda' is a PANDA object
wrapper = get_pt_regs_wrapper(panda, regs, arch_name=panda.arch_name)
# Access registers in an architecture-agnostic way
pc = wrapper.get_pc()
sp = wrapper.get_sp()
retval = wrapper.get_retval()
# Get syscall arguments (handles calling convention automatically)
arg0 = wrapper.get_syscall_arg(0)
arg1 = wrapper.get_syscall_arg(1)
# Or get userland function arguments
user_arg0 = wrapper.get_userland_arg(0)
# Dump all registers as a dictionary
reg_dict = wrapper.dump()
# Coroutine-style argument access (portal):
# get_args_portal and get_arg_portal are generator-based and can yield if a memory read is required (e.g., stack argument).
# Use 'yield from' to drive these coroutines in a portal/coroutine context.
args = yield from wrapper.get_args_portal(3)
The wrappers also support advanced features such as handling 32-bit compatibility mode on x86_64/AArch64, stack argument extraction, and portal-style coroutine memory reads. The get_args_portal and get_arg_portal methods are generator-based and will yield if a memory read is required (such as when reading stack arguments may fail and need to be retried or handled asynchronously).
Classes¶
PtRegsWrapper: Base class for all pt_regs wrappers, provides generic register access and argument extraction.
X86PtRegsWrapper, X86_64PtRegsWrapper, ArmPtRegsWrapper, …: Architecture-specific subclasses.
PandaMemReadFail: Exception for failed memory reads (for portal/coroutine use).
Functions¶
get_pt_regs_wrapper(panda: Optional[Any], regs: Any, arch_name: Optional[str] = None) -> PtRegsWrapper: Factory to select the correct wrapper for a given architecture.
These wrappers are useful for dynamic analysis, syscall tracing, emulation, and any tool that needs to reason about process register state in a cross-architecture way.
- class pyplugins.wrappers.ptregs_wrap.AArch64PtRegsWrapper(obj, panda=None)[source]¶
Bases:
PtRegsWrapperWrapper for AArch64 pt_regs
- Parameters:
obj (Any)
panda (Any | None)
- get_register(reg_name)[source]¶
Get register value by name, handling AArch32 compatibility mode if needed
- Parameters:
reg_name (str)
- Return type:
int | None
- get_syscall_arg(num)[source]¶
Get AArch64 syscall argument, considering compatibility mode
- Parameters:
num (int)
- Return type:
int | None
- get_syscall_number()[source]¶
Get syscall number, considering compatibility mode. In AArch64, the syscall number is in syscallno. In AArch32 mode, use ARM implementation.
- Return type:
int | None
- get_userland_arg(num)[source]¶
Get AArch64 userland argument, considering compatibility mode
- Parameters:
num (int)
- Return type:
int | None
- i = 30¶
- class pyplugins.wrappers.ptregs_wrap.ArmPtRegsWrapper(obj, panda=None)[source]¶
Bases:
PtRegsWrapperWrapper for ARM pt_regs
- Parameters:
obj (Any)
panda (Any | None)
- get_syscall_arg(num)[source]¶
Get ARM syscall argument
- Parameters:
num (int)
- Return type:
int | None
- class pyplugins.wrappers.ptregs_wrap.LoongArch64PtRegsWrapper(obj, panda=None)[source]¶
Bases:
PtRegsWrapperWrapper for LoongArch64 pt_regs
- Parameters:
obj (Any)
panda (Any | None)
- field = 'csr_estat'¶
- get_syscall_arg(num)[source]¶
Get LoongArch64 syscall argument
- Parameters:
num (int)
- Return type:
int | None
- get_userland_arg(num)[source]¶
Get LoongArch64 userland argument
- Parameters:
num (int)
- Return type:
int | None
- idx = 31¶
- in_kernel()[source]¶
Returns True if the pt_regs represents kernel mode, False otherwise. Subclasses should override for architecture-specific logic.
- Return type:
bool
- name = 's8'¶
- class pyplugins.wrappers.ptregs_wrap.Mips64PtRegsWrapper(obj, panda=None)[source]¶
Bases:
MipsPtRegsWrapperWrapper for MIPS64 pt_regs
- Parameters:
obj (Any)
panda (Any | None)
- class pyplugins.wrappers.ptregs_wrap.MipsPtRegsWrapper(obj, panda=None)[source]¶
Bases:
PtRegsWrapperWrapper for MIPS pt_regs
- Parameters:
obj (Any)
panda (Any | None)
- get_syscall_arg(num)[source]¶
Get MIPS syscall argument
- Parameters:
num (int)
- Return type:
int | None
- get_userland_arg(num)[source]¶
Get MIPS userland argument
- Parameters:
num (int)
- Return type:
int | None
- idx = 31¶
- in_kernel()[source]¶
Returns True if the pt_regs represents kernel mode, False otherwise. Subclasses should override for architecture-specific logic.
- Return type:
bool
- name = 'ra'¶
- exception pyplugins.wrappers.ptregs_wrap.PandaMemReadFail(addr, size)[source]¶
Bases:
ExceptionException for failed memory reads, used for portal/coroutine use-cases.
- Attributes:
addr (int): The address that failed to read. size (int): The size of the attempted read.
- Parameters:
addr (int)
size (int)
- Return type:
None
- class pyplugins.wrappers.ptregs_wrap.PowerPC64PtRegsWrapper(obj, panda=None)[source]¶
Bases:
PowerPCPtRegsWrapperWrapper for PowerPC64 pt_regs
- Parameters:
obj (Any)
panda (Any | None)
- class pyplugins.wrappers.ptregs_wrap.PowerPCPtRegsWrapper(obj, panda=None)[source]¶
Bases:
PtRegsWrapperWrapper for PowerPC pt_regs
- Parameters:
obj (Any)
panda (Any | None)
- get_syscall_arg(num)[source]¶
Get PowerPC syscall argument
- Parameters:
num (int)
- Return type:
int | None
- get_userland_arg(num)[source]¶
Get PowerPC userland argument
- Parameters:
num (int)
- Return type:
int | None
- i = 31¶
- in_kernel()[source]¶
Returns True if the pt_regs represents kernel mode, False otherwise. Subclasses should override for architecture-specific logic.
- Return type:
bool
- reg = 'result'¶
- class pyplugins.wrappers.ptregs_wrap.PtRegsWrapper(obj, panda=None)[source]¶
Bases:
WrapperBase class for pt_regs wrappers across different architectures.
- Args:
obj: The pt_regs structure to wrap. panda: Optional PANDA object for memory reading.
- Parameters:
obj (Any)
panda (Any | None)
- property REG_NAMES: List[str]¶
Returns a list of all valid register names for this architecture.
- get_arg(num, convention=None)[source]¶
Get function argument based on calling convention.
- Args:
num: Argument number (0-based) convention: Calling convention (‘syscall’ or ‘userland’)
- Returns:
The value of the requested argument
- Parameters:
num (int)
convention (str | None)
- Return type:
int | None
- get_arg_portal(num, convention=None)[source]¶
Coroutine/generator version of get_arg for portal/coroutine use.
- Args:
num: Argument number (0-based) convention: Calling convention (‘syscall’ or ‘userland’)
- Returns:
The value of the requested argument (or None if unavailable).
- Parameters:
num (int)
convention (str | None)
- Return type:
Generator[int | None, Any, int | None]
- get_args(count, convention=None)[source]¶
Get a list of function arguments according to the calling convention.
- Args:
count: Number of arguments to retrieve. convention: Calling convention (‘syscall’ or ‘userland’).
- Returns:
List of argument values (may include None if unavailable).
- Parameters:
count (int)
convention (str | None)
- Return type:
List[int | None]
- get_args_portal(count, convention=None)[source]¶
Coroutine/generator version of get_args for portal/coroutine use.
- Args:
count: Number of arguments to retrieve. convention: Calling convention (‘syscall’ or ‘userland’).
- Returns:
List of argument values (may include None if unavailable).
- Parameters:
count (int)
convention (str | None)
- Return type:
Generator[int | None, Any, List[int | None]]
- get_register(reg_name)[source]¶
Get register value by name (Optimized).
- Parameters:
reg_name (str)
- Return type:
int | None
- get_retaddr()[source]¶
Get the return address (best guess for this architecture). Supports both generator and non-generator implementations in subclasses.
- Return type:
int | None
- get_retaddr_portal()[source]¶
Coroutine/generator version of get_retaddr for portal/coroutine use.
- Return type:
Generator[int | None, Any, int | None]
- get_syscall_arg(num)[source]¶
Get syscall argument. Subclasses must implement.
- Parameters:
num (int)
- Return type:
int | None
- get_syscall_number()[source]¶
Get syscall number. Subclasses must implement.
- Return type:
int | None
- get_userland_arg(num)[source]¶
Get userland argument. Subclasses must implement.
- Parameters:
num (int)
- Return type:
int | None
- in_kernel()[source]¶
Returns True if the pt_regs represents kernel mode, False otherwise. Subclasses should override for architecture-specific logic.
- Return type:
bool
- read_stack_arg(arg_num, word_size=None)[source]¶
Read a function argument from the stack.
- Args:
arg_num: Argument number (0-based). word_size: Word size override (default: based on architecture).
- Returns:
The argument value read from the stack.
- Parameters:
arg_num (int)
word_size (int | None)
- Return type:
int | None
- set_register(reg_name, value)[source]¶
Set register value by name (Optimized).
- Parameters:
reg_name (str)
value (int)
- Return type:
bool
- class pyplugins.wrappers.ptregs_wrap.Riscv32PtRegsWrapper(obj, panda=None)[source]¶
Bases:
PtRegsWrapperWrapper for RISC-V 32-bit pt_regs
- Parameters:
obj (Any)
panda (Any | None)
- abi_name = 't6'¶
- get_syscall_arg(num)[source]¶
Get RISC-V 32-bit syscall argument
- Parameters:
num (int)
- Return type:
int | None
- get_userland_arg(num)[source]¶
Get RISC-V 32-bit userland argument
- Parameters:
num (int)
- Return type:
int | None
- in_kernel()[source]¶
Returns True if the pt_regs represents kernel mode, False otherwise. Subclasses should override for architecture-specific logic.
- Return type:
bool
- x_reg = 'x31'¶
- class pyplugins.wrappers.ptregs_wrap.Riscv64PtRegsWrapper(obj, panda=None)[source]¶
Bases:
Riscv32PtRegsWrapperWrapper for RISC-V 64-bit pt_regs - same structure as 32-bit but with 64-bit registers
- Parameters:
obj (Any)
panda (Any | None)
- class pyplugins.wrappers.ptregs_wrap.X86PtRegsWrapper(obj, panda=None)[source]¶
Bases:
PtRegsWrapperWrapper for x86 (32-bit) pt_regs
- Parameters:
obj (Any)
panda (Any | None)
- get_syscall_arg(num)[source]¶
Get x86 syscall argument
- Parameters:
num (int)
- Return type:
int | None
- class pyplugins.wrappers.ptregs_wrap.X86_64PtRegsWrapper(obj, panda=None)[source]¶
Bases:
PtRegsWrapperWrapper for x86_64 pt_regs
- Parameters:
obj (Any)
panda (Any | None)
- get_register(reg_name)[source]¶
Get register value by name (Optimized).
- Parameters:
reg_name (str)
- Return type:
int | None
- get_syscall_arg(num)[source]¶
Get x86_64 syscall argument, considering compatibility mode
- Parameters:
num (int)
- Return type:
int | None
- get_syscall_number()[source]¶
Get syscall number, considering compatibility mode. In x86_64, the syscall number is in orig_rax. In compatibility mode, use x86 implementation.
- Return type:
int | None
- get_userland_arg(num)[source]¶
Get x86_64 userland argument, considering compatibility mode
- Parameters:
num (int)
- Return type:
int | None
- in_kernel()[source]¶
Returns True if the pt_regs represents kernel mode, False otherwise. Subclasses should override for architecture-specific logic.
- Return type:
bool
- k = 'rsp'¶
- set_register(reg_name, value)[source]¶
Set register value by name (Optimized).
- Parameters:
reg_name (str)
value (int)
- Return type:
bool
- v = 'sp'¶
- pyplugins.wrappers.ptregs_wrap.get_pt_regs_wrapper(panda, regs, arch_name=None)[source]¶
Factory function to create the appropriate pt_regs wrapper based on architecture.
- Args:
panda: PANDA object (may be used to determine architecture if arch_name not provided) regs: The pt_regs structure to wrap arch_name: Architecture name (optional, will be determined from PANDA if not provided)
- Returns:
An appropriate PtRegsWrapper subclass instance.
- Parameters:
panda (Any | None)
regs (Any)
arch_name (str | None)
- Return type: