-
-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathdebugging_interface.py
More file actions
195 lines (148 loc) · 6.71 KB
/
debugging_interface.py
File metadata and controls
195 lines (148 loc) · 6.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#
# This file is part of libdebug Python library (https://github.com/libdebug/libdebug).
# Copyright (c) 2023-2025 Roberto Alessandro Bertolini, Gabriele Digregorio, Francesco Panebianco. 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.memory_map_list import MemoryMapList
from libdebug.data.registers import Registers
from libdebug.data.signal_catcher import SignalCatcher
from libdebug.data.syscall_handler import SyscallHandler
from libdebug.debugger.internal_debugger import InternalDebugger
from libdebug.state.thread_context import ThreadContext
class DebuggingInterface(ABC):
"""The interface used by `_InternalDebugger` to communicate with the available debugging backends, such as `ptrace` or `gdb`."""
@abstractmethod
def __init__(self: DebuggingInterface, internal_debugger: InternalDebugger) -> None:
"""Initializes the DebuggingInterface classs."""
@abstractmethod
def reset(self: DebuggingInterface) -> None:
"""Resets the state of the interface."""
@abstractmethod
def run(self: DebuggingInterface, redirect_pipes: bool) -> None:
"""Runs the specified process.
Args:
redirect_pipes (bool): Whether to hook and redirect the pipes of the process to a PipeManager.
"""
@abstractmethod
def attach(self: DebuggingInterface, pid: int) -> None:
"""Attaches to the specified process.
Args:
pid (int): the pid of the process to attach to.
"""
@abstractmethod
def detach(self: DebuggingInterface) -> None:
"""Detaches from the process."""
@abstractmethod
def kill(self: DebuggingInterface) -> None:
"""Instantly terminates the process."""
@abstractmethod
def cont(self: DebuggingInterface) -> None:
"""Continues the execution of the process."""
@abstractmethod
def wait(self: DebuggingInterface) -> None:
"""Waits for the process to stop."""
@abstractmethod
def migrate_to_gdb(self: DebuggingInterface) -> None:
"""Migrates the current process to GDB."""
@abstractmethod
def migrate_from_gdb(self: DebuggingInterface) -> None:
"""Migrates the current process from GDB."""
@abstractmethod
def step(self: DebuggingInterface, thread: ThreadContext) -> None:
"""Executes a single instruction of the specified thread.
Args:
thread (ThreadContext): The thread to step.
"""
@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.
"""
@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".
"""
@abstractmethod
def next(self: DebuggingInterface, thread: ThreadContext) -> None:
"""Executes the next instruction of the process. If the instruction is a call, the debugger will continue until the called function returns."""
@abstractmethod
def get_maps(self: DebuggingInterface) -> MemoryMapList[MemoryMap]:
"""Returns the memory maps of the process."""
@abstractmethod
def set_breakpoint(self: DebuggingInterface, bp: Breakpoint) -> None:
"""Sets a breakpoint at the specified address.
Args:
bp (Breakpoint): The breakpoint to set.
"""
@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.
"""
@abstractmethod
def set_syscall_handler(self: DebuggingInterface, handler: SyscallHandler) -> None:
"""Sets a handler for a syscall.
Args:
handler (HandledSyscall): The syscall to set.
"""
@abstractmethod
def unset_syscall_handler(self: DebuggingInterface, handler: SyscallHandler) -> None:
"""Unsets a handler for a syscall.
Args:
handler (HandledSyscall): The syscall to unset.
"""
@abstractmethod
def set_signal_catcher(self: DebuggingInterface, catcher: SignalCatcher) -> None:
"""Sets a catcher for a signal.
Args:
catcher (CaughtSignal): The signal to set.
"""
@abstractmethod
def unset_signal_catcher(self: DebuggingInterface, catcher: SignalCatcher) -> None:
"""Unset a catcher for a signal.
Args:
catcher (CaughtSignal): The signal to unset.
"""
@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.
"""
@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.
"""
@abstractmethod
def fetch_fp_registers(self: DebuggingInterface, registers: Registers) -> None:
"""Fetches the floating-point registers of the specified thread.
Args:
registers (Registers): The registers instance to update.
"""
@abstractmethod
def flush_fp_registers(self: DebuggingInterface, registers: Registers) -> None:
"""Flushes the floating-point registers of the specified thread.
Args:
registers (Registers): The registers instance to flush.
"""