From e4dbee2e44d6f9a1b8139748ed3f3ee803a2d6b6 Mon Sep 17 00:00:00 2001 From: CoprDistGit Date: Mon, 10 Apr 2023 16:06:19 +0000 Subject: automatic import of python-pygdbmi --- .gitignore | 1 + python-pygdbmi.spec | 633 ++++++++++++++++++++++++++++++++++++++++++++++++++++ sources | 1 + 3 files changed, 635 insertions(+) create mode 100644 python-pygdbmi.spec create mode 100644 sources diff --git a/.gitignore b/.gitignore index e69de29..9376f20 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +/pygdbmi-0.11.0.0.tar.gz diff --git a/python-pygdbmi.spec b/python-pygdbmi.spec new file mode 100644 index 0000000..7f40980 --- /dev/null +++ b/python-pygdbmi.spec @@ -0,0 +1,633 @@ +%global _empty_manifest_terminate_build 0 +Name: python-pygdbmi +Version: 0.11.0.0 +Release: 1 +Summary: Parse gdb machine interface output with Python +License: MIT +URL: https://github.com/cs01/pygdbmi +Source0: https://mirrors.nju.edu.cn/pypi/web/packages/2a/d0/d386ad42b12b90e60293c56a3b793910f34aa21c63f7ddc8a857e498d458/pygdbmi-0.11.0.0.tar.gz +BuildArch: noarch + + +%description +Python (**py**) [**gdb**](https://www.gnu.org/software/gdb/) machine interface [(**mi**)](https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI.html) +> GDB/MI is a line based machine oriented text interface to GDB and is activated by specifying using the --interpreter command line option (see Mode Options). It is specifically intended to support the development of systems which use the debugger as just one small component of a larger system. +## What's in the box? +1. A function to parse gdb machine interface string output and return structured data types (Python dicts) that are JSON serializable. Useful for writing the backend to a gdb frontend. For example, [gdbgui](https://github.com/cs01/gdbgui) uses pygdbmi on the backend. +2. A Python class to control and interact with gdb as a subprocess +To get [machine interface](https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI.html) output from gdb, run gdb with the `--interpreter=mi2` flag like so: +``` +gdb --interpreter=mi2 +``` +## Installation + pip install pygdbmi +## Compatibility +### Operating Systems +Cross platform support for Linux, macOS and Windows +- Linux/Unix + Ubuntu 14.04 and 16.04 have been tested to work. Other versions likely work as well. +- macOS + Note: the error `please check gdb is codesigned - see taskgated(8)` can be fixed by codesigning gdb with [these instructions](http://andresabino.com/2015/04/14/codesign-gdb-on-mac-os-x-yosemite-10-10-2/). If the error is not fixed, please [create an issue in github](https://github.com/cs01/pygdbmi/issues). +- Windows + Windows 10 has been tested to work with MinGW and cygwin. +### gdb versions +- gdb 7.6+ has been tested. Older versions may work as well. +## Examples +gdb mi defines a syntax for its output that is suitable for machine readability and scripting: [example output](https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Simple-Examples.html#GDB_002fMI-Simple-Examples): +``` +-> -break-insert main +<- ^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"} +<- (gdb) +``` +Use `pygdbmi.gdbmiparser.parse_response` to turn that string output into a JSON serializable dictionary +```python +from pygdbmi import gdbmiparser +from pprint import pprint +response = gdbmiparser.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) +pprint(response) +# Prints: +# {'message': 'done', +# 'payload': {'bkpt': {'addr': '0x08048564', +# 'disp': 'keep', +# 'enabled': 'y', +# 'file': 'myprog.c', +# 'fullname': '/home/myprog.c', +# 'func': 'main', +# 'line': '68', +# 'number': '1', +# 'thread-groups': ['i1'], +# 'times': '0', +# 'type': 'breakpoint'}}, +# 'token': None, +# 'type': 'result'} +``` +## Programmatic Control Over gdb +But how do you get the gdb output into Python in the first place? If you want, `pygdbmi` also has a class to control gdb as subprocess. You can write commands, and get structured output back: +```python +from pygdbmi.gdbcontroller import GdbController +from pprint import pprint +# Start gdb process +gdbmi = GdbController() +print(gdbmi.command) # print actual command run as subprocess +# Load binary a.out and get structured response +response = gdbmi.write('-file-exec-file a.out') +pprint(response) +# Prints: +# [{'message': 'thread-group-added', +# 'payload': {'id': 'i1'}, +# 'stream': 'stdout', +# 'token': None, +# 'type': 'notify'}, +# {'message': 'done', +# 'payload': None, +# 'stream': 'stdout', +# 'token': None, +# 'type': 'result'}] +``` +Now do whatever you want with gdb. All gdb commands, as well as gdb [machine interface commands](<(https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Input-Syntax.html#GDB_002fMI-Input-Syntax)>) are acceptable. gdb mi commands give better structured output that is machine readable, rather than gdb console output. mi commands begin with a `-`. +```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') +response = gdbmi.send_signal_to_gdb('SIGKILL') # name of signal is okay +response = gdbmi.send_signal_to_gdb(2) # value of signal is okay too +response = gdbmi.interrupt_gdb() # sends SIGINT to gdb +response = gdbmi.write('continue') +response = gdbmi.exit() +``` +## Parsed Output Format +Each parsed gdb response consists of a list of dictionaries. Each dictionary has keys `message`, `payload`, `token`, and `type`. +- `message` contains a textual message from gdb, which is not always present. When missing, this is `None`. +- `payload` contains the content of gdb's output, which can contain any of the following: `dictionary`, `list`, `string`. This too is not always present, and can be `None` depending on the response. +- `token` If an input command was prefixed with a (optional) token then the corresponding output for that command will also be prefixed by that same token. This field is only present for pygdbmi output types `nofity` and `result`. When missing, this is `None`. +The `type` is defined based on gdb's various [mi output record types](<(https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Output-Records.html#GDB_002fMI-Output-Records)>), and can be +- `result` - the result of a gdb command, such as `done`, `running`, `error`, etc. +- `notify` - additional async changes that have occurred, such as breakpoint modified +- `console` - textual responses to cli commands +- `log` - debugging messages from gdb's internals +- `output` - output from target +- `target` - output from remote target +- `done` - when gdb has finished its output +## Contributing +Documentation fixes, bug fixes, performance improvements, and functional improvements are welcome. You may want to create an issue before beginning work to make sure I am interested in merging it to the master branch. +pygdbmi uses [nox](https://github.com/theacodes/nox) for automation. +See available tasks with +``` +nox -l +``` +Run tests and lint with +``` +nox -s tests +nox -s lint +``` +Positional arguments passed to `nox -s tests` are passed directly to `pytest`. For instance, to run only the parse tests use +``` +nox -s tests -- tests/test_gdbmiparser.py +``` +See [`pytest`'s documentation](https://docs.pytest.org/) for more details on how to run tests. +To format code using the correct settings use +``` +nox -s format +``` +Or, to format only specified files, use +``` +nox -s format -- example.py pygdbmi/IoManager.py +``` +### Making a release +Only maintainers of the [pygdbmi package on PyPi](https://pypi.org/project/pygdbmi/) can make a release. +In the following steps, replace these strings with the correct values: +- `` is the name of the remote for the main pygdbmi repository (for instance, `origin`) +- `` is the version number chosen in step 2. +To make a release: +1. Checkout the `master` branch and pull from the main repository with `git pull master` +2. Decide the version number for the new release; we follow + [Semantic Versioning](https://semver.org/) but prefixing the version with `0.`: given a version + number _0.SECOND.THIRD.FOURTH_, increment the: + - _SECOND_ component when you make incompatible API changes + - _THIRD_ component when you add functionality in a backwards compatible manner + - _FOURTH_ component when you make backwards compatible bug fixes +3. Update `CHANGELOG.md` to list the chosen version number instead of `## dev` +4. Update `__version__` in `pygdbmi/__init__.py` to the chosen version number +5. Create a branch, for instance using `git checkout -b before-release-` +6. Commit your changes, for instance using `git commit -a -m 'Bump version to for release'` +7. Check that the docs look fine by serving them locally with `nox -s serve_docs` +8. Push the branch, for instance with `git push --set-upstream before-release-` +9. If tests pass on the PR you created, you can merge into `master` +10. Go to the [new release page](https://github.com/cs01/pygdbmi/releases/new) and prepare the + release: + - Add a tag in the form `v` (for example `v0.1.2.3`) + - Set the title to `pygdbmi v` (for example `pygdbmi v0.1.2.3`) + - Copy and paste the section for the new release only from `CHANGELOG.md` excluding the line + with the version number + - Press “Publish release” +10. Publish the release to PyPI with `nox -s publish` +11. Publish the docs with `nox -s publish_docs` +11. Verify that the [PyPi page for pygdbmi](https://pypi.org/project/pygdbmi/) looks correct +12. Verify that the [published docs](https://cs01.github.io/pygdbmi/) look correct +13. Prepare for changes for the next release by adding something like this above the previous + entries in `CHANGELOG.md` (where `` is `` with the last digit increaded + by 1): + ``` + ## .dev0 + - *Replace this line with new entries* + ``` +14. Create a branch for the changes with `git checkout -b after-release-` +15. Commit the change with `git commit -m 'Prepare for work on the next release' CHANGELOG.md` +16. Push the branch with `git push --set-upstream after-release-` +17. If tests pass, merge into `master` +## Similar projects +- [tsgdbmi](https://github.com/Guyutongxue/tsgdbmi) A port of pygdbmi to TypeScript +- [danielzfranklin/gdbmi](https://github.com/danielzfranklin/gdbmi) A port of pygdbmi to Rust +## Projects Using pygdbmi +- [gdbgui](https://github.com/cs01/gdbgui) implements a browser-based frontend to gdb, using pygdbmi on the backend +- [PINCE](https://github.com/korcankaraokcu/PINCE) is a gdb frontend that aims to provide a reverse engineering tool and a reusable library focused on games. It uses pygdbmi to parse gdb/mi based output for some functions +- [avatar²](https://github.com/avatartwo/avatar2) is an orchestration framework for reversing and analysing firmware of embedded devices. It utilizes pygdbmi for internal communication to different analysis targets. +- [UDB](https://undo.io/udb) is a proprietary time-travel debugger for C and C++ based on GDB. It uses pygdbmi in its extensive test suite to parse the debugger's output. +- Know of another project? Create a PR and add it here. +## Authors +- [Chad Smith](https://github.com/cs01) (main author and creator). +- [Marco Barisione](http://www.barisione.org/) (co-maintainer). +- [The community](https://github.com/cs01/pygdbmi/graphs/contributors). Thanks especially to @mariusmue, @bobthekingofegypt, @mouuff, and @felipesere. + +%package -n python3-pygdbmi +Summary: Parse gdb machine interface output with Python +Provides: python-pygdbmi +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +%description -n python3-pygdbmi +Python (**py**) [**gdb**](https://www.gnu.org/software/gdb/) machine interface [(**mi**)](https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI.html) +> GDB/MI is a line based machine oriented text interface to GDB and is activated by specifying using the --interpreter command line option (see Mode Options). It is specifically intended to support the development of systems which use the debugger as just one small component of a larger system. +## What's in the box? +1. A function to parse gdb machine interface string output and return structured data types (Python dicts) that are JSON serializable. Useful for writing the backend to a gdb frontend. For example, [gdbgui](https://github.com/cs01/gdbgui) uses pygdbmi on the backend. +2. A Python class to control and interact with gdb as a subprocess +To get [machine interface](https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI.html) output from gdb, run gdb with the `--interpreter=mi2` flag like so: +``` +gdb --interpreter=mi2 +``` +## Installation + pip install pygdbmi +## Compatibility +### Operating Systems +Cross platform support for Linux, macOS and Windows +- Linux/Unix + Ubuntu 14.04 and 16.04 have been tested to work. Other versions likely work as well. +- macOS + Note: the error `please check gdb is codesigned - see taskgated(8)` can be fixed by codesigning gdb with [these instructions](http://andresabino.com/2015/04/14/codesign-gdb-on-mac-os-x-yosemite-10-10-2/). If the error is not fixed, please [create an issue in github](https://github.com/cs01/pygdbmi/issues). +- Windows + Windows 10 has been tested to work with MinGW and cygwin. +### gdb versions +- gdb 7.6+ has been tested. Older versions may work as well. +## Examples +gdb mi defines a syntax for its output that is suitable for machine readability and scripting: [example output](https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Simple-Examples.html#GDB_002fMI-Simple-Examples): +``` +-> -break-insert main +<- ^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"} +<- (gdb) +``` +Use `pygdbmi.gdbmiparser.parse_response` to turn that string output into a JSON serializable dictionary +```python +from pygdbmi import gdbmiparser +from pprint import pprint +response = gdbmiparser.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) +pprint(response) +# Prints: +# {'message': 'done', +# 'payload': {'bkpt': {'addr': '0x08048564', +# 'disp': 'keep', +# 'enabled': 'y', +# 'file': 'myprog.c', +# 'fullname': '/home/myprog.c', +# 'func': 'main', +# 'line': '68', +# 'number': '1', +# 'thread-groups': ['i1'], +# 'times': '0', +# 'type': 'breakpoint'}}, +# 'token': None, +# 'type': 'result'} +``` +## Programmatic Control Over gdb +But how do you get the gdb output into Python in the first place? If you want, `pygdbmi` also has a class to control gdb as subprocess. You can write commands, and get structured output back: +```python +from pygdbmi.gdbcontroller import GdbController +from pprint import pprint +# Start gdb process +gdbmi = GdbController() +print(gdbmi.command) # print actual command run as subprocess +# Load binary a.out and get structured response +response = gdbmi.write('-file-exec-file a.out') +pprint(response) +# Prints: +# [{'message': 'thread-group-added', +# 'payload': {'id': 'i1'}, +# 'stream': 'stdout', +# 'token': None, +# 'type': 'notify'}, +# {'message': 'done', +# 'payload': None, +# 'stream': 'stdout', +# 'token': None, +# 'type': 'result'}] +``` +Now do whatever you want with gdb. All gdb commands, as well as gdb [machine interface commands](<(https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Input-Syntax.html#GDB_002fMI-Input-Syntax)>) are acceptable. gdb mi commands give better structured output that is machine readable, rather than gdb console output. mi commands begin with a `-`. +```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') +response = gdbmi.send_signal_to_gdb('SIGKILL') # name of signal is okay +response = gdbmi.send_signal_to_gdb(2) # value of signal is okay too +response = gdbmi.interrupt_gdb() # sends SIGINT to gdb +response = gdbmi.write('continue') +response = gdbmi.exit() +``` +## Parsed Output Format +Each parsed gdb response consists of a list of dictionaries. Each dictionary has keys `message`, `payload`, `token`, and `type`. +- `message` contains a textual message from gdb, which is not always present. When missing, this is `None`. +- `payload` contains the content of gdb's output, which can contain any of the following: `dictionary`, `list`, `string`. This too is not always present, and can be `None` depending on the response. +- `token` If an input command was prefixed with a (optional) token then the corresponding output for that command will also be prefixed by that same token. This field is only present for pygdbmi output types `nofity` and `result`. When missing, this is `None`. +The `type` is defined based on gdb's various [mi output record types](<(https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Output-Records.html#GDB_002fMI-Output-Records)>), and can be +- `result` - the result of a gdb command, such as `done`, `running`, `error`, etc. +- `notify` - additional async changes that have occurred, such as breakpoint modified +- `console` - textual responses to cli commands +- `log` - debugging messages from gdb's internals +- `output` - output from target +- `target` - output from remote target +- `done` - when gdb has finished its output +## Contributing +Documentation fixes, bug fixes, performance improvements, and functional improvements are welcome. You may want to create an issue before beginning work to make sure I am interested in merging it to the master branch. +pygdbmi uses [nox](https://github.com/theacodes/nox) for automation. +See available tasks with +``` +nox -l +``` +Run tests and lint with +``` +nox -s tests +nox -s lint +``` +Positional arguments passed to `nox -s tests` are passed directly to `pytest`. For instance, to run only the parse tests use +``` +nox -s tests -- tests/test_gdbmiparser.py +``` +See [`pytest`'s documentation](https://docs.pytest.org/) for more details on how to run tests. +To format code using the correct settings use +``` +nox -s format +``` +Or, to format only specified files, use +``` +nox -s format -- example.py pygdbmi/IoManager.py +``` +### Making a release +Only maintainers of the [pygdbmi package on PyPi](https://pypi.org/project/pygdbmi/) can make a release. +In the following steps, replace these strings with the correct values: +- `` is the name of the remote for the main pygdbmi repository (for instance, `origin`) +- `` is the version number chosen in step 2. +To make a release: +1. Checkout the `master` branch and pull from the main repository with `git pull master` +2. Decide the version number for the new release; we follow + [Semantic Versioning](https://semver.org/) but prefixing the version with `0.`: given a version + number _0.SECOND.THIRD.FOURTH_, increment the: + - _SECOND_ component when you make incompatible API changes + - _THIRD_ component when you add functionality in a backwards compatible manner + - _FOURTH_ component when you make backwards compatible bug fixes +3. Update `CHANGELOG.md` to list the chosen version number instead of `## dev` +4. Update `__version__` in `pygdbmi/__init__.py` to the chosen version number +5. Create a branch, for instance using `git checkout -b before-release-` +6. Commit your changes, for instance using `git commit -a -m 'Bump version to for release'` +7. Check that the docs look fine by serving them locally with `nox -s serve_docs` +8. Push the branch, for instance with `git push --set-upstream before-release-` +9. If tests pass on the PR you created, you can merge into `master` +10. Go to the [new release page](https://github.com/cs01/pygdbmi/releases/new) and prepare the + release: + - Add a tag in the form `v` (for example `v0.1.2.3`) + - Set the title to `pygdbmi v` (for example `pygdbmi v0.1.2.3`) + - Copy and paste the section for the new release only from `CHANGELOG.md` excluding the line + with the version number + - Press “Publish release” +10. Publish the release to PyPI with `nox -s publish` +11. Publish the docs with `nox -s publish_docs` +11. Verify that the [PyPi page for pygdbmi](https://pypi.org/project/pygdbmi/) looks correct +12. Verify that the [published docs](https://cs01.github.io/pygdbmi/) look correct +13. Prepare for changes for the next release by adding something like this above the previous + entries in `CHANGELOG.md` (where `` is `` with the last digit increaded + by 1): + ``` + ## .dev0 + - *Replace this line with new entries* + ``` +14. Create a branch for the changes with `git checkout -b after-release-` +15. Commit the change with `git commit -m 'Prepare for work on the next release' CHANGELOG.md` +16. Push the branch with `git push --set-upstream after-release-` +17. If tests pass, merge into `master` +## Similar projects +- [tsgdbmi](https://github.com/Guyutongxue/tsgdbmi) A port of pygdbmi to TypeScript +- [danielzfranklin/gdbmi](https://github.com/danielzfranklin/gdbmi) A port of pygdbmi to Rust +## Projects Using pygdbmi +- [gdbgui](https://github.com/cs01/gdbgui) implements a browser-based frontend to gdb, using pygdbmi on the backend +- [PINCE](https://github.com/korcankaraokcu/PINCE) is a gdb frontend that aims to provide a reverse engineering tool and a reusable library focused on games. It uses pygdbmi to parse gdb/mi based output for some functions +- [avatar²](https://github.com/avatartwo/avatar2) is an orchestration framework for reversing and analysing firmware of embedded devices. It utilizes pygdbmi for internal communication to different analysis targets. +- [UDB](https://undo.io/udb) is a proprietary time-travel debugger for C and C++ based on GDB. It uses pygdbmi in its extensive test suite to parse the debugger's output. +- Know of another project? Create a PR and add it here. +## Authors +- [Chad Smith](https://github.com/cs01) (main author and creator). +- [Marco Barisione](http://www.barisione.org/) (co-maintainer). +- [The community](https://github.com/cs01/pygdbmi/graphs/contributors). Thanks especially to @mariusmue, @bobthekingofegypt, @mouuff, and @felipesere. + +%package help +Summary: Development documents and examples for pygdbmi +Provides: python3-pygdbmi-doc +%description help +Python (**py**) [**gdb**](https://www.gnu.org/software/gdb/) machine interface [(**mi**)](https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI.html) +> GDB/MI is a line based machine oriented text interface to GDB and is activated by specifying using the --interpreter command line option (see Mode Options). It is specifically intended to support the development of systems which use the debugger as just one small component of a larger system. +## What's in the box? +1. A function to parse gdb machine interface string output and return structured data types (Python dicts) that are JSON serializable. Useful for writing the backend to a gdb frontend. For example, [gdbgui](https://github.com/cs01/gdbgui) uses pygdbmi on the backend. +2. A Python class to control and interact with gdb as a subprocess +To get [machine interface](https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI.html) output from gdb, run gdb with the `--interpreter=mi2` flag like so: +``` +gdb --interpreter=mi2 +``` +## Installation + pip install pygdbmi +## Compatibility +### Operating Systems +Cross platform support for Linux, macOS and Windows +- Linux/Unix + Ubuntu 14.04 and 16.04 have been tested to work. Other versions likely work as well. +- macOS + Note: the error `please check gdb is codesigned - see taskgated(8)` can be fixed by codesigning gdb with [these instructions](http://andresabino.com/2015/04/14/codesign-gdb-on-mac-os-x-yosemite-10-10-2/). If the error is not fixed, please [create an issue in github](https://github.com/cs01/pygdbmi/issues). +- Windows + Windows 10 has been tested to work with MinGW and cygwin. +### gdb versions +- gdb 7.6+ has been tested. Older versions may work as well. +## Examples +gdb mi defines a syntax for its output that is suitable for machine readability and scripting: [example output](https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Simple-Examples.html#GDB_002fMI-Simple-Examples): +``` +-> -break-insert main +<- ^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"} +<- (gdb) +``` +Use `pygdbmi.gdbmiparser.parse_response` to turn that string output into a JSON serializable dictionary +```python +from pygdbmi import gdbmiparser +from pprint import pprint +response = gdbmiparser.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) +pprint(response) +# Prints: +# {'message': 'done', +# 'payload': {'bkpt': {'addr': '0x08048564', +# 'disp': 'keep', +# 'enabled': 'y', +# 'file': 'myprog.c', +# 'fullname': '/home/myprog.c', +# 'func': 'main', +# 'line': '68', +# 'number': '1', +# 'thread-groups': ['i1'], +# 'times': '0', +# 'type': 'breakpoint'}}, +# 'token': None, +# 'type': 'result'} +``` +## Programmatic Control Over gdb +But how do you get the gdb output into Python in the first place? If you want, `pygdbmi` also has a class to control gdb as subprocess. You can write commands, and get structured output back: +```python +from pygdbmi.gdbcontroller import GdbController +from pprint import pprint +# Start gdb process +gdbmi = GdbController() +print(gdbmi.command) # print actual command run as subprocess +# Load binary a.out and get structured response +response = gdbmi.write('-file-exec-file a.out') +pprint(response) +# Prints: +# [{'message': 'thread-group-added', +# 'payload': {'id': 'i1'}, +# 'stream': 'stdout', +# 'token': None, +# 'type': 'notify'}, +# {'message': 'done', +# 'payload': None, +# 'stream': 'stdout', +# 'token': None, +# 'type': 'result'}] +``` +Now do whatever you want with gdb. All gdb commands, as well as gdb [machine interface commands](<(https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Input-Syntax.html#GDB_002fMI-Input-Syntax)>) are acceptable. gdb mi commands give better structured output that is machine readable, rather than gdb console output. mi commands begin with a `-`. +```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') +response = gdbmi.send_signal_to_gdb('SIGKILL') # name of signal is okay +response = gdbmi.send_signal_to_gdb(2) # value of signal is okay too +response = gdbmi.interrupt_gdb() # sends SIGINT to gdb +response = gdbmi.write('continue') +response = gdbmi.exit() +``` +## Parsed Output Format +Each parsed gdb response consists of a list of dictionaries. Each dictionary has keys `message`, `payload`, `token`, and `type`. +- `message` contains a textual message from gdb, which is not always present. When missing, this is `None`. +- `payload` contains the content of gdb's output, which can contain any of the following: `dictionary`, `list`, `string`. This too is not always present, and can be `None` depending on the response. +- `token` If an input command was prefixed with a (optional) token then the corresponding output for that command will also be prefixed by that same token. This field is only present for pygdbmi output types `nofity` and `result`. When missing, this is `None`. +The `type` is defined based on gdb's various [mi output record types](<(https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Output-Records.html#GDB_002fMI-Output-Records)>), and can be +- `result` - the result of a gdb command, such as `done`, `running`, `error`, etc. +- `notify` - additional async changes that have occurred, such as breakpoint modified +- `console` - textual responses to cli commands +- `log` - debugging messages from gdb's internals +- `output` - output from target +- `target` - output from remote target +- `done` - when gdb has finished its output +## Contributing +Documentation fixes, bug fixes, performance improvements, and functional improvements are welcome. You may want to create an issue before beginning work to make sure I am interested in merging it to the master branch. +pygdbmi uses [nox](https://github.com/theacodes/nox) for automation. +See available tasks with +``` +nox -l +``` +Run tests and lint with +``` +nox -s tests +nox -s lint +``` +Positional arguments passed to `nox -s tests` are passed directly to `pytest`. For instance, to run only the parse tests use +``` +nox -s tests -- tests/test_gdbmiparser.py +``` +See [`pytest`'s documentation](https://docs.pytest.org/) for more details on how to run tests. +To format code using the correct settings use +``` +nox -s format +``` +Or, to format only specified files, use +``` +nox -s format -- example.py pygdbmi/IoManager.py +``` +### Making a release +Only maintainers of the [pygdbmi package on PyPi](https://pypi.org/project/pygdbmi/) can make a release. +In the following steps, replace these strings with the correct values: +- `` is the name of the remote for the main pygdbmi repository (for instance, `origin`) +- `` is the version number chosen in step 2. +To make a release: +1. Checkout the `master` branch and pull from the main repository with `git pull master` +2. Decide the version number for the new release; we follow + [Semantic Versioning](https://semver.org/) but prefixing the version with `0.`: given a version + number _0.SECOND.THIRD.FOURTH_, increment the: + - _SECOND_ component when you make incompatible API changes + - _THIRD_ component when you add functionality in a backwards compatible manner + - _FOURTH_ component when you make backwards compatible bug fixes +3. Update `CHANGELOG.md` to list the chosen version number instead of `## dev` +4. Update `__version__` in `pygdbmi/__init__.py` to the chosen version number +5. Create a branch, for instance using `git checkout -b before-release-` +6. Commit your changes, for instance using `git commit -a -m 'Bump version to for release'` +7. Check that the docs look fine by serving them locally with `nox -s serve_docs` +8. Push the branch, for instance with `git push --set-upstream before-release-` +9. If tests pass on the PR you created, you can merge into `master` +10. Go to the [new release page](https://github.com/cs01/pygdbmi/releases/new) and prepare the + release: + - Add a tag in the form `v` (for example `v0.1.2.3`) + - Set the title to `pygdbmi v` (for example `pygdbmi v0.1.2.3`) + - Copy and paste the section for the new release only from `CHANGELOG.md` excluding the line + with the version number + - Press “Publish release” +10. Publish the release to PyPI with `nox -s publish` +11. Publish the docs with `nox -s publish_docs` +11. Verify that the [PyPi page for pygdbmi](https://pypi.org/project/pygdbmi/) looks correct +12. Verify that the [published docs](https://cs01.github.io/pygdbmi/) look correct +13. Prepare for changes for the next release by adding something like this above the previous + entries in `CHANGELOG.md` (where `` is `` with the last digit increaded + by 1): + ``` + ## .dev0 + - *Replace this line with new entries* + ``` +14. Create a branch for the changes with `git checkout -b after-release-` +15. Commit the change with `git commit -m 'Prepare for work on the next release' CHANGELOG.md` +16. Push the branch with `git push --set-upstream after-release-` +17. If tests pass, merge into `master` +## Similar projects +- [tsgdbmi](https://github.com/Guyutongxue/tsgdbmi) A port of pygdbmi to TypeScript +- [danielzfranklin/gdbmi](https://github.com/danielzfranklin/gdbmi) A port of pygdbmi to Rust +## Projects Using pygdbmi +- [gdbgui](https://github.com/cs01/gdbgui) implements a browser-based frontend to gdb, using pygdbmi on the backend +- [PINCE](https://github.com/korcankaraokcu/PINCE) is a gdb frontend that aims to provide a reverse engineering tool and a reusable library focused on games. It uses pygdbmi to parse gdb/mi based output for some functions +- [avatar²](https://github.com/avatartwo/avatar2) is an orchestration framework for reversing and analysing firmware of embedded devices. It utilizes pygdbmi for internal communication to different analysis targets. +- [UDB](https://undo.io/udb) is a proprietary time-travel debugger for C and C++ based on GDB. It uses pygdbmi in its extensive test suite to parse the debugger's output. +- Know of another project? Create a PR and add it here. +## Authors +- [Chad Smith](https://github.com/cs01) (main author and creator). +- [Marco Barisione](http://www.barisione.org/) (co-maintainer). +- [The community](https://github.com/cs01/pygdbmi/graphs/contributors). Thanks especially to @mariusmue, @bobthekingofegypt, @mouuff, and @felipesere. + +%prep +%autosetup -n pygdbmi-0.11.0.0 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-pygdbmi -f filelist.lst +%dir %{python3_sitelib}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Mon Apr 10 2023 Python_Bot - 0.11.0.0-1 +- Package Spec generated diff --git a/sources b/sources new file mode 100644 index 0000000..2f04666 --- /dev/null +++ b/sources @@ -0,0 +1 @@ +34b1812e77469c6206002b3929798cab pygdbmi-0.11.0.0.tar.gz -- cgit v1.2.3