Skip to content

gdbcontroller

This module defines the GdbController class which runs gdb as a subprocess and can write to it and read from it to get structured output.

GdbController

Source code in pygdbmi/gdbcontroller.py
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
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()

    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

    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)

    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
        )

    def exit(self) -> None:
        """Terminate gdb process"""
        if self.gdb_process:
            self.gdb_process.terminate()
            self.gdb_process.communicate()
        self.gdb_process = None
        return None

__init__(command=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

Parameters:

Name Type Description Default
command Optional[List[str]]

Command to run in shell to spawn new gdb subprocess

None
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.

DEFAULT_TIME_TO_CHECK_FOR_ADDITIONAL_OUTPUT_SEC

Returns:

Type Description

New GdbController object

Source code in pygdbmi/gdbcontroller.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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()

exit()

Terminate gdb process

Source code in pygdbmi/gdbcontroller.py
120
121
122
123
124
125
126
def exit(self) -> None:
    """Terminate gdb process"""
    if self.gdb_process:
        self.gdb_process.terminate()
        self.gdb_process.communicate()
    self.gdb_process = None
    return None

get_gdb_response(timeout_sec=DEFAULT_GDB_TIMEOUT_SEC, raise_error_on_timeout=True)

Get gdb response. See IoManager.get_gdb_response() for details

Source code in pygdbmi/gdbcontroller.py
102
103
104
105
106
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)

spawn_new_gdb_subprocess()

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

Source code in pygdbmi/gdbcontroller.py
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
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

write(mi_cmd_to_write, timeout_sec=DEFAULT_GDB_TIMEOUT_SEC, raise_error_on_timeout=True, read_response=True)

Write command to gdb. See IoManager.write() for details

Source code in pygdbmi/gdbcontroller.py
108
109
110
111
112
113
114
115
116
117
118
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
    )