Fix and expand process driver debug messages (#3431)

pull/3416/head^2
Matt. 2 weeks ago committed by GitHub
parent 653f8666f1
commit 683c2de30d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -160,20 +160,11 @@ def _updates_scope_counter(target: str) -> Callable[[Callable[..., Any]], Any]:
def sub1(self: ProcessDriver, *args, **kwargs):
setattr(self, target, getattr(self, target) + 1)
try:
if self.debug:
print(
f"[*] ProcessDriver: self.{target} += 1 ({getattr(self, target)})",
file=sys.__stdout__,
)
self.debug_print(f"self.{target} += 1 ({getattr(self, target)})")
return fn(self, *args, **kwargs)
finally:
setattr(self, target, getattr(self, target) - 1)
if self.debug:
print(
f"[*] ProcessDriver: self.{target} -= 1 ({getattr(self, target)})",
file=sys.__stdout__,
)
self.debug_print(f"self.{target} -= 1 ({getattr(self, target)})")
return sub1
@ -215,12 +206,24 @@ class ProcessDriver:
self._in_run_until_next_stop = 0
self._in_run_coroutine = 0
def debug_print(self, *args, **kwargs) -> None:
if self.debug:
try:
print("[*] ProcessDriver: ", end="")
print(*args, **kwargs)
except BlockingIOError as e:
try:
# Try to inform the user of the error.
print(
f"[-] ProcessDriver: Error after printing {e.characters_written} characters in the previous debug message. Information may be missing."
)
except BlockingIOError:
pass
def has_process(self) -> bool:
"""
Whether there's an active process in this driver.
"""
if self.debug:
print(f"[-] ProcessDriver: has_process() for {self.process}")
return self.process is not None and self.process.GetState() != lldb.eStateConnected
def has_connection(self) -> bool:
@ -238,29 +241,23 @@ class ProcessDriver:
return
if self._in_run_until_next_stop > 0:
if self.debug:
print("[*] ProcessDriver: Sending Interrupt", file=sys.__stdout__)
if self._in_run_coroutine > 0:
self.debug_print("Sending interrupt and requesting current coroutine stop")
else:
self.debug_print("Sending interrupt")
# If we're in a coroutine, we should tell it to stop as soon as it gets out of _run_until_next_stop()
self._pending_cancellation = self._in_run_coroutine > 0
self.process.SendAsyncInterrupt()
elif self._hold_cancellation > 0 and not in_lldb_command_handler:
if self.debug:
print("[*] ProcessDriver: Pushing pending cancellation", file=sys.__stdout__)
self.debug_print("Pushing pending cancellation")
self._pending_cancellation = True
else:
if self.debug:
print(
"[*] ProcessDriver: Requesting cancellation immediately",
file=sys.__stdout__,
end="",
)
if self._hold_cancellation > 0:
print(" (forced by being in a command handler)", file=sys.__stdout__)
else:
print(file=sys.__stdout__)
self.debug_print(
"Requesting cancellation immediately",
"(forced by being in a command handler)" if self._hold_cancellation > 0 else "",
)
# This happens even if interrupts are suspended, if we're inside a
# command handler. We shouldn't interrupt LLDB until it starts
@ -280,22 +277,17 @@ class ProcessDriver:
self._hold_cancellation += 1
try:
if self.debug:
print(
"[*] ProcessDriver: Temporarily suspending cancellations", file=sys.__stdout__
)
self.debug_print("Temporarily suspending cancellations")
yield None
finally:
if self.debug:
print("[*] ProcessDriver: Resuming cancellations", file=sys.__stdout__)
self.debug_print("Resuming cancellations")
self._hold_cancellation -= 1
if self._hold_cancellation == 0 and self._pending_cancellation:
if self.debug:
print(
"[*] ProcessDriver: Executing pending cancellation", file=sys.__stdout__
)
self.debug_print(
"Executing pending cancellation",
)
self._pending_cancellation = False
if interrupt is None:
# The default action is to raise an exception in place.
@ -344,16 +336,16 @@ class ProcessDriver:
while True:
event = lldb.SBEvent()
if not self.listener.WaitForEvent(timeout_time, event):
if self.debug:
print(f"[-] ProcessDriver: Timed out after {timeout_time}s")
self.debug_print(
f"Timed out after {timeout_time}s",
)
timeout_time = timeout
# If the process isn't running, we should stop.
if not running:
if self.debug:
print(
"[-] ProcessDriver: Waited too long for process to start running, giving up"
)
self.debug_print(
"Waited too long for process to start running, giving up",
)
result = _PollResultTimedOut(last_event)
break
@ -363,9 +355,9 @@ class ProcessDriver:
if self.debug:
descr = lldb.SBStream()
if event.GetDescription(descr):
print(f"[-] ProcessDriver: {descr.GetData()}")
self.debug_print(descr.GetData())
else:
print(f"[!] ProcessDriver: No description for {event}")
self.debug_print(f"No description for {event}")
if lldb.SBTarget.EventIsTargetEvent(event):
if event.GetType() == lldb.SBTarget.eBroadcastBitModulesLoaded:
@ -409,8 +401,9 @@ class ProcessDriver:
):
# Nothing else for us to do here. Clear our internal
# references to the process, fire the exit event, and leave.
if self.debug:
print(f"[-] ProcessDriver: Process exited with state {new_state}")
self.debug_print(
f"Process exited with state {new_state}",
)
self.process = None
self.listener = None
@ -470,8 +463,7 @@ class ProcessDriver:
target.write(out.encode(sys.stdout.encoding, errors="backslashreplace"))
target.write(b"\n")
if self.debug:
print(f"[-] ProcessDriver: LLDB Command Status: {ret.GetStatus():#x}")
self.debug_print(f"LLDB Command finished with status: {ret.GetStatus():#x}")
# Only call _run_until_next_stop() if the command started the process.
start_expected = True
@ -524,32 +516,40 @@ class ProcessDriver:
"""
assert self.has_process(), "called run_coroutine() on a driver with no process"
self.debug_print("Coroutine: Starting")
exceptions: List[BaseException] = []
def queue_cancel():
self.debug_print("Coroutine: Queueing up user cancellation exception")
exceptions.append(UserCancelledError())
while True:
try:
if len(exceptions) == 0:
self.debug_print("Coroutine: Resuming")
step = coroutine.send(None)
else:
self.debug_print(f"Coroutine: Raising {type(exceptions[-1])}")
step = coroutine.throw(exceptions[-1])
# The coroutine has caught the exception. Continue running
# it as if nothing happened.
exceptions.pop()
except StopIteration:
# We got to the end of the coroutine. We're done.
self.debug_print("Coroutine: Ran to completion")
break
except CancelledError:
# We requested that the coroutine be cancelled, and it didn't
# override our decision. We're done.
self.debug_print("Coroutine: Cancelled")
break
# Being interrupted here would be bad for keeping the state of the
# process consistent.
with self.suspend_interrupts(interrupt=queue_cancel):
if isinstance(step, YieldSingleStep):
self.debug_print("Coroutine: Performing ExecutionController.single_step()")
# Pick the currently selected thread and step it forward by one
# instruction.
#
@ -577,6 +577,7 @@ class ProcessDriver:
continue
elif isinstance(step, YieldContinue):
self.debug_print("Coroutine: Performing ExecutionController.cont()")
threads_suspended = []
if step.selected_thread:
thread = self.process.GetSelectedThread()

Loading…
Cancel
Save