|
|
|
|
@ -1,6 +1,7 @@
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import re
|
|
|
|
|
from asyncio import CancelledError
|
|
|
|
|
from contextlib import nullcontext
|
|
|
|
|
from typing import Any
|
|
|
|
|
from typing import Coroutine
|
|
|
|
|
@ -835,7 +836,7 @@ class GDBProcess(pwndbg.dbg_mod.Process):
|
|
|
|
|
# We don't need to bother communicating with the coroutine, as
|
|
|
|
|
# it doesn't yield anything we care about.
|
|
|
|
|
coroutine.send(None)
|
|
|
|
|
except StopIteration:
|
|
|
|
|
except (StopIteration, CancelledError):
|
|
|
|
|
# We're done.
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
@ -845,10 +846,25 @@ class GDBExecutionController(pwndbg.dbg_mod.ExecutionController):
|
|
|
|
|
async def single_step(self):
|
|
|
|
|
gdb.execute("si")
|
|
|
|
|
|
|
|
|
|
# Check if the program stopped because of the step we just took. If it
|
|
|
|
|
# stopped for any other reason, we should propagate a cancellation error
|
|
|
|
|
# to the task and give it a chance to respond.
|
|
|
|
|
if "It stopped after being stepped" not in gdb.execute("info program", to_string=True):
|
|
|
|
|
raise CancelledError()
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
async def cont(self, until: pwndbg.dbg_mod.StopPoint):
|
|
|
|
|
gdb.execute("continue")
|
|
|
|
|
|
|
|
|
|
# Check if the program stopped because of the breakpoint we were given,
|
|
|
|
|
# and, just like for the single step, propagate a cancellation error if
|
|
|
|
|
# it stopped for any other reason.
|
|
|
|
|
assert isinstance(until, GDBStopPoint)
|
|
|
|
|
if f"It stopped at breakpoint {until.inner.number}" not in gdb.execute(
|
|
|
|
|
"info program", to_string=True
|
|
|
|
|
):
|
|
|
|
|
raise CancelledError()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Like in LLDB, we only need a single instance of the execution controller.
|
|
|
|
|
EXECUTION_CONTROLLER = GDBExecutionController()
|
|
|
|
|
|