Source code for libdebug.utils.debugger_wrappers
#
# This file is part of libdebug Python library (https://github.com/libdebug/libdebug).
# Copyright (c) 2024 Gabriele Digregorio, Roberto Alessandro Bertolini. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for details.
#
from __future__ import annotations
from functools import wraps
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from libdebug.debugger.internal_debugger import InternalDebugger
    from libdebug.state.thread_context import ThreadContext
[docs]
def change_state_function_process(method: callable) -> callable:
    """Decorator to perfom control flow checks before executing a method."""
    @wraps(method)
    def wrapper(self: InternalDebugger, *args: ..., **kwargs: ...) -> ...:
        if not self.instanced:
            raise RuntimeError(
                "Process not running. Did you call run()?",
            )
        # We have to ensure that the process is stopped before executing the method
        self._ensure_process_stopped()
        # We have to ensure that at least one thread is alive before executing the method
        if self.threads[0].dead:
            raise RuntimeError("All threads are dead.")
        return method(self, *args, **kwargs)
    return wrapper 
[docs]
def change_state_function_thread(method: callable) -> callable:
    """Decorator to perfom control flow checks before executing a method."""
    @wraps(method)
    def wrapper(
        self: InternalDebugger, thread: ThreadContext, *args: ..., **kwargs: ...
    ) -> ...:
        if not self.instanced:
            raise RuntimeError(
                "Process not running. Did you call run()?",
            )
        # We have to ensure that the process is stopped before executing the method
        self._ensure_process_stopped()
        # We have to ensure that at least one thread is alive before executing the method
        if thread.dead:
            raise RuntimeError("The threads is dead.")
        return method(self, thread, *args, **kwargs)
    return wrapper 
[docs]
def background_alias(alias_method: callable) -> callable:
    """Decorator that automatically resolves the call to a different method if coming from the background thread."""
    # This is the stupidest thing I've ever seen. Why Python, why?
    def _background_alias(method: callable) -> callable:
        @wraps(method)
        def inner(self: InternalDebugger, *args: ..., **kwargs: ...) -> ...:
            if self._is_in_background():
                return alias_method(self, *args, **kwargs)
            return method(self, *args, **kwargs)
        return inner
    return _background_alias