fix problem in close program and kill gdb
This commit is contained in:
parent
edec4eda3e
commit
4319b21559
@ -313,92 +313,135 @@ class GDBSession:
|
|||||||
|
|
||||||
def kill_program(self, timeout: int = DEFAULT_GDB_OPERATION_TIMEOUT) -> str:
|
def kill_program(self, timeout: int = DEFAULT_GDB_OPERATION_TIMEOUT) -> str:
|
||||||
logger.info(f"Sending 'kill' command to GDB with timeout {timeout}s.")
|
logger.info(f"Sending 'kill' command to GDB with timeout {timeout}s.")
|
||||||
try:
|
full_output = ""
|
||||||
return self.send_cmd("kill", expect_prompt=True, timeout=timeout)
|
if not self.child or not self.child.isalive():
|
||||||
except (TimeoutError, wexpect.EOF) as e: # EOF can happen if kill makes GDB quit or target was not running
|
|
||||||
logger.warning(f"Exception during 'kill' (might be normal if program not running or GDB exits): {e}")
|
|
||||||
return f"<kill_command_exception: {e}>"
|
|
||||||
except ConnectionError: # If GDB session died before kill
|
|
||||||
logger.warning("Cannot send 'kill', GDB session not active.")
|
logger.warning("Cannot send 'kill', GDB session not active.")
|
||||||
return "<kill_command_error_no_session>"
|
return "<kill_command_error_no_session>"
|
||||||
except Exception as e: # Other unexpected errors
|
try:
|
||||||
logger.error(f"Unexpected error during 'kill': {e}", exc_info=True)
|
self.child.sendline("kill")
|
||||||
return f"<kill_command_unexpected_error: {e}>"
|
full_output += "kill\n"
|
||||||
|
|
||||||
|
# Patterns for expect_list: 0=confirmation, 1=prompt, 2=EOF, 3=TIMEOUT
|
||||||
|
# Using re.compile for robustness with expect_list
|
||||||
|
patterns = [
|
||||||
|
re.compile(r"Kill the program being debugged\s*\?\s*\(y or n\)\s*"),
|
||||||
|
re.compile(re.escape(self.gdb_prompt)),
|
||||||
|
wexpect.EOF, # Questa è una costante, non una regex
|
||||||
|
wexpect.TIMEOUT # Questa è una costante
|
||||||
|
]
|
||||||
|
|
||||||
|
confirmation_timeout = max(5, timeout // 2)
|
||||||
|
logger.debug(f"Kill: Expecting confirmation or prompt with timeout {confirmation_timeout}s")
|
||||||
|
index = self.child.expect_list(patterns, timeout=confirmation_timeout)
|
||||||
|
output_segment = self.child.before if hasattr(self.child, 'before') else ""
|
||||||
|
full_output += output_segment
|
||||||
|
|
||||||
|
if index == 0:
|
||||||
|
logger.info("Kill: GDB asked for kill confirmation. Sending 'y'.")
|
||||||
|
self.child.sendline("y")
|
||||||
|
full_output += "y\n"
|
||||||
|
|
||||||
|
# Wait for the final prompt after 'y'
|
||||||
|
logger.debug(f"Kill: Expecting GDB prompt after 'y' with timeout {confirmation_timeout}s")
|
||||||
|
self.child.expect_exact(self.gdb_prompt, timeout=confirmation_timeout)
|
||||||
|
output_segment_after_y = self.child.before if hasattr(self.child, 'before') else ""
|
||||||
|
full_output += output_segment_after_y
|
||||||
|
logger.info("Kill: Kill confirmed and acknowledged by GDB.")
|
||||||
|
elif index == 1:
|
||||||
|
logger.info("Kill: GDB returned to prompt after 'kill' (program likely not running or no confirmation needed).")
|
||||||
|
elif index == 2:
|
||||||
|
logger.warning("Kill: GDB exited (EOF) during 'kill' command/confirmation.")
|
||||||
|
self.child = None
|
||||||
|
# Non sollevare EOF qui, ma segnala l'output
|
||||||
|
full_output += "<EOF reached during kill>"
|
||||||
|
elif index == 3:
|
||||||
|
logger.error(f"Kill: Timeout waiting for kill confirmation or prompt. Output so far: {output_segment.strip()}")
|
||||||
|
full_output += "<Timeout during kill confirmation>"
|
||||||
|
|
||||||
|
return full_output.strip()
|
||||||
|
|
||||||
|
except (TimeoutError, wexpect.EOF, ConnectionError) as e:
|
||||||
|
logger.warning(f"Kill: Exception during 'kill' (detail: {type(e).__name__} - {e}). Output: {full_output.strip()}")
|
||||||
|
return f"<kill_command_exception: {type(e).__name__} - {e}. Output: {full_output.strip()}>"
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Kill: Unexpected error during 'kill': {e}. Output: {full_output.strip()}", exc_info=True)
|
||||||
|
return f"<kill_command_unexpected_error: {e}. Output: {full_output.strip()}>"
|
||||||
|
|
||||||
def quit(self, timeout: int = DEFAULT_GDB_OPERATION_TIMEOUT) -> None:
|
def quit(self, timeout: int = DEFAULT_GDB_OPERATION_TIMEOUT) -> None:
|
||||||
"""
|
|
||||||
Sends 'quit' and 'y' (if needed) to GDB and closes the connection.
|
|
||||||
Uses the debugged version of quit.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
timeout: Timeout for the quit command sequence.
|
|
||||||
"""
|
|
||||||
if self.child and self.child.isalive():
|
if self.child and self.child.isalive():
|
||||||
logger.info(f"Attempting GDB quit sequence with timeout {timeout}s for phases.")
|
logger.info(f"Attempting GDB quit sequence with overall timeout {timeout}s.")
|
||||||
quit_ack_timeout = max(2, timeout // 3) # Timeout for "Quit anyway?" and for final exit check
|
phase_timeout = max(3, timeout // 3)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.child.sendline("quit")
|
self.child.sendline("quit")
|
||||||
logger.debug("Sent 'quit' command to GDB.")
|
logger.debug("Quit: Sent 'quit' command to GDB.")
|
||||||
|
|
||||||
# Check for "Quit anyway? (y or n)"
|
# Patterns for expect_list. EOF and TIMEOUT are special constants.
|
||||||
# We need to be careful with expect here, as it might consume the final prompt if GDB quits immediately.
|
# Regexes should be pre-compiled for reliability with expect_list if issues persist.
|
||||||
# A short, non-blocking read or a carefully crafted expect might be better.
|
expect_patterns_quit = [
|
||||||
# For simplicity, let's use expect with a short timeout for the confirmation.
|
re.compile(re.escape(self.gdb_prompt)), # 0: Prompt GDB
|
||||||
try:
|
re.compile(r"Quit anyway\s*\?\s*\(y or n\)\s*"), # 1: Conferma "Quit anyway?"
|
||||||
# Expect either the prompt (if quit fails or is rejected by GDB for some reason),
|
wexpect.EOF, # 2: EOF
|
||||||
# the confirmation, EOF, or timeout.
|
wexpect.TIMEOUT # 3: TIMEOUT
|
||||||
patterns = [self.gdb_prompt, r"Quit anyway\? \(y or n\) ", wexpect.EOF, wexpect.TIMEOUT]
|
]
|
||||||
index = self.child.expect_list(patterns, timeout=quit_ack_timeout)
|
|
||||||
|
logger.debug(f"Quit: Expecting one of the patterns with timeout {phase_timeout}s")
|
||||||
|
index = self.child.expect_list(expect_patterns_quit, timeout=phase_timeout)
|
||||||
|
|
||||||
response_after_quit = self.child.before if hasattr(self.child, 'before') else ""
|
response_after_quit = self.child.before if hasattr(self.child, 'before') else ""
|
||||||
logger.debug(f"GDB response after 'quit' (index {index}): {response_after_quit!r}")
|
logger.debug(f"Quit: GDB response after 'quit' (index {index}): {response_after_quit!r}")
|
||||||
|
|
||||||
if index == 1: # "Quit anyway?" matched
|
if index == 1: # "Quit anyway?" matched
|
||||||
logger.info("GDB asked for quit confirmation. Sending 'y'.")
|
logger.info("Quit: GDB asked for quit confirmation. Sending 'y'.")
|
||||||
self.child.sendline("y")
|
self.child.sendline("y")
|
||||||
# Wait for GDB to process 'y' and exit.
|
|
||||||
# Expect EOF or timeout. Prompt means quit failed.
|
|
||||||
try:
|
try:
|
||||||
final_index = self.child.expect_exact([self.gdb_prompt, wexpect.EOF, wexpect.TIMEOUT], timeout=quit_ack_timeout)
|
# After 'y', expect EOF or TIMEOUT (if GDB hangs). Prompt means quit failed.
|
||||||
|
final_expect_patterns_y = [
|
||||||
|
re.compile(re.escape(self.gdb_prompt)), # 0
|
||||||
|
wexpect.EOF, # 1
|
||||||
|
wexpect.TIMEOUT # 2
|
||||||
|
]
|
||||||
|
final_index = self.child.expect_list(final_expect_patterns_y, timeout=phase_timeout)
|
||||||
final_response = self.child.before if hasattr(self.child, 'before') else ""
|
final_response = self.child.before if hasattr(self.child, 'before') else ""
|
||||||
logger.debug(f"GDB response after 'y' (index {final_index}): {final_response!r}")
|
logger.debug(f"Quit: GDB response after 'y' (index {final_index}): {final_response!r}")
|
||||||
if final_index == 0: # Prompt again
|
if final_index == 0:
|
||||||
logger.warning("GDB did not quit after 'y' confirmation.")
|
logger.warning("Quit: GDB did not quit after 'y' confirmation and returned to prompt.")
|
||||||
|
elif final_index == 1:
|
||||||
|
logger.info("Quit: GDB exited after 'y' confirmation (EOF received).")
|
||||||
|
elif final_index == 2:
|
||||||
|
logger.info("Quit: Timeout waiting for GDB to exit after 'y'. Assuming exited or hung.")
|
||||||
except wexpect.TIMEOUT:
|
except wexpect.TIMEOUT:
|
||||||
logger.info("Timeout waiting for GDB to exit after 'y'. Assuming exited or hung.")
|
logger.info("Quit: Timeout (expecting EOF/Prompt) after 'y'. Assuming GDB exited or hung.")
|
||||||
except wexpect.EOF:
|
except wexpect.EOF:
|
||||||
logger.info("GDB exited after 'y' confirmation (EOF received).")
|
logger.info("Quit: GDB exited (EOF expecting EOF/Prompt) after 'y' confirmation.")
|
||||||
elif index == 0: # Prompt
|
elif index == 0:
|
||||||
logger.warning("GDB did not quit and returned to prompt. Target might still be running or an error occurred.")
|
logger.warning("Quit: GDB did not quit (returned to prompt, no confirmation asked).")
|
||||||
elif index == 2: # EOF
|
elif index == 2:
|
||||||
logger.info("GDB exited immediately after 'quit' command (EOF received).")
|
logger.info("Quit: GDB exited immediately after 'quit' command (EOF received, no confirmation).")
|
||||||
elif index == 3: # Timeout
|
elif index == 3:
|
||||||
logger.warning("Timeout waiting for GDB response after 'quit' command. GDB might be hung or exited cleanly without EOF.")
|
logger.warning("Quit: Timeout waiting for GDB response after 'quit' command (no confirmation). GDB might be hung or exited.")
|
||||||
|
|
||||||
except wexpect.TIMEOUT:
|
except wexpect.TIMEOUT:
|
||||||
logger.warning("Timeout waiting for GDB response after initial 'quit' command. Assuming GDB exited or hung.")
|
logger.warning("Quit: Timeout on initial expect after 'quit'. Assuming GDB exited or hung.")
|
||||||
except wexpect.EOF:
|
except wexpect.EOF:
|
||||||
logger.info("GDB exited (EOF) after initial 'quit' command (no confirmation needed).")
|
logger.info("Quit: EOF on initial expect after 'quit'. GDB exited.")
|
||||||
|
|
||||||
# Final check and cleanup
|
|
||||||
time.sleep(0.5) # Brief pause to allow process to terminate fully
|
|
||||||
if self.child and self.child.isalive():
|
|
||||||
logger.warning("GDB process is still alive after quit sequence. Attempting forceful close.")
|
|
||||||
self.child.close(force=True) # Use force=True as a last resort
|
|
||||||
else:
|
|
||||||
logger.info("GDB process appears to have exited successfully.")
|
|
||||||
|
|
||||||
except Exception as e_quit_main:
|
except Exception as e_quit_main:
|
||||||
logger.error(f"Exception during GDB quit sequence: {e_quit_main}", exc_info=True)
|
logger.error(f"Quit: Exception during GDB quit sequence: {e_quit_main}", exc_info=True)
|
||||||
if self.child and self.child.isalive():
|
|
||||||
try: self.child.close(force=True)
|
|
||||||
except Exception as e_close_final: logger.error(f"Error during final GDB child close: {e_close_final}")
|
|
||||||
finally:
|
finally:
|
||||||
|
if self.child and self.child.isalive():
|
||||||
|
logger.warning("Quit: GDB process is still alive after quit attempts. Closing connection.")
|
||||||
|
try:
|
||||||
|
self.child.close() # Rimosso force=True
|
||||||
|
except Exception as e_close_final:
|
||||||
|
logger.error(f"Quit: Error during final GDB child close: {e_close_final}", exc_info=True)
|
||||||
|
elif self.child and not self.child.isalive():
|
||||||
|
logger.info("Quit: GDB process was already not alive before final close call.")
|
||||||
|
|
||||||
self.child = None
|
self.child = None
|
||||||
self.gdb_script_sourced_successfully = False # Reset status
|
self.gdb_script_sourced_successfully = False
|
||||||
logger.info("GDB session resources (controller-side) released.")
|
logger.info("Quit: GDB session resources (controller-side) released.")
|
||||||
else:
|
else:
|
||||||
logger.info("GDB session quit called, but no active child process.")
|
logger.info("Quit: GDB session quit called, but no active child process.")
|
||||||
|
|
||||||
def is_alive(self) -> bool:
|
def is_alive(self) -> bool:
|
||||||
return self.child is not None and self.child.isalive()
|
return self.child is not None and self.child.isalive()
|
||||||
Loading…
Reference in New Issue
Block a user