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

Loading…
Cancel
Save