### Install pygdbmi Source: https://cs01.github.io/pygdbmi Install the pygdbmi library using pip. ```bash pip install pygdbmi ``` -------------------------------- ### Control GDB as a Subprocess Source: https://cs01.github.io/pygdbmi Instantiate `GdbController` to manage GDB as a subprocess. You can then write commands to GDB and receive structured responses. The `get_subprocess_cmd()` method shows the exact command used to start GDB. ```python from pygdbmi.gdbcontroller import GdbController from pprint import pprint # Start gdb process gdbmi = GdbController() print(gdbmi.get_subprocess_cmd()) # print actual command run as subprocess # Load binary a.out and get structured response response = gdbmi.write('-file-exec-file a.out') pprint(response) ``` -------------------------------- ### Spawn New GDB Subprocess Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Spawns a new GDB subprocess using the command specified during initialization. If a GDB process already exists, it will be terminated before a new one is started. Returns the PID of the new GDB process. ```python def spawn_new_gdb_subprocess(self): """Spawn a new gdb subprocess with the arguments supplied to the object during initialization. If gdb subprocess already exists, terminate it before spanwing a new one. Return int: gdb process id """ if self.gdb_process: logger.debug( "Killing current gdb subprocess (pid %d)" % self.gdb_process.pid ) self.exit() logger.debug(f'Launching gdb: {" ".join(self.command)}') # Use pipes to the standard streams self.gdb_process = subprocess.Popen( self.command, shell=False, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0, ) self.io_manager = IoManager( self.gdb_process.stdin, self.gdb_process.stdout, self.gdb_process.stderr, self.time_to_check_for_additional_output_sec, ) return self.gdb_process.pid ``` -------------------------------- ### Interact with GDB using MI Commands Source: https://cs01.github.io/pygdbmi Execute GDB commands, including Machine Interface (MI) commands, using the `write` method of `GdbController`. MI commands, which start with a '-', generally provide more structured output. ```python response = gdbmi.write('-break-insert main') # machine interface (MI) commands start with a '-' response = gdbmi.write('break main') # normal gdb commands work too, but the return value is slightly different response = gdbmi.write('-exec-run') response = gdbmi.write('run') response = gdbmi.write('-exec-next', timeout_sec=0.1) # the wait time can be modified from the default of 1 second response = gdbmi.write('next') response = gdbmi.write('next', raise_error_on_timeout=False) response = gdbmi.write('next', raise_error_on_timeout=True, timeout_sec=0.01) response = gdbmi.write('-exec-continue') ``` -------------------------------- ### Get GDB Response Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Retrieves a response from the GDB subprocess. ```APIDOC ## Get GDB Response ### Description Retrieves a response from the GDB subprocess. This method is a wrapper around `IoManager.get_gdb_response()`. ### Method get_gdb_response ### Endpoint None (This is a method of the GdbController class) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **timeout_sec** (float) - The maximum time in seconds to wait for a response. Defaults to `DEFAULT_GDB_TIMEOUT_SEC`. - **raise_error_on_timeout** (bool) - If True, raises an error if the timeout is reached before a response is received. Defaults to True. ### Request Example ```python # Assuming 'gdbmi' is an instance of GdbController response = gdbmi.get_gdb_response(timeout_sec=5.0) ``` ### Response #### Success Response (200) Returns the structured response from GDB. #### Response Example ```json { "msg-id": 1, "payload": [ { "type": "output", "payload": "(gdb) " } ] } ``` ``` -------------------------------- ### Get GDB Response Method Source: https://cs01.github.io/pygdbmi/api/iomanager Retrieves responses from GDB, blocking until a response is received or the timeout is reached. ```python def get_gdb_response( self, timeout_sec: float = DEFAULT_GDB_TIMEOUT_SEC, raise_error_on_timeout=True ): """Get response from GDB, and block while doing so. If GDB does not have any response ready to be read by timeout_sec, an exception is raised. Args: timeout_sec: Maximum time to wait for reponse. Must be >= 0. Will return after raise_error_on_timeout: Whether an exception should be raised if no response was found after timeout_sec Returns: List of parsed GDB responses, returned from gdbmiparser.parse_response, with the additional key 'stream' which is either 'stdout' or 'stderr' Raises: GdbTimeoutError: if response is not received within timeout_sec ValueError: if select returned unexpected file number """ if timeout_sec < 0: logger.warning("timeout_sec was negative, replacing with 0") timeout_sec = 0 if USING_WINDOWS: retval = self._get_responses_windows(timeout_sec) else: retval = self._get_responses_unix(timeout_sec) if not retval and raise_error_on_timeout: raise GdbTimeoutError( "Did not get response from gdb after %s seconds" % timeout_sec ) else: return retval ``` -------------------------------- ### Get GDB Response Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Retrieves a response from the GDB subprocess. This method forwards the call to the IoManager, allowing for configurable timeouts and error handling on timeout. ```python def get_gdb_response( self, timeout_sec: float = DEFAULT_GDB_TIMEOUT_SEC, raise_error_on_timeout=True, ): """Get gdb response. See IoManager.get_gdb_response() for details""" return self.io_manager.get_gdb_response(timeout_sec, raise_error_on_timeout) ``` -------------------------------- ### Get GDB Response with Timeout Source: https://cs01.github.io/pygdbmi/api/iomanager Retrieves responses from GDB, blocking until a response is available or a timeout occurs. Raises GdbTimeoutError if no response is received within the specified duration. Handles both Unix and Windows systems. ```python def get_gdb_response( self, timeout_sec: float = DEFAULT_GDB_TIMEOUT_SEC, raise_error_on_timeout=True ): """Get response from GDB, and block while doing so. If GDB does not have any response ready to be read by timeout_sec, an exception is raised. Args: timeout_sec: Maximum time to wait for reponse. Must be >= 0. Will return after raise_error_on_timeout: Whether an exception should be raised if no response was found after timeout_sec Returns: List of parsed GDB responses, returned from gdbmiparser.parse_response, with the additional key 'stream' which is either 'stdout' or 'stderr' Raises: GdbTimeoutError: if response is not received within timeout_sec ValueError: if select returned unexpected file number """ if timeout_sec < 0: logger.warning("timeout_sec was negative, replacing with 0") timeout_sec = 0 if USING_WINDOWS: retval = self._get_responses_windows(timeout_sec) else: retval = self._get_responses_unix(timeout_sec) if not retval and raise_error_on_timeout: raise GdbTimeoutError( "Did not get response from gdb after %s seconds" % timeout_sec ) else: return retval ``` -------------------------------- ### Constructor: __init__ Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Initializes a new GdbController object and spawns a GDB subprocess. ```APIDOC ## __init__(command=None, time_to_check_for_additional_output_sec=DEFAULT_TIME_TO_CHECK_FOR_ADDITIONAL_OUTPUT_SEC) ### Description Run gdb as a subprocess. Send commands and receive structured output. Create new object, along with a gdb subprocess. ### Parameters #### Request Body - **command** (Optional[List[str]]) - Optional - Command to run in shell to spawn new gdb subprocess. - **time_to_check_for_additional_output_sec** (float) - Optional - When parsing responses, wait this amount of time before exiting. If <= 0, full timeout time is used. ### Response #### Success Response (200) - **GdbController** (Object) - New GdbController object ``` -------------------------------- ### Run Linting with Nox Source: https://cs01.github.io/pygdbmi Apply linting to the project code using nox. ```bash nox -s lint ``` -------------------------------- ### GdbController Initialization Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Initializes the GdbController by running GDB as a subprocess and setting up communication channels. ```APIDOC ## GdbController Constructor ### Description Initializes the GdbController by running GDB as a subprocess and setting up communication channels. It can optionally take a custom command to launch GDB and a timeout for checking additional output. ### Method __init__ ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **command** (Optional[List[str]]) - Command to run in shell to spawn new gdb subprocess. Defaults to `DEFAULT_GDB_LAUNCH_COMMAND`. - **time_to_check_for_additional_output_sec** (float) - When parsing responses, wait this amount of time before exiting (exits before timeout is reached to save time). If <= 0, full timeout time is used. Defaults to `DEFAULT_TIME_TO_CHECK_FOR_ADDITIONAL_OUTPUT_SEC`. ### Request Example ```python from pygdbmi.gdbcontroller import GdbController gdbmi = GdbController() ``` ### Response #### Success Response (200) Returns a new GdbController object. #### Response Example ```json { "message": "GdbController initialized successfully" } ``` ``` -------------------------------- ### Constructor: __init__ Source: https://cs01.github.io/pygdbmi/api/iomanager Initializes the IoManager with stdin, stdout, and stderr file objects. This is used to manage I/O for file objects created before the class is instantiated. ```APIDOC ## __init__ ### Description Manage I/O for file objects created before calling this class. This can be useful if the gdb process is managed elsewhere, or if a pty is used. ### Parameters #### Path Parameters - **stdin** (io.BufferedWriter) - Required - The standard input stream for GDB. - **stdout** (io.BufferedReader) - Required - The standard output stream for GDB. - **stderr** (Optional[io.BufferedReader]) - Optional - The standard error stream for GDB. - **time_to_check_for_additional_output_sec** (float) - Optional - Time to check for additional output. ``` -------------------------------- ### Run Tests with Nox Source: https://cs01.github.io/pygdbmi Execute the test suite using nox. ```bash nox -s tests ``` -------------------------------- ### Initialize GdbController Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Initializes the GdbController to run GDB as a subprocess. It optionally takes a command to launch GDB and a timeout for checking output. Ensure GDB is in your PATH or provide an absolute path. ```python class GdbController: def __init__( self, command: Optional[List[str]] = None, time_to_check_for_additional_output_sec=DEFAULT_TIME_TO_CHECK_FOR_ADDITIONAL_OUTPUT_SEC, ): """ Run gdb as a subprocess. Send commands and receive structured output. Create new object, along with a gdb subprocess Args: command: Command to run in shell to spawn new gdb subprocess time_to_check_for_additional_output_sec: When parsing responses, wait this amout of time before exiting (exits before timeout is reached to save time). If <= 0, full timeout time is used. Returns: New GdbController object """ if command is None: command = DEFAULT_GDB_LAUNCH_COMMAND if not any([("--interpreter=mi" in c) for c in command]): logger.warning( "Adding `--interpreter=mi3` (or similar) is recommended to get structured output. " + "See https://sourceware.org/gdb/onlinedocs/gdb/Mode-Options.html#Mode-Options." ) self.abs_gdb_path = None # abs path to gdb executable self.command = command # type: List[str] self.time_to_check_for_additional_output_sec = time_to_check_for_additional_output_sec self.gdb_process = None self._allow_overwrite_timeout_times = self.time_to_check_for_additional_output_sec > 0 gdb_path = command[0] if not gdb_path: raise ValueError("a valid path to gdb must be specified") else: abs_gdb_path = find_executable(gdb_path) if abs_gdb_path is None: raise ValueError( 'gdb executable could not be resolved from "%s"' % gdb_path ) else: self.abs_gdb_path = abs_gdb_path self.spawn_new_gdb_subprocess() ``` -------------------------------- ### Run GDB with Machine Interface Source: https://cs01.github.io/pygdbmi To obtain machine interface output from GDB, launch GDB with the `--interpreter=mi2` flag. ```bash gdb --interpreter=mi2 ``` -------------------------------- ### Initialize GdbController Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Initializes a new GdbController instance and spawns a GDB subprocess. It validates the GDB executable path and warns if the MI interpreter flag is missing. ```python def __init__( self, command: Optional[List[str]] = None, time_to_check_for_additional_output_sec=DEFAULT_TIME_TO_CHECK_FOR_ADDITIONAL_OUTPUT_SEC, ): """ Run gdb as a subprocess. Send commands and receive structured output. Create new object, along with a gdb subprocess Args: command: Command to run in shell to spawn new gdb subprocess time_to_check_for_additional_output_sec: When parsing responses, wait this amout of time before exiting (exits before timeout is reached to save time). If <= 0, full timeout time is used. Returns: New GdbController object """ if command is None: command = DEFAULT_GDB_LAUNCH_COMMAND if not any([("--interpreter=mi" in c) for c in command]): logger.warning( "Adding `--interpreter=mi3` (or similar) is recommended to get structured output. " + "See https://sourceware.org/gdb/onlinedocs/gdb/Mode-Options.html#Mode-Options." ) self.abs_gdb_path = None # abs path to gdb executable self.command = command # type: List[str] self.time_to_check_for_additional_output_sec = ( time_to_check_for_additional_output_sec ) self.gdb_process = None self._allow_overwrite_timeout_times = ( self.time_to_check_for_additional_output_sec > 0 ) gdb_path = command[0] if not gdb_path: raise ValueError("a valid path to gdb must be specified") else: abs_gdb_path = find_executable(gdb_path) if abs_gdb_path is None: raise ValueError( 'gdb executable could not be resolved from "%s"' % gdb_path ) else: self.abs_gdb_path = abs_gdb_path self.spawn_new_gdb_subprocess() ``` -------------------------------- ### Method: spawn_new_gdb_subprocess Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Spawns a new GDB subprocess using the initialized command. ```APIDOC ## spawn_new_gdb_subprocess() ### Description Spawn a new gdb subprocess with the arguments supplied to the object during initialization. If gdb subprocess already exists, terminate it before spawning a new one. ### Response #### Success Response (200) - **pid** (int) - The process ID of the newly spawned gdb subprocess. ``` -------------------------------- ### List Available Nox Tasks Source: https://cs01.github.io/pygdbmi Use this command to see all the automation tasks available with nox. ```bash nox -l ``` -------------------------------- ### GDBController.write Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Sends a command to the GDB process and optionally waits for a response. ```APIDOC ## write(mi_cmd_to_write, timeout_sec=DEFAULT_GDB_TIMEOUT_SEC, raise_error_on_timeout=True, read_response=True) ### Description Writes a command to the GDB process. This method acts as a wrapper for the underlying IoManager.write() method. ### Parameters - **mi_cmd_to_write** (Union[str, List[str]]) - Required - The GDB/MI command or list of commands to send. - **timeout_sec** (float) - Optional - Time in seconds to wait for a response before timing out. - **raise_error_on_timeout** (bool) - Optional - Whether to raise an exception if the command times out. - **read_response** (bool) - Optional - Whether to read and return the response from GDB. ``` -------------------------------- ### IoManager Class Initialization Source: https://cs01.github.io/pygdbmi/api/iomanager Initializes the IoManager with GDB's I/O streams. It sets up file descriptors and read/write lists, and configures streams for non-blocking operations. ```APIDOC ## IoManager ### Description Manages I/O for file objects created before calling this class. This can be useful if the gdb process is managed elsewhere, or if a pty is used. ### Method __init__ ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **stdin** (io.BufferedWriter) - Required - The standard input stream for GDB. - **stdout** (io.BufferedReader) - Required - The standard output stream from GDB. - **stderr** (Optional[io.BufferedReader]) - Optional - The standard error stream from GDB. - **time_to_check_for_additional_output_sec** (float) - Optional - The time in seconds to check for additional output. Defaults to DEFAULT_TIME_TO_CHECK_FOR_ADDITIONAL_OUTPUT_SEC. ### Request Example ```python # Example usage (assuming stdin, stdout, stderr are already set up) io_manager = IoManager(stdin, stdout, stderr) ``` ### Response None (initializes the object) ``` -------------------------------- ### Initialize IoManager with File Objects Source: https://cs01.github.io/pygdbmi/api/iomanager Initializes the IoManager with stdin, stdout, and stderr file objects. Ensures streams are non-blocking for efficient I/O operations. Useful when GDB process is managed externally or when using a pseudo-terminal. ```python def __init__( self, stdin: io.BufferedWriter, stdout: io.BufferedReader, stderr: Optional[io.BufferedReader], time_to_check_for_additional_output_sec=DEFAULT_TIME_TO_CHECK_FOR_ADDITIONAL_OUTPUT_SEC, ): """ Manage I/O for file objects created before calling this class This can be useful if the gdb process is managed elsewhere, or if a pty is used. """ self.stdin = stdin self.stdout = stdout self.stderr = stderr self.stdin_fileno = self.stdin.fileno() self.stdout_fileno = self.stdout.fileno() self.stderr_fileno = self.stderr.fileno() if self.stderr else -1 self.read_list: List[int] = [] if self.stdout: self.read_list.append(self.stdout_fileno) self.write_list = [self.stdin_fileno] self._incomplete_output: Dict[str, Any] = {"stdout": None, "stderr": None} self.time_to_check_for_additional_output_sec = time_to_check_for_additional_output_sec self._allow_overwrite_timeout_times = self.time_to_check_for_additional_output_sec > 0 make_non_blocking(self.stdout) if self.stderr: make_non_blocking(self.stderr) ``` -------------------------------- ### Spawn New GDB Subprocess Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Spawns a new GDB subprocess, terminating any existing one. ```APIDOC ## Spawn New GDB Subprocess ### Description Spawns a new GDB subprocess with the arguments supplied to the object during initialization. If a GDB subprocess already exists, it is terminated before spawning a new one. ### Method spawn_new_gdb_subprocess ### Endpoint None (This is a method of the GdbController class) ### Parameters None ### Request Example ```python # Assuming 'gdbmi' is an instance of GdbController gdbmi.spawn_new_gdb_subprocess() ``` ### Response #### Success Response (200) Returns the process ID (PID) of the newly spawned GDB process. #### Response Example ```json { "pid": 12345 } ``` ``` -------------------------------- ### Spawn GDB Subprocess Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Spawns a new GDB subprocess using the configured command. If a process is already running, it terminates the existing one first. ```python def spawn_new_gdb_subprocess(self): """Spawn a new gdb subprocess with the arguments supplied to the object during initialization. If gdb subprocess already exists, terminate it before spanwing a new one. Return int: gdb process id """ if self.gdb_process: logger.debug( "Killing current gdb subprocess (pid %d)" % self.gdb_process.pid ) self.exit() logger.debug(f'Launching gdb: {" ".join(self.command)}') # Use pipes to the standard streams self.gdb_process = subprocess.Popen( self.command, shell=False, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0, ) self.io_manager = IoManager( self.gdb_process.stdin, self.gdb_process.stdout, self.gdb_process.stderr, self.time_to_check_for_additional_output_sec, ) return self.gdb_process.pid ``` -------------------------------- ### Handle GDB Output Ready Event Source: https://cs01.github.io/pygdbmi/api/iomanager Processes file descriptors that are ready for output. Writes commands to GDB's stdin and flushes the buffer to ensure GDB receives the data. Logs an error for unexpected file descriptors. ```python _, outputready, _ = select.select([], self.write_list, [], timeout_sec) for fileno in outputready: if fileno == self.stdin_fileno: # ready to write self.stdin.write(mi_cmd_to_write_nl.encode()) # type: ignore # must flush, otherwise gdb won't realize there is data # to evaluate, and we won't get a response self.stdin.flush() # type: ignore else: logger.error("got unexpected fileno %d" % fileno) if read_response is True: return self.get_gdb_response( timeout_sec=timeout_sec, raise_error_on_timeout=raise_error_on_timeout ) else: return [] ``` -------------------------------- ### Write Command to GDB Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Use this method to write a command to GDB. It handles timeouts and response reading. See IoManager.write() for more details. ```python def write( self, mi_cmd_to_write: Union[str, List[str]], timeout_sec=DEFAULT_GDB_TIMEOUT_SEC, raise_error_on_timeout: bool = True, read_response: bool = True, ): """Write command to gdb. See IoManager.write() for details""" return self.io_manager.write( mi_cmd_to_write, timeout_sec, raise_error_on_timeout, read_response ) ``` -------------------------------- ### Method: get_gdb_response Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Retrieves the response from the GDB subprocess. ```APIDOC ## get_gdb_response(timeout_sec=DEFAULT_GDB_TIMEOUT_SEC, raise_error_on_timeout=True) ### Description Get gdb response. See IoManager.get_gdb_response() for details. ### Parameters #### Query Parameters - **timeout_sec** (float) - Optional - Timeout in seconds for the response. - **raise_error_on_timeout** (bool) - Optional - Whether to raise an error if the timeout is reached. ``` -------------------------------- ### Continue Execution and Exit GDB Source: https://cs01.github.io/pygdbmi Continue GDB execution using the `continue` command and exit the GDB subprocess using the `exit` method. ```python response = gdbmi.write('continue') response = gdbmi.exit() ``` -------------------------------- ### Write Command to GDB Process Source: https://cs01.github.io/pygdbmi/api/iomanager Use this method to send commands to GDB. It can handle string or list inputs for commands and optionally read responses with configurable timeouts. Ensure GDB subprocess is properly initialized before use. ```python def write( self, mi_cmd_to_write: Union[str, List[str]], timeout_sec=DEFAULT_GDB_TIMEOUT_SEC, raise_error_on_timeout: bool = True, read_response: bool = True, ): """Write to gdb process. Block while parsing responses from gdb for a maximum of timeout_sec. Args: mi_cmd_to_write: String to write to gdb. If list, it is joined by newlines. timeout_sec: Maximum number of seconds to wait for response before exiting. Must be >= 0. raise_error_on_timeout: If read_response is True, raise error if no response is received read_response: Block and read response. If there is a separate thread running, this can be false, and the reading thread read the output. Returns: List of parsed gdb responses if read_response is True, otherwise [] Raises: TypeError: if mi_cmd_to_write is not valid """ # self.verify_valid_gdb_subprocess() if timeout_sec < 0: logger.warning("timeout_sec was negative, replacing with 0") timeout_sec = 0 # Ensure proper type of the mi command if isinstance(mi_cmd_to_write, str): mi_cmd_to_write_str = mi_cmd_to_write elif isinstance(mi_cmd_to_write, list): mi_cmd_to_write_str = "\n".join(mi_cmd_to_write) else: raise TypeError( "The gdb mi command must a be str or list. Got " + str(type(mi_cmd_to_write)) ) logger.debug("writing: %s", mi_cmd_to_write) if not mi_cmd_to_write_str.endswith("\n"): mi_cmd_to_write_nl = mi_cmd_to_write_str + "\n" else: mi_cmd_to_write_nl = mi_cmd_to_write_str if USING_WINDOWS: # select not implemented in windows for pipes # assume it's always ready outputready = [self.stdin_fileno] else: _, outputready, _ = select.select([], self.write_list, [], timeout_sec) for fileno in outputready: if fileno == self.stdin_fileno: # ready to write self.stdin.write(mi_cmd_to_write_nl.encode()) # type: ignore # must flush, otherwise gdb won't realize there is data # to evaluate, and we won't get a response self.stdin.flush() # type: ignore else: logger.warning("got unexpected fileno %d" % fileno) if read_response is True: return self.get_gdb_response( timeout_sec=timeout_sec, raise_error_on_timeout=raise_error_on_timeout ) else: return [] ``` -------------------------------- ### Method: exit Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Terminates the active GDB process. ```APIDOC ## exit() ### Description Terminate the current gdb process and clean up resources. ### Response #### Success Response (200) - **None** (null) - Returns None ``` -------------------------------- ### write(mi_cmd_to_write, timeout_sec, raise_error_on_timeout, read_response) Source: https://cs01.github.io/pygdbmi/api/iomanager Writes a command to the GDB process and optionally reads the response. This method blocks until a response is received or a timeout occurs. ```APIDOC ## write(mi_cmd_to_write, timeout_sec, raise_error_on_timeout, read_response) ### Description Write to gdb process. Block while parsing responses from gdb for a maximum of timeout_sec. ### Method POST (conceptual, as this is a method within a class) ### Endpoint N/A (Class method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **mi_cmd_to_write** (Union[str, List[str]]) - Required - String to write to gdb. If list, it is joined by newlines. - **timeout_sec** (float) - Optional - Maximum number of seconds to wait for response before exiting. Must be >= 0. Defaults to `DEFAULT_GDB_TIMEOUT_SEC`. - **raise_error_on_timeout** (bool) - Optional - If `read_response` is True, raise error if no response is received. Defaults to `True`. - **read_response** (bool) - Optional - Block and read response. If there is a separate thread running, this can be false, and the reading thread read the output. Defaults to `True`. ### Request Example ```json { "mi_cmd_to_write": ["-file-exec-and-symbols", "/path/to/executable"], "timeout_sec": 5.0, "read_response": true } ``` ### Response #### Success Response (200) - **(List[dict])** - List of parsed gdb responses if `read_response` is True, otherwise an empty list `[]`. #### Response Example ```json [ { "type": "result", "payload": { "msg": "done" } } ] ``` ### Error Handling - **TypeError**: Raised if `mi_cmd_to_write` is not a string or a list of strings. ``` -------------------------------- ### Make File Object Non-Blocking (Windows) Source: https://cs01.github.io/pygdbmi/api/iomanager Configures a file object to be non-blocking on Windows systems by adjusting named pipe handle state. Requires specific Windows API calls. ```python def make_non_blocking(file_obj: io.IOBase): """make file object non-blocking Windows doesn't have the fcntl module, but someone on stack overflow supplied this code as an answer, and it works http://stackoverflow.com/a/34504971/2893090""" if USING_WINDOWS: LPDWORD = POINTER(DWORD) PIPE_NOWAIT = wintypes.DWORD(0x00000001) SetNamedPipeHandleState = windll.kernel32.SetNamedPipeHandleState SetNamedPipeHandleState.argtypes = [HANDLE, LPDWORD, LPDWORD, LPDWORD] SetNamedPipeHandleState.restype = BOOL h = msvcrt.get_osfhandle(file_obj.fileno()) # type: ignore res = windll.kernel32.SetNamedPipeHandleState(h, byref(PIPE_NOWAIT), None, None) if res == 0: raise ValueError(WinError()) ``` -------------------------------- ### Windows Response Handling Source: https://cs01.github.io/pygdbmi/api/iomanager Handles GDB response retrieval on Windows systems using a polling loop, as select is not supported. ```python def _get_responses_windows(self, timeout_sec): """Get responses on windows. Assume no support for select and use a while loop.""" timeout_time_sec = time.time() + timeout_sec responses = [] while True: responses_list = [] try: self.stdout.flush() raw_output = self.stdout.readline().replace(b"\r", b"\n") responses_list = self._get_responses_list(raw_output, "stdout") except IOError: pass try: self.stderr.flush() raw_output = self.stderr.readline().replace(b"\r", b"\n") responses_list += self._get_responses_list(raw_output, "stderr") except IOError: pass responses += responses_list if timeout_sec == 0: break elif responses_list and self._allow_overwrite_timeout_times: timeout_time_sec = min( time.time() + self.time_to_check_for_additional_output_sec, timeout_time_sec, ) elif time.time() > timeout_time_sec: break return responses ``` -------------------------------- ### Write Command to GDB Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Writes a command to the GDB subprocess and optionally reads the response. ```APIDOC ## Write Command to GDB ### Description Writes a command to GDB. This method is a wrapper around `IoManager.write()`. ### Method write ### Endpoint None (This is a method of the GdbController class) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **mi_cmd_to_write** (Union[str, List[str]]) - The GDB/MI command(s) to write. - **timeout_sec** (float) - The maximum time in seconds to wait for a response. Defaults to `DEFAULT_GDB_TIMEOUT_SEC`. - **raise_error_on_timeout** (bool) - If True, raises an error if the timeout is reached before a response is received. Defaults to True. - **read_response** (bool) - If True, reads and returns the response from GDB. Defaults to True. ### Request Example ```python # Assuming 'gdbmi' is an instance of GdbController response = gdbmi.write("-file-exec-and-symbols /bin/ls") ``` ### Response #### Success Response (200) Returns the response from GDB if `read_response` is True, otherwise returns None. #### Response Example ```json { "msg-id": 2, "payload": [ { "type": "result", "payload": { "symtab-file": "/bin/ls" } } ] } ``` ``` -------------------------------- ### Write Command to GDB Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Writes a command to the GDB subprocess. This method delegates to IoManager.write, supporting various command formats and options for reading responses and handling timeouts. ```python def write( self, mi_cmd_to_write: Union[str, List[str]], timeout_sec=DEFAULT_GDB_TIMEOUT_SEC, raise_error_on_timeout: bool = True, read_response: bool = True, ): """Write command to gdb. See IoManager.write() for details""" return self.io_manager.write( mi_cmd_to_write, timeout_sec, raise_error_on_timeout, read_response ) ``` -------------------------------- ### Read GDB Responses on Unix-like Systems Source: https://cs01.github.io/pygdbmi/api/iomanager Uses `select` to efficiently wait for and read output from GDB's stdout and stderr streams on Unix-like systems. Handles incomplete responses and timeouts. ```python def _get_responses_unix(self, timeout_sec): """Get responses on unix-like system. Use select to wait for output.""" timeout_time_sec = time.time() + timeout_sec responses = [] while True: select_timeout = timeout_time_sec - time.time() if select_timeout <= 0: select_timeout = 0 events, _, _ = select.select(self.read_list, [], [], select_timeout) responses_list = None # to avoid infinite loop if using Python 2 for fileno in events: # new data is ready to read if fileno == self.stdout_fileno: self.stdout.flush() raw_output = self.stdout.read() stream = "stdout" elif fileno == self.stderr_fileno: self.stderr.flush() raw_output = self.stderr.read() stream = "stderr" else: raise ValueError( "Developer error. Got unexpected file number %d" % fileno ) responses_list = self._get_responses_list(raw_output, stream) responses += responses_list if timeout_sec == 0: # just exit immediately break elif responses_list and self._allow_overwrite_timeout_times: # update timeout time to potentially be closer to now to avoid lengthy wait times when nothing is being output by gdb timeout_time_sec = min( time.time() + self.time_to_check_for_additional_output_sec, timeout_time_sec, ) elif time.time() > timeout_time_sec: break return responses ``` -------------------------------- ### Write Commands to GDB Process Source: https://cs01.github.io/pygdbmi/api/iomanager Writes MI commands to the GDB process, optionally reading and parsing responses. Handles command formatting and timeouts, with specific logic for Windows. ```python def write( self, mi_cmd_to_write: Union[str, List[str]], timeout_sec=DEFAULT_GDB_TIMEOUT_SEC, raise_error_on_timeout: bool = True, read_response: bool = True, ): """Write to gdb process. Block while parsing responses from gdb for a maximum of timeout_sec. Args: mi_cmd_to_write: String to write to gdb. If list, it is joined by newlines. timeout_sec: Maximum number of seconds to wait for response before exiting. Must be >= 0. raise_error_on_timeout: If read_response is True, raise error if no response is received read_response: Block and read response. If there is a separate thread running, this can be false, and the reading thread read the output. Returns: List of parsed gdb responses if read_response is True, otherwise [] Raises: TypeError: if mi_cmd_to_write is not valid """ # self.verify_valid_gdb_subprocess() if timeout_sec < 0: logger.warning("timeout_sec was negative, replacing with 0") timeout_sec = 0 # Ensure proper type of the mi command if isinstance(mi_cmd_to_write, str): mi_cmd_to_write_str = mi_cmd_to_write elif isinstance(mi_cmd_to_write, list): mi_cmd_to_write_str = "\n".join(mi_cmd_to_write) else: raise TypeError( "The gdb mi command must a be str or list. Got " + str(type(mi_cmd_to_write)) ) logger.debug("writing: %s", mi_cmd_to_write) if not mi_cmd_to_write_str.endswith("\n"): mi_cmd_to_write_nl = mi_cmd_to_write_str + "\n" else: mi_cmd_to_write_nl = mi_cmd_to_write_str if USING_WINDOWS: # select not implemented in windows for pipes # assume it's always ready outputready = [self.stdin_fileno] else: ``` -------------------------------- ### parse_response(gdb_mi_text) Source: https://cs01.github.io/pygdbmi/api/gdbmiparser Parses a raw string of GDB MI output and converts it into a structured dictionary containing the type, message, payload, and token. ```APIDOC ## parse_response(gdb_mi_text) ### Description Parses gdb mi text and turns it into a dictionary. This function identifies the type of GDB MI output (notify, result, console, log, target, or output) and extracts relevant data. ### Parameters - **gdb_mi_text** (str) - Required - String output from gdb ### Response - **type** (str) - The category of the GDB MI output - **message** (str/null) - The message associated with the output - **payload** (dict/str/null) - The structured data or content of the output - **token** (str/null) - The GDB token associated with the command ### Response Example { "type": "result", "message": "done", "payload": {"value": "1"}, "token": "1" } ``` -------------------------------- ### Retrieve GDB Response Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Fetches the response from the GDB subprocess via the IoManager. ```python def get_gdb_response( self, timeout_sec: float = DEFAULT_GDB_TIMEOUT_SEC, raise_error_on_timeout=True ): """Get gdb response. See IoManager.get_gdb_response() for details""" return self.io_manager.get_gdb_response(timeout_sec, raise_error_on_timeout) ``` -------------------------------- ### make_non_blocking(file_obj) Source: https://cs01.github.io/pygdbmi/api/iomanager This function makes a given file object non-blocking. It includes platform-specific implementations for Windows and other operating systems. ```APIDOC ## make_non_blocking(file_obj) ### Description Makes a file object non-blocking. This is crucial for preventing read operations from blocking the program when no data is available. ### Method Function call ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```python import io def make_non_blocking(file_obj: io.IOBase): # ... implementation details ... pass # Example usage (assuming file_obj is an open file handle) # make_non_blocking(my_file_handle) ``` ### Response #### Success Response (None) This function does not return a value upon success. #### Response Example None ### Error Handling Raises `ValueError` on Windows if `SetNamedPipeHandleState` fails. ``` -------------------------------- ### response_is_finished(gdb_mi_text) Source: https://cs01.github.io/pygdbmi/api/gdbmiparser Checks if the provided GDB MI output string indicates the end of a response. ```APIDOC ## response_is_finished(gdb_mi_text) ### Description Return true if the gdb mi response is ending. ### Parameters - **gdb_mi_text** (str) - Required - String output from gdb ### Response - **result** (bool) - True if gdb response is finished, False otherwise. ``` -------------------------------- ### Make File Object Non-Blocking (Unix-like) Source: https://cs01.github.io/pygdbmi/api/iomanager Sets the file status flag (F_SETFL) on pipes to non-blocking using the fcntl module. This prevents read operations from blocking when no new data is available. ```python else: # Set the file status flag (F_SETFL) on the pipes to be non-blocking # so we can attempt to read from a pipe with no new data without locking # the program up fcntl.fcntl(file_obj, fcntl.F_SETFL, os.O_NONBLOCK) ``` -------------------------------- ### IoManager Class Definition Source: https://cs01.github.io/pygdbmi/api/iomanager The IoManager class manages file objects for GDB communication. It initializes non-blocking I/O for stdout and stderr streams. ```python class IoManager: def __init__( self, stdin: io.BufferedWriter, stdout: io.BufferedReader, stderr: Optional[io.BufferedReader], time_to_check_for_additional_output_sec=DEFAULT_TIME_TO_CHECK_FOR_ADDITIONAL_OUTPUT_SEC, ): """ Manage I/O for file objects created before calling this class This can be useful if the gdb process is managed elsewhere, or if a pty is used. """ self.stdin = stdin self.stdout = stdout self.stderr = stderr self.stdin_fileno = self.stdin.fileno() self.stdout_fileno = self.stdout.fileno() self.stderr_fileno = self.stderr.fileno() if self.stderr else -1 self.read_list: List[int] = [] if self.stdout: self.read_list.append(self.stdout_fileno) self.write_list = [self.stdin_fileno] self._incomplete_output: Dict[str, Any] = {"stdout": None, "stderr": None} self.time_to_check_for_additional_output_sec = ( time_to_check_for_additional_output_sec ) self._allow_overwrite_timeout_times = ( self.time_to_check_for_additional_output_sec > 0 ) make_non_blocking(self.stdout) if self.stderr: make_non_blocking(self.stderr) ``` -------------------------------- ### Check GDB MI Response Completion Source: https://cs01.github.io/pygdbmi/api/gdbmiparser Determines if the provided GDB MI string indicates the end of a response. ```python def response_is_finished(gdb_mi_text: str) -> bool: """Return true if the gdb mi response is ending Args: gdb_mi_text: String output from gdb Returns: True if gdb response is finished """ if _GDB_MI_RESPONSE_FINISHED_RE.match(gdb_mi_text): return True else: return False ``` -------------------------------- ### Parse GDB/MI Output String Source: https://cs01.github.io/pygdbmi Use `pygdbmi.gdbmiparser.parse_response` to convert GDB/MI output strings into JSON-serializable Python dictionaries. This is useful for processing debugger output programmatically. ```python from pygdbmi import gdbmiparser from pprint import pprint response = gdbmi_parser.parse_response('^done,bkpt={number="1",type="breakpoint",disp="keep", enabled="y",addr="0x08048564",func="main",file="myprog.c",fullname="/home/myprog.c",line="68",thread-groups=["i1"],times="0"') pprint(response) ``` -------------------------------- ### Terminate GDB Process Source: https://cs01.github.io/pygdbmi/api/gdbcontroller Terminates the GDB subprocess. ```APIDOC ## Terminate GDB Process ### Description Terminates the GDB subprocess. ### Method exit ### Endpoint None (This is a method of the GdbController class) ### Parameters None ### Request Example ```python # Assuming 'gdbmi' is an instance of GdbController gdbmi.exit() ``` ### Response #### Success Response (200) Returns None. #### Response Example ```json { "message": "GDB process terminated" } ``` ``` -------------------------------- ### Method: get_gdb_response Source: https://cs01.github.io/pygdbmi/api/iomanager Blocks while waiting for a response from GDB. If no response is received within the specified timeout, an exception is raised. ```APIDOC ## get_gdb_response ### Description Get response from GDB, and block while doing so. If GDB does not have any response ready to be read by timeout_sec, an exception is raised. ### Parameters #### Query Parameters - **timeout_sec** (float) - Optional - Maximum time to wait for response. Must be >= 0. Default: DEFAULT_GDB_TIMEOUT_SEC. - **raise_error_on_timeout** (bool) - Optional - Whether an exception should be raised if no response was found after timeout_sec. Default: True. ### Response - **Returns** (List) - List of parsed GDB responses, returned from gdbmiparser.parse_response, with the additional key 'stream' which is either 'stdout' or 'stderr'. ### Errors - **GdbTimeoutError**: Raised if response is not received within timeout_sec. - **ValueError**: Raised if select returned unexpected file number. ```