pygdbmi
pygdbmi is a Python library that parses GDB's machine interface (MI) output into structured data (Python dictionaries) that are JSON serializable. It also provides a class, `GdbController`, to control GDB as a subprocess, allowing programmatic interaction for backend development of GDB frontends. It supports cross-platform debugging on Linux, macOS, and Windows. The current stable version is 0.11.0.0, with releases occurring periodically to introduce new features, fix bugs, and address breaking changes.
Warnings
- breaking The `GdbController` class API changed significantly in version 0.10.0.0. The constructor now expects `command: Optional[List[str]]` and `time_to_check_for_additional_output_sec: Optional[int]]`. Several methods like `GdbController.verify_valid_gdb_subprocess()` were removed, and the `NoGdbProcessError` exception was also removed.
- breaking Support for Python 3.5 was dropped in `pygdbmi` v0.10.0.0, and support for Python 3.6 was dropped in v0.10.0.2.
- breaking The `pygdbmi.IoManager.make_non_blocking` function was removed from the public API in version 0.11.0.0 as it was considered an internal utility not meant for public consumption.
- gotcha When using GDB versions 8.1 and newer, the output from the `run` command might be split into multiple parts. This can cause `pygdbmi` to only catch the initial part, leading to `GdbTimeOutError` if subsequent calls to `get_gdb_response()` are not handled correctly to fetch all parts of the response.
- gotcha To ensure GDB outputs machine-readable interface (MI) format, it must be launched with the `--interpreter=mi2` flag. If this flag is omitted, `pygdbmi` will receive standard console output which it cannot reliably parse into structured data.
Install
-
pip install pygdbmi
Imports
- GdbController
from pygdbmi.gdbcontroller import GdbController
- parse_response
from pygdbmi.gdbmiparser import parse_response
- NoGdbProcessError
Removed in v0.10.0.0
Quickstart
from pygdbmi.gdbcontroller import GdbController
from pprint import pprint
import os
import subprocess
import shutil
# NOTE: This example assumes 'make' and 'gdb' are available in your PATH.
# Create a dummy C program for debugging
if not os.path.exists('sample_app'):
os.makedirs('sample_app')
with open('sample_app/main.c', 'w') as f:
f.write('int main() { int x = 1; x++; return 0; }')
if shutil.which('gcc') and shutil.which('make'):
subprocess.run(['gcc', 'main.c', '-o', 'pygdbmiapp', '-g'], cwd='sample_app', check=True)
binary_path = os.path.abspath('sample_app/pygdbmiapp')
else:
print("Warning: 'gcc' or 'make' not found. Quickstart will only demonstrate parsing.")
binary_path = None
gdbmi = GdbController()
try:
if binary_path:
print(f"\nDebugging: {binary_path}")
# Load the binary
responses = gdbmi.write(f"-file-exec-and-symbols {binary_path}")
print("Load binary response:")
pprint(responses)
# Set a breakpoint at main
responses = gdbmi.write("-break-insert main")
print("Breakpoint response:")
pprint(responses)
# Run the program
responses = gdbmi.write("-exec-run")
print("Run response:")
pprint(responses)
# Continue to finish
responses = gdbmi.write("-exec-continue")
print("Continue response:")
pprint(responses)
# Example of parsing raw MI output
print("\nParsing raw GDB MI output:")
raw_mi_output = '^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"}'
parsed_response = gdbmi.gdbmiparser.parse_response(raw_mi_output)
pprint(parsed_response)
finally:
# Ensure gdb process is terminated
gdbmi.exit()
print("\nGDB process exited.")
# Clean up dummy app
shutil.rmtree('sample_app', ignore_errors=True)