Source code for libdebug.interfaces.debugging_interface
#
# This file is part of libdebug Python library (https://github.com/libdebug/libdebug).
# Copyright (c) 2023-2024 Roberto Alessandro Bertolini, Gabriele Digregorio. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for details.
#
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from libdebug.data.breakpoint import Breakpoint
    from libdebug.data.memory_map import MemoryMap
    from libdebug.data.signal_hook import SignalHook
    from libdebug.data.syscall_hook import SyscallHook
    from libdebug.state.thread_context import ThreadContext
[docs]
class DebuggingInterface(ABC):
    """The interface used by `_InternalDebugger` to communicate with the available debugging backends, such as `ptrace` or `gdb`."""
    def __init__(self: DebuggingInterface) -> None:
        """Initializes the DebuggingInterface classs."""
[docs]
    @abstractmethod
    def reset(self: DebuggingInterface) -> None:
        """Resets the state of the interface.""" 
[docs]
    @abstractmethod
    def run(self: DebuggingInterface) -> None:
        """Runs the specified process.""" 
[docs]
    @abstractmethod
    def attach(self: DebuggingInterface, pid: int) -> None:
        """Attaches to the specified process.
        Args:
            pid (int): the pid of the process to attach to.
        """ 
[docs]
    @abstractmethod
    def detach(self: DebuggingInterface) -> None:
        """Detaches from the process.""" 
[docs]
    @abstractmethod
    def kill(self: DebuggingInterface) -> None:
        """Instantly terminates the process.""" 
[docs]
    @abstractmethod
    def cont(self: DebuggingInterface) -> None:
        """Continues the execution of the process.""" 
[docs]
    @abstractmethod
    def wait(self: DebuggingInterface) -> None:
        """Waits for the process to stop.""" 
[docs]
    @abstractmethod
    def migrate_to_gdb(self: DebuggingInterface) -> None:
        """Migrates the current process to GDB.""" 
[docs]
    @abstractmethod
    def migrate_from_gdb(self: DebuggingInterface) -> None:
        """Migrates the current process from GDB.""" 
[docs]
    @abstractmethod
    def step(self: DebuggingInterface, thread: ThreadContext) -> None:
        """Executes a single instruction of the specified thread.
        Args:
            thread (ThreadContext): The thread to step.
        """ 
[docs]
    @abstractmethod
    def step_until(self: DebuggingInterface, thread: ThreadContext, address: int, max_steps: int) -> None:
        """Executes instructions of the specified thread until the specified address is reached.
        Args:
            thread (ThreadContext): The thread to step.
            address (int): The address to reach.
            max_steps (int): The maximum number of steps to execute.
        """ 
[docs]
    @abstractmethod
    def finish(self: DebuggingInterface, thread: ThreadContext, heuristic: str) -> None:
        """Continues execution until the current function returns or the process stops.
        The command requires a heuristic to determine the end of the function. The available heuristics are:
        - `backtrace`: The debugger will place a breakpoint on the saved return address found on the stack and continue execution on all threads.
        - `step-mode`: The debugger will step on the specified thread until the current function returns. This will be slower.
        Args:
            thread (ThreadContext): The thread to finish.
            heuristic (str, optional): The heuristic to use. Defaults to "backtrace".
        """ 
[docs]
    @abstractmethod
    def maps(self: DebuggingInterface) -> list[MemoryMap]:
        """Returns the memory maps of the process.""" 
[docs]
    @abstractmethod
    def set_breakpoint(self: DebuggingInterface, bp: Breakpoint) -> None:
        """Sets a breakpoint at the specified address.
        Args:
            bp (Breakpoint): The breakpoint to set.
        """ 
[docs]
    @abstractmethod
    def unset_breakpoint(self: DebuggingInterface, bp: Breakpoint) -> None:
        """Restores the original instruction flow at the specified address.
        Args:
            bp (Breakpoint): The breakpoint to restore.
        """ 
[docs]
    @abstractmethod
    def set_syscall_hook(self: DebuggingInterface, hook: SyscallHook) -> None:
        """Sets a syscall hook.
        Args:
            hook (SyscallHook): The syscall hook to set.
        """ 
[docs]
    @abstractmethod
    def unset_syscall_hook(self: DebuggingInterface, hook: SyscallHook) -> None:
        """Unsets a syscall hook.
        Args:
            hook (SyscallHook): The syscall hook to unset.
        """ 
[docs]
    @abstractmethod
    def set_signal_hook(self: DebuggingInterface, hook: SignalHook) -> None:
        """Sets a signal hook.
        Args:
            hook (SignalHook): The signal hook to set.
        """ 
[docs]
    @abstractmethod
    def unset_signal_hook(self: DebuggingInterface, hook: SignalHook) -> None:
        """Unsets a signal hook.
        Args:
            hook (SignalHook): The signal hook to unset.
        """ 
[docs]
    @abstractmethod
    def peek_memory(self: DebuggingInterface, address: int) -> int:
        """Reads the memory at the specified address.
        Args:
            address (int): The address to read.
        Returns:
            int: The read memory value.
        """ 
[docs]
    @abstractmethod
    def poke_memory(self: DebuggingInterface, address: int, data: int) -> None:
        """Writes the memory at the specified address.
        Args:
            address (int): The address to write.
            data (int): The value to write.
        """