Giter Site home page Giter Site logo

cs01 / pygdbmi Goto Github PK

View Code? Open in Web Editor NEW
204.0 11.0 47.0 7.08 MB

A library to parse gdb mi output and interact with gdb subprocesses

Home Page: https://cs01.github.io/pygdbmi

License: MIT License

Python 99.13% C 0.79% Makefile 0.09%
python gdb-commands json-serializable gdb-mi parser parser-library frontend gdb subprocess backend

pygdbmi's Introduction

pygdbmi - Get Structured Output from GDB's Machine Interface

Test status PyPI version

Documentation https://cs01.github.io/pygdbmi

Source Code https://github.com/cs01/pygdbmi


Python (py) gdb machine interface (mi)

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 uses pygdbmi on the backend.
  2. A Python class to control and interact with gdb as a subprocess

To get machine interface 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. If the error is not fixed, please create an issue in github.

  • 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:

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

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:

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 are acceptable. gdb mi commands give better structured output that is machine readable, rather than gdb console output. mi commands begin with a -.

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, 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 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 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 can make a release.

In the following steps, replace these strings with the correct values:

  • <REMOTE> is the name of the remote for the main pygdbmi repository (for instance, origin)
  • <VERSION> 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 <REMOTE> master

  2. Decide the version number for the new release; we follow Semantic Versioning 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-<VERSION>

  6. Commit your changes, for instance using git commit -a -m 'Bump version to <VERSION> 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 <REMOTE> before-release-<VERSION>

  9. If tests pass on the PR you created, you can merge into master

  10. Go to the new release page and prepare the release:

    • Add a tag in the form v<VERSION> (for example v0.1.2.3)
    • Set the title to pygdbmi v<VERSION> (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”
  11. Publish the release to PyPI with nox -s publish

  12. Publish the docs with nox -s publish_docs

  13. Verify that the PyPi page for pygdbmi looks correct

  14. Verify that the published docs look correct

  15. Prepare for changes for the next release by adding something like this above the previous entries in CHANGELOG.md (where <VERSION+1> is <VERSION> with the last digit increaded by 1):

    ## <VERSION+1>.dev0
    
    - *Replace this line with new entries*
    
  16. Create a branch for the changes with git checkout -b after-release-<VERSION>

  17. Commit the change with git commit -m 'Prepare for work on the next release' CHANGELOG.md

  18. Push the branch with git push --set-upstream <REMOTE> after-release-<VERSION>

  19. If tests pass, merge into master

Similar projects

Projects Using pygdbmi

  • gdbgui implements a browser-based frontend to gdb, using pygdbmi on the backend
  • 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² is an orchestration framework for reversing and analysing firmware of embedded devices. It utilizes pygdbmi for internal communication to different analysis targets.
  • 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.
  • pwndbg-gui is a user-friendly graphical interface for pwndbg, a tool that simplifies exploit development and reverse engineering with GDB. It uses pygdbmi to interact with GDB and get structured responses.
  • Know of another project? Create a PR and add it here.

Authors

pygdbmi's People

Contributors

alescher avatar barisione avatar bobthekingofegypt avatar cs01 avatar felipesere avatar h0bo avatar jaspercraeghs avatar johncf avatar korcankaraokcu avatar mariusmue avatar matkuki avatar mouuff avatar rudolfwalter avatar tomekjaworski avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pygdbmi's Issues

"GdbTimeoutError" during '-symbol-info-variables' command

Describe the bug
I'm trying to invoke GDB 11.1 with --interpreter=mi2.
When i issue '-symbol-info-variables' command, timeout error is reported as below
"GdbTimeoutError: Did not get response from gdb after 1 seconds"

The project is big & there are lot of variables.
When i try to do it directly in GDB, it works fine.

To Reproduce
I have just explained the issue in the description.

Expected behavior
The response for '-symbol-info-variables' should be properly available in json output format.

Screenshots
If applicable, add screenshots to help explain your problem.

Please complete the following information:

  • OS: Windows 10
  • pygdbmi version (pip freeze output): pygdbmi==0.10.0.2

Additional context
Add any other context about the problem here.
2022-06-08_16h03_59

Suppress logging output from StringStream?

Hi,

I just stumbled on your library whilst trying to figure out how to drive gdb from a nosetests test suite. My test suite is intended to test some embedded microcontroller firmware, which it does so by launching it in a QEMU virtual machine (qemu-system-arm -M lm3s9695evb) then setting breakpoints, etc.

One gripe I have though, is the StringStream class directly calls logging.debug, one character at a time. This results in the following in nosetests:

-------------------- >> begin captured logging << --------------------
DEBUG:TestCliUtil.gdb[testlib.py:129]:Sending -target-select extended-remote localhost:1234
DEBUG:root[StringStream.py:72]: i
DEBUG:root[StringStream.py:72]: 1
DEBUG:root[StringStream.py:72]: "
DEBUG:TestCliUtil.gdb[testlib.py:129]:Sending -target-disconnect
DEBUG:root[StringStream.py:72]: i
DEBUG:root[StringStream.py:72]: 1
DEBUG:root[StringStream.py:72]: "
DEBUG:root[StringStream.py:72]: 4
DEBUG:root[StringStream.py:72]: 2
DEBUG:root[StringStream.py:72]: 0
DEBUG:root[StringStream.py:72]: 0
DEBUG:root[StringStream.py:72]: 0
DEBUG:root[StringStream.py:72]: "
DEBUG:root[StringStream.py:72]: 1
DEBUG:root[StringStream.py:72]: "
DEBUG:root[StringStream.py:72]: i
DEBUG:root[StringStream.py:72]: 1
DEBUG:root[StringStream.py:72]: "
DEBUG:root[StringStream.py:72]: 0
DEBUG:root[StringStream.py:72]: x
DEBUG:root[StringStream.py:72]: 0
DEBUG:root[StringStream.py:72]: 0
DEBUG:root[StringStream.py:72]: 0
DEBUG:root[StringStream.py:72]: 0
DEBUG:root[StringStream.py:72]: 0
DEBUG:root[StringStream.py:72]: a
DEBUG:root[StringStream.py:72]: 7
DEBUG:root[StringStream.py:72]: 8
DEBUG:root[StringStream.py:72]: "
DEBUG:root[StringStream.py:72]: R
DEBUG:root[StringStream.py:72]: e
DEBUG:root[StringStream.py:72]: s
DEBUG:root[StringStream.py:72]: e
DEBUG:root[StringStream.py:72]: t
DEBUG:root[StringStream.py:72]: H
DEBUG:root[StringStream.py:72]: a
DEBUG:root[StringStream.py:72]: n
DEBUG:root[StringStream.py:72]: d
DEBUG:root[StringStream.py:72]: l
DEBUG:root[StringStream.py:72]: e
DEBUG:root[StringStream.py:72]: r
DEBUG:root[StringStream.py:72]: "
DEBUG:root[StringStream.py:72]: t
DEBUG:root[StringStream.py:72]: e
DEBUG:root[StringStream.py:72]: s
DEBUG:root[StringStream.py:72]: t
DEBUG:root[StringStream.py:72]: /
DEBUG:root[StringStream.py:72]: l
DEBUG:root[StringStream.py:72]: i
DEBUG:root[StringStream.py:72]: b
DEBUG:root[StringStream.py:72]: /
DEBUG:root[StringStream.py:72]: s
DEBUG:root[StringStream.py:72]: t
DEBUG:root[StringStream.py:72]: a
DEBUG:root[StringStream.py:72]: r
DEBUG:root[StringStream.py:72]: t
DEBUG:root[StringStream.py:72]: u
DEBUG:root[StringStream.py:72]: p
DEBUG:root[StringStream.py:72]: .
DEBUG:root[StringStream.py:72]: c
DEBUG:root[StringStream.py:72]: "
DEBUG:root[StringStream.py:72]: /
DEBUG:root[StringStream.py:72]: h
DEBUG:root[StringStream.py:72]: o
DEBUG:root[StringStream.py:72]: m
DEBUG:root[StringStream.py:72]: e
DEBUG:root[StringStream.py:72]: /
DEBUG:root[StringStream.py:72]: s
DEBUG:root[StringStream.py:72]: t
DEBUG:root[StringStream.py:72]: u
DEBUG:root[StringStream.py:72]: a
DEBUG:root[StringStream.py:72]: r
DEBUG:root[StringStream.py:72]: t
DEBUG:root[StringStream.py:72]: l
DEBUG:root[StringStream.py:72]: /
DEBUG:root[StringStream.py:72]: v
DEBUG:root[StringStream.py:72]: r
DEBUG:root[StringStream.py:72]: t
DEBUG:root[StringStream.py:72]: /
DEBUG:root[StringStream.py:72]: p
DEBUG:root[StringStream.py:72]: r
DEBUG:root[StringStream.py:72]: o
DEBUG:root[StringStream.py:72]: j
DEBUG:root[StringStream.py:72]: e
DEBUG:root[StringStream.py:72]: c
DEBUG:root[StringStream.py:72]: t
DEBUG:root[StringStream.py:72]: s
DEBUG:root[StringStream.py:72]: /
DEBUG:root[StringStream.py:72]: w
DEBUG:root[StringStream.py:72]: i
DEBUG:root[StringStream.py:72]: d
DEBUG:root[StringStream.py:72]: e
DEBUG:root[StringStream.py:72]: s
DEBUG:root[StringStream.py:72]: k
DEBUG:root[StringStream.py:72]: y
DEBUG:root[StringStream.py:72]: /
DEBUG:root[StringStream.py:72]: h
DEBUG:root[StringStream.py:72]: u
DEBUG:root[StringStream.py:72]: b
DEBUG:root[StringStream.py:72]: /
DEBUG:root[StringStream.py:72]: f
DEBUG:root[StringStream.py:72]: i
DEBUG:root[StringStream.py:72]: r
DEBUG:root[StringStream.py:72]: m
DEBUG:root[StringStream.py:72]: w
DEBUG:root[StringStream.py:72]: a
DEBUG:root[StringStream.py:72]: r
DEBUG:root[StringStream.py:72]: e
DEBUG:root[StringStream.py:72]: /
DEBUG:root[StringStream.py:72]: t
DEBUG:root[StringStream.py:72]: e
DEBUG:root[StringStream.py:72]: s
DEBUG:root[StringStream.py:72]: t
DEBUG:root[StringStream.py:72]: /
DEBUG:root[StringStream.py:72]: l
DEBUG:root[StringStream.py:72]: i
DEBUG:root[StringStream.py:72]: b
DEBUG:root[StringStream.py:72]: /
DEBUG:root[StringStream.py:72]: s
DEBUG:root[StringStream.py:72]: t
DEBUG:root[StringStream.py:72]: a
DEBUG:root[StringStream.py:72]: r
DEBUG:root[StringStream.py:72]: t
DEBUG:root[StringStream.py:72]: u
DEBUG:root[StringStream.py:72]: p
DEBUG:root[StringStream.py:72]: .
DEBUG:root[StringStream.py:72]: c
DEBUG:root[StringStream.py:72]: "
DEBUG:root[StringStream.py:72]: 2
DEBUG:root[StringStream.py:72]: 9
DEBUG:root[StringStream.py:72]: 9
DEBUG:root[StringStream.py:72]: "
DEBUG:root[StringStream.py:72]: 1
DEBUG:root[StringStream.py:72]: "
DEBUG:root[StringStream.py:72]: a
DEBUG:root[StringStream.py:72]: l
DEBUG:root[StringStream.py:72]: l
DEBUG:root[StringStream.py:72]: "
DEBUG:root[StringStream.py:72]: i
DEBUG:root[StringStream.py:72]: 1
DEBUG:root[StringStream.py:72]: "

For bonus points, the text is coloured bright blue (cyan). Hitting the logger class with that quantity of log messages is a recipe for a really slow application (I've been there before… Logger.debug() in a tight loop inside OpenERP made things crawl!), and moreover, because it's the root logger, it's impossible to filter it if you have a requirement to see debug information elsewhere.

I'd suggest three things:

  1. StringStream should use logging.getLogger to get a logger instance of its own rather than polluting the root logger with its messages.
  2. StringStream should batch log messages so it's not calling .debug() so frequently as this will really slow down the logger class.
  3. StringStream should not be calling basicConfig.

(1) and (3) is real easy to fix:

    def __init__(self, raw_text, debug=False):
        self.raw_text = raw_text
        self.index = 0
        self.len = len(raw_text)

        self._log = logging.getLogger(self.__class__.__module__)
        if debug:
            self._log.setLevel(logging.DEBUG)
        else:
            self._log.setLevel(logging.ERROR)
        handler = logging.StreamHandler()
        handler.setFormatter(logging.Formatter("%(funcName)20s %(message)s"))
        self._log.addHandler(handler)

Then replace calls to logging.debug with self._log.debug. As it happens, that's just one place. So to take care of that, and suggestion (2) at the same time:

    def advance_past_string_with_gdb_escapes(self, chars_to_remove_gdb_escape=None):
        """characters that gdb escapes that should not be
        escaped by this parser
        """

        if chars_to_remove_gdb_escape is None:
            chars_to_remove_gdb_escape = ['"']

        buf = ""

        if self._log.isEnabledFor(logging.DEBUG):
            read_text = ""

        while True:
            c = self.raw_text[self.index]
            self.index += 1
            if self._log.isEnabledFor(logging.DEBUG):
                read_text += c

            if c == "\\":
                # We are on a backslash and there is another character after the backslash
                # to parse. Handle this case specially since gdb escaped it for us

                # Get the next char that is being escaped
                c2 = self.raw_text[self.index]
                self.index += 1
                # only store the escaped character in the buffer; don't store the backslash
                # (don't leave it escaped)
                buf += c2

            elif c == '"':
                # Quote is closed. Exit (and don't include the end quote).
                break

            else:
                # capture this character, and keep capturing
                buf += c

        if self._log.isEnabledFor(logging.DEBUG):
            self._log.debug("%s", fmt_cyan(read_text))

        return buf

pygdbmi is now packaged for Fedora

Just as a courteousy, I just wanted to let you know that pygdbmi is now packaged for Fedora!

We added it to help with KDE bug reports, to tap into the gdb mi as KDE added that function in DrKonqi.

Slow time response with pipes (Windows)

I am testing a program I developed for a Microcontroller with a Cortex-M4 CPU. As I need to read/write some specific variables in real time I decided to develop a GUI and use the xPack Qemu ARM software. This SW allows to emulate the microcontroller and interact as well with GDB. I am using pygdbmi to interrupt the program, write data from the GUI and read data and display it. I noticed the execution time of the complete process (interrupt >-read-memory-bytes>-write-memory-bytes>continue) takes around 1-0.6 seconds. As this represents lag in the GUI I decided to check if I could decrease the latency.

As I found out that there is support for GDB with a python API I created a script with a custom command that does what I need (interrupt>read>write>continue). Within the python script I measure the time it takes to execute and it was around 0.01-0.02 seconds. As I still need to integrate it to the GUI I tested two approaches:

  1. Use again pygdbmi and call the custom command I made in the python script. The response from the command is parsed through the pygdbmi library and the latency was between 1-0.4 seconds, which is a minor improvement.
  2. Use a file as a pipe and check if the latency comes from the pipes. In the python script for gdb I added method that writes a json file with the data I require. The only interaction with pipes in this case is to write to the standard input and send the command to the gdb process. To know if the script has finished I poll instead for the data contained in the json file. To my surprise this reduced the latency to almost the same I had by manually executing the python script (0.02-0.03) seconds.

So from these results and for my purpose, using files instead of pipes to retrieve the gbd response and the python script support for gdb I was able to have a faster GUI response for my simulated MCU. I could not test the results in Linux as I had troubles using a precompiled gdb with python support for my specific target (arm-none-eabi-gdb).

As I do not have experience with how pipes in Windows work I am not sure if this could be a issue related with windows pipes, the way pygdbmi gets responses from pipes in Windows , if the GDB Machine Interface is too slow or if my implementation is not as it should be. Just wanted to post the results of these experiments as maybe this can become useful to look for ways on reducing latency when interacting with GDB.

Problem with trailing \n characters

Sometimes gdb return the characters \n...not as a new line but escapes the \
e.g. \\n not \n

An error is thrown when writing the following command:

mi_cmd_to_write --- 1-target-select remote 192.168.122.48:1234

gdb_mi_text --- =tsv-created,name="trace_timestamp",initial="0"\n

The \n is with the escaped \ and attempts to parse a string of length 0 within _parse_val thus throwing an unexpected character exception.

I've written a patch that searches for the characters at the end of each string to parse and removes them.

https://pastebin.com/gfuUiD8Z

I'm unsure where you want to issue a fix so haven't created a pull request.

Capture debugee output

Gdbmi seems not capturing debugee output (like printf)
This may lead to timeout error
I wrote a simple program that print a string per second for 10 seconds and set two breakpoints at the start and end of loop.
Gdbmi works fine until gdb hit the first break point, however after I type continue, debugee will enter the
10 seconds loop, then cause gdbmi timeout error and never hit second bp at the loop end.
this loop will print output properly in gdb with --interpreter=mi2
Do you have any suggestion? Or should I edit timeout limit depends on debugee?

GdbController cannot recognize window short path of gdb executable

Describe the bug
When gdb executable is short format like this:
C:/PROGRA~2/GNUARM~1/102021~1.10/bin/AR470E~1.EXE

Full path: "C:\PROGRA2\GNUARM1\102021~1.10\bin\arm-none-eabi-gdb.exe"

Then the consrtuctor will raise error: gdb executable could not be resolved from

Checked the code, function distutils.spawn.find_executable() will return None for C:/PROGRA~2/GNUARM~1/102021~1.10/bin/AR470E~1.EXE

To Reproduce

gdb = GdbController(`C:/PROGRA~2/GNUARM~1/102021~1.10/bin/AR470E~1.EXE`)

String parsing regression with v0.10.0.2

Hi,

I'm seeing the following regression with release 0.10.0.2 (the previous one worked fine).
I'm issuing a GDB MI command as follows (setting a field of a struct):

-data-evaluate-expression "((my_add_t*)0x200002f8)->paddA = 254"

The response coming back from gdb is like this:

1030^done,value="254 '\376'"

The function _unescape_internal in gdbescapes.py raises an exception when executin this line:

replaced = octal_sequence_bytes.decode("utf-8")

Exception:

'utf-8' codec can't decode byte 0xfe in position 0: invalid start byte

You can directly reproduce/trigger this issue with:

from pygdbmi.gdbescapes import _unescape_internal
_unescape_internal("1030^done,value=\"254 '\376'\"", expect_closing_quote=True)

Is this change in behavior intended? If yes, what would I need to do to get re-enable the old behavior?

Thank you.

Environment:

OS: Windows 10
pygdbmi version: 0.10.0.2

README.md - AttributeError: 'GdbController' object has no attribute 'get_subprocess_cmd'

Example from README.md does not work.

Running gdbmi.get_subprocess_cmd() cause following error:
AttributeError: 'GdbController' object has no attribute 'get_subprocess_cmd'

Function get_subprocess_cmd() was removed from file pygdbmi/gdbcontroller.py in commit:
449080a#diff-e29bd3c69c0c2b3f6f7c89a6ea177b322af7411076e74606faddf68573a7630dL126

Please update README.md

pygdbmi version (pip freeze output):
pygdbmi 0.10.0.2

Escapes in MI error records are mangled

Describe the bug

When parsing an error record, backslashes are just dropped. This works for quotes but mangles other escapes (like \n).

For instance this:

^error,msg="This is an error\non multiple lines and with\tother escapes"

Becomes a dictionary with this message:

This is an errornon multiple lines and withtother escapes

To Reproduce

I wrote a simple script.py Python script with a GDB command to be able to have arbitrary escapes:

import gdb


class MyCommand(gdb.Command):
    def __init__(self):
        super().__init__("my-command", gdb.COMMAND_NONE)

    def invoke(self, args, from_tty):
        raise gdb.GdbError("This is an error\non multiple lines and with\tother escapes")


MyCommand()

Start GDB in MI-mode and load the script:

gdb -i=mi2 -x script.py

When you use the command, GDB produces this output:

(gdb)
my-command
&"my-command\n"
&"This is an error\n"
&"on multiple lines and with\tother escapes\n"
^error,msg="This is an error\non multiple lines and with\tother escapes"

Parse it with pygdbmi:

gdbmiparser.parse_response(r'^error,msg="This is an error\non multiple lines and with\tother escapes"')

And you get:

{'type': 'result',
 'message': 'error',
 'payload': {'msg': 'This is an errornon multiple lines and withtother escapes'},
 'token': None}

Expected behavior

Escapes should be interpreted. In the example above I would expect this output:

{'type': 'result',
 'message': 'error',
 'payload': {'msg': 'This is an error\non multiple lines and with\tother escapes'},
 'token': None}

The correct escape behaviour (which is not compatible with Python escapes) can be found in printchar in gdb/utils.c in the binutils-gdb repository.

Please complete the following information:

  • OS: macOS
  • pygdbmi version (pip freeze output):
$ pip freeze | grep pygdbmi
pygdbmi==0.10.0.1

Additional context

I haven't looked at the pygdbmi code yet but I may be able to make a PR if you are interested. I already have an unescape function in Python.

IoManager._get_responses_windows mangles token when reading from stdout

Describe the bug

The IoManager._get_responses_windows() method sometimes doesn't read the MI token.

To Reproduce

I'm using pygdbmi to drive arm-none-eabi-gdb. I'm issuing commands using a token:

0-gdb-set trace-commands on
1-gdb-set logging on

And so forth. The reply from GDB is

0^done
1^done

The problem is that when issuing the command 2-gdb-set print repeats 0, GDB replies with 2^done, but IoManager._get_responses_windows() only reads ^done. As I'm using the tokens to match the commands with the replies, my SW fails.

To really check that it's a problem with pygdbmi, I tried to directly call arm-none-eabi-gdb with the following script:

gdb_args = [arm-none-eabi-gdb]
gdb_args.append('--init-command=.gdbinit')
gdb_args.append('--quiet')
gdb_args.append('--interpreter=mi3')

with open('gdb_stdout.txt', 'w') as f_out:

    gdb_process = subprocess.Popen(
        gdb_args,
        shell=False,
        stdout=f_out,
        stdin=subprocess.PIPE,
        stderr=subprocess.PIPE,
        bufsize=0,
    )
    gdb_process.stdin.write('0-gdb-set trace-commands on\n'.encode())
    time.sleep(0.5)
    gdb_process.stdin.write('1-gdb-set logging on\n'.encode())
    time.sleep(0.5)
    gdb_process.stdin.write('2-gdb-set print repeats 0\n'.encode())
    time.sleep(0.5)
    gdb_process.stdin.write('3-gdb-set print elements 0\n'.encode())
    time.sleep(0.5)

The gdb_stdout.txt file is

(gdb) 
~"+set trace-commands on\n"
0^done
(gdb) 
~"+set logging on\n"
~"Already logging to gdb.txt.\n"
1^done
(gdb) 
~"+set print repeats 0\n"
2^done
(gdb) 
~"+set print elements 0\n"
3^done
(gdb) 
~"Exception condition detected on fd 0\n"
~"error detected on stdin\n"

So, clearly, GDB is indeed replying 2^done

I've enabled debugging in IOManager with and also added some more debug statements:

logging.basicConfig(filename='example.log', level=logging.DEBUG)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
    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")
                logger.debug("raw stdout {}".format(repr(raw_output)))
                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")
                logger.debug("raw stderr {}".format(repr(raw_output)))
                responses_list += self._get_responses_list(raw_output, "stderr")
            except IOError:
                pass

And got:

DEBUG:pygdbmi.IoManager:writing: 2-gdb-set print repeats 0
DEBUG:pygdbmi.IoManager:raw stdout b'"+set print repeats 0\\n"\n\n'
DEBUG:pygdbmi.IoManager:{'message': None,
 'payload': '"+set print repeats 0\\n"',
 'stream': 'stdout',
 'type': 'output'}
DEBUG:pygdbmi.IoManager:raw stdout b'^done\n\n'
DEBUG:pygdbmi.IoManager:{'message': 'done',
 'payload': None,
 'stream': 'stdout',
 'token': None,
 'type': 'result'}

Looking at the gdb log, it's definitively printing the token:

~"+set print repeats 0\n"
2^done
(gdb) 

Please complete the following information:

  • OS: Windows 10 64 bits
  • pygdbmi version (pip freeze output): 0.10.0.0

Some responses dropped while debugging ARM microcontroller

Describe the bug
When using GdbController.write and parsing the responses, some responses are lost unless a very large timeout (> 1second) is used.

To Reproduce

  • Connect microcontroller (GigaDevice GD32E231C in my case) to PC
  • Create a OpenOCD connection to MCU in one terminal
  • Create a pygdbmi connection to MCU in another terminal with:
debugger = pygdbmi.gdbcontroller.GdbController(command=[gdb_path, "--interpreter=mi2"])
  • Use debugger.write(command, timeout_sec=2.0) commands to debug

Expected behavior
Everytime a command is executed with debugger.write, it would be expected to parse all of the available responses, but some responses are dropped. This, for example, is very bad when step-ing through a program and the stack-frame location is not updated all the time.

This is fixable by adding a debugger.get_gdb_response call after a debugger.write call with a delay of at least 1 second between them, but you can imagine that this is unusable, as commands usually take 400ms to execute with debugger.write and then an additional 1 second wait on top of that makes it very slow.

Please complete the following information:

  • OS: Windows 10 x64, Python 3.10
  • pygdbmi version (pip freeze output): 0.10.0.2

No symbol table is loaded

response = gdbmi.write('-break-insert main')
>>> pprint(response)
[{'message': u'error',
  'payload': {u'msg': u'No symbol table is loaded.  Use the "file" command.'},
  'stream': 'stdout',
  'token': None,
  'type': 'result'}]´

I tried to use it with a simple application I am compiling the application using g++
g++ TestFileMonitor.cpp -I./boost_1_55_0 -L./boost_1_55_0/stage/lib -l:libboost_thread.a -l:libboost_system.a -lpthread -g
If I try to debug it directly using gdb it works, if I use python (pygdbmi) it does not

#!/usr/bin/env python
from pygdbmi.gdbcontroller import GdbController
from pprint import pprint

# Start gdb process
gdbmi = GdbController()

# Load binary a.out and get structured response
response = gdbmi.write('-file-exec-file a.out')
pprint(response)
response = gdbmi.write('-break-insert main')
pprint(response)
response = gdbmi.write('next')
pprint(response)
response = gdbmi.exit()

Gdb version GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
Ubuntu Version: Linux VirtualBox 3.19.0-25-generic #26 ~ 14.04.1 - Ubuntu SMP Fri Jul 24 21:18:00 UTC 2015 i686 i686 i686 GNU/Linux

Waiting for a response after the response

while True:

Hello! If I understand correctly, the one way to exit from mentioned While loop - timeout. Maybe it could be better to add something like

            if len(responses) is not 0:
                if responses[-1].get('message') == 'done':
                    break

because right now, for example, inserting several breakpoints in windows takes (N_breakpionts * timeout) seconds. GdbController could already have a responce, but continue to wait a timeout.

Consider using a real language parser to parse MI output

Describe the bug
Currently, we use regular expressions to parse the GDB MI output. In #72 (review) Chad suggested we used a proper parser to do it:

NIce, this is much better!

Should we consider writing a grammar to simplify this more? Someone did this in rust for pygdbmi -- https://github.com/JP3BGY/gdbmi/blob/master/src/gdbmi_output.pest

We could use lark which has implementation in other languages for the same source .lark grammar.

I'm not keen to write a grammar (it's not something I've done since univeristy!) but, as we already have one we could use, this is a good idea.

To Reproduce
N/A

Expected behavior
No visible change to users (apart from performance improvements probably).

Screenshots
N/A

Please complete the following information:

  • OS: All
  • pygdbmi version (pip freeze output): master pre-0.10.0.3.

Additional context
N/A

Support for Intel's MPI debugging

When starting gdb from intel's mpirun using:

mpirun -gdb -gdb-args --interpreter=mi3 -n 2 ./my-prog 

output has an leading indicator of which processes are being debugged, for example:

[0,1] (mpigdb) run

which breaks the output parsing. By proxying the gdbmiparser.parse_response I can easily restore the structured output:

mpigdb_prefix = re.compile(r"^\s*(\(mpigdb\))?\s*\[[0-9,]+\]\s")
parse = gdbmiparser.parse_response 

def new_parse(a0, *args, **kwargs):
    newa0 = mpigdb_prefix.sub("", a0) 
    return parse(newa0, *args, **kwargs)

gdbmiparser.parse_response = new_parse

But the mpi rank information is lost. It would be nice if such information could be included in the parsed output.

Raise better exceptions

GdbController.write returns 3 types of errors, but all are identified with ValueError. This doesn't contribute much more than simply raising Exception. I'd suggest creating 3 Exception sub-classes which can correctly distinguish between them, since their severity is vastly different.

Documentation published to https://cs01.github.io/pygdbmi/ is out of date

Describe the bug
The published documentation is out of date. For example, the "Programmatic Control Over gdb" section referencesget_subprocess_cmd() which no longer exists. The readme file located at: https://github.com/cs01/pygdbmi/tree/v0.11.0.0/docs is updated, however.

To Reproduce
View https://cs01.github.io/pygdbmi/

Expected behavior
Documentation reflects current release

Screenshots
If applicable, add screenshots to help explain your problem.

Please complete the following information:

  • OS: N/A
  • pygdbmi version (pip freeze output): 0.11.0.0

Additional context
Add any other context about the problem here.

new behavior when running "run" command in GDB 8.1

In GDB 8.1, it seems when running "run" related command under MI, GDB will split output into two part and causing pygdbmi only catch the former part.
tempsnip
I've tried calling get_gdb_response() just after run command, it works at first "run", but whenever I call "run" again to restart program will raise GdbTimeOutError.
I'll post raw GDB MI output and pygdbmi output here, hope it helps.
First "run" in GDB:
image
Second "run" in GDB:
image
First "run" with pygdbmi:
image
Notice here pygdbmi catch breakpoint stopped event:
image
image
image
Second "run" with pygdbmi:
Trying to fetch second part causing timeout, and pygdbmi will never catch breakpoint stopped event.
image
image
image

-break-insert * address not supported

(gdb) -break-insert * 0x44a920
^error,msg="-break-insert: Garbage following "

(gdb) break * 0x44a920
&"break * 0x44a920\n"
~"Breakpoint 1 at 0x44a920\n"
=breakpoint-created,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="0x000000000044a920",thread-groups=["i1"],times="0",original-location="* 0x44a920"}
^done
(gdb)

Interrupt GDB

Is your feature request related to a problem? Please describe.

#26 This method has since been removed.

#42 The resolution of this issue may not be applicable in every scenario and not all GDB targets support it, while my use case can be solved using -gdb-set target-async on I still feel there should be a method for interrupting execution that works on all platforms.

Describe the solution you'd like

A method that works consistently in all environments with most GDB implementations.

Also the GdbController constructor should have an argument that controls how the process is going to be started with regards to the child process' group.

Describe alternatives you've considered

Currently this line works, sort of:

self.gdbmi.gdb_process.send_signal(signal.CTRL_C_EVENT)

However the issue is that the Signal is also received by Python itself, which in my case causes Pytest to end abruptly in a KeyboardInterrupt exception.

This problem can be fixed by changing the signal handler, or the better way is to assign a new group to the child process, on Unix it's os.setgpid(pid, gid) and on Windows subprocess.Popen(command, ..., creationflags=subprocess.CREATE_NEW_PROCESS_GROUP).

Environment:

  • OS: Windows 10
  • pygdbmi version: 0.10.0.0

Missing send_signal_to_gdb() and interrupt_gdb() of GdbController

The documentation shows two methods on objects of class GdbController which are not supported:

response = gdbmi.send_signal_to_gdb('SIGKILL')  # name of signal is okay
response = gdbmi.interrupt_gdb()  # sends SIGINT to gdb

There appear to be no equivalent methods available.

Refering to 0.11.0.0 release.

Add ability to wait (with timeout) for the (gdb) "prompt".

Is your feature request related to a problem? Please describe.
I am looking into enhancing one of my project that is using a self written way to talk to gdb/mi and in that project I read some data with single commands and the result comes in chunks over tens of seconds. In my code I normally wait for the (gdb) string, which indicates that gdb is done writing the data, however trying pygdbmi the read functionality (_get_responses_unix) seems to entirely be based on timeouts.

Describe the solution you'd like
Add an option ( or make it the default ) to wait for the (gdb) prompt to indicate a commands output completion. Ideally one would have two timeouts: one for the whole read operation of all output, and one for the time after the last data is read.

Describe alternatives you've considered
Getting the data myself and just using pygdbmi as a parser, but thats probably not as neat.

Additional context
Add any other context or screenshots about the feature request here.

IoManager._get_responses_windows self.stdout.readline() stuck

I'm using pygdbmi to drive an embedded system, and so far everything works great. I can load an embedded application, I can set breakpoints, I can run, I can stop. and I can use -data-list-register-values x for one of my company's products, which runs an Arm Cortex-M3 cpu.

I recently started to use the same code for another product. This second product uses an Arm Cortex-M33 CPU, and pretty much all the commands work file with it, with the exception of -data-list-register-values x.

My setup is this: both CPUs are using a JLink adapter, so I'm interfacing them through JLinkGDBServerCL.exe.

My test code is:

import unittest
import subprocess
import time

from pprint import pprint

from pygdbmi.gdbcontroller import GdbController

from gdbdrivermi import kill_synopsys_tools

import logging
logging.basicConfig(filename='myapp.log', level=logging.DEBUG)

class TestPyGDBMI(unittest.TestCase):

    def test_connect(self):
        command = [
            'C:\\Program Files (x86)\\SEGGER\\JLink_V694d\\JLinkGDBServerCL.exe',
            '-select', 'USB', '-if', 'SWD', '-device', 'RSL15', '-endian',
            'little', '-speed', '1000', '-port', '2331', '-vd', '-ir',
            '-localhostonly', '1', '-noreset', '-singlerun', '-strict',
            '-timeout 0', '-nogui']

        # Use pipes to the standard streams
        gdbServer = subprocess.Popen(command,
            shell=False,
            stdout=subprocess.PIPE,
            stdin=subprocess.PIPE,
            stderr=subprocess.PIPE,
            bufsize=0,
        )

        gdb_command = ['C:\\Program Files (x86)\\ON Semiconductor\\IDE\\arm_tools\\bin\\arm-none-eabi-gdb.exe',
                        '--nx', '--quiet', '--interpreter=mi3']

        # Start gdb process
        gdbmi = GdbController(command=gdb_command, 
                              time_to_check_for_additional_output_sec=3)

        response = gdbmi.write('-gdb-set trace-commands on', timeout_sec=5)
        pprint(response)

        response = gdbmi.write('-gdb-set logging on', timeout_sec=5)
        pprint(response)

        response = gdbmi.write('-target-select remote localhost:2331', timeout_sec=5)
        pprint(response)

        response = gdbmi.write('-interpreter-exec console "monitor reset "', timeout_sec=5)
        pprint(response)

        response = gdbmi.write('-interpreter-exec console "monitor halt"', timeout_sec=5)
        pprint(response)

        response = gdbmi.write('-file-exec-and-symbols blinky.elf', timeout_sec=5)
        pprint(response)

        response = gdbmi.write('-target-download', timeout_sec=5)
        pprint(response)

        response = gdbmi.write('-break-insert  main', timeout_sec=5)
        pprint(response)

        response = gdbmi.write('continue&', timeout_sec=5)
        pprint(response)

        response = gdbmi.write('-data-list-register-names', timeout_sec=5)
        pprint(response)

        response = gdbmi.write('-data-list-register-values x', timeout_sec=10)
        pprint(response)

        assert True

if __name__ == '__main__':
    unittest.main()

Everything works 100 % fine until I send -data-list-register-values x, then GdbController gets stuck and I can't receive anything from GDB.

If I start JLinkGDBServerCL.exe and arm-none-eabi-gdb.exe and use the exact same sequence of commands, I get a nice reply:

Starting GDB server:

"C:\Program Files (x86)\SEGGER\JLink_V694d\JLinkGDBServerCL.exe" -select USB -if SWD -device RSL15 -endian little -speed 1000 -port 2331 -vd -ir -localhostonly 1 -noreset -singlerun -strict -timeout 0 -nogui

Running GDB Arm:

"C:\Program Files (x86)\ON Semiconductor\IDE\arm_tools\bin\arm-none-eabi-gdb.exe" --nx --quiet --interpreter=mi3
C:\Program Files (x86)\ON Semiconductor\IDE\arm_tools\bin\arm-none-eabi-gdb.exe: warning: Couldn't determine a path for the index cache directory.
=thread-group-added,id="i1"
(gdb)
-gdb-set trace-commands on
^done
(gdb)
-gdb-set logging on
~"+set logging on\n"
^done
(gdb)
-target-select remote localhost:2331
~"+target remote localhost:2331\n"
=thread-group-started,id="i1",pid="42000"
&"warning: No executable has been specified and target does not support\ndetermining executable automatically.  Try using the \"file\" command."
&"\n"
=thread-created,id="1",group-id="i1"
~"0x00000000 in ?? ()\n"
*stopped,frame={addr="0x00000000",func="??",args=[],arch="arm"},thread-id="1",stopped-threads="all"
^connected
(gdb)
-interpreter-exec console "monitor reset "
~"+monitor reset \n"
@"Resetting target\r\n"
^done
(gdb)
-interpreter-exec console "monitor halt"
~"+monitor halt\n"
^done
(gdb)
-file-exec-and-symbols blinky.elf
~"+file blinky.elf\n"
^done
(gdb)
-target-download
~"+load \n"
+download,{section=".text",section-size="6840",total-size="59929"}
+download,{section=".text",section-sent="6840",section-size="6840",total-sent="6840",total-size="59929"}
+download,{section=".ARM.exidx.reset",section-size="8",total-size="59929"}
+download,{section=".data",section-size="5240",total-size="59929"}
^done,address="0x100124",load-size="12088",transfer-rate="1179312",write-rate="4029"
(gdb)
-break-insert  main
^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="0x00100540",func="main",file="C:/git/blinky/app.c",fullname="C:\\git\\blinky\\app.c",line="144",thread-groups=["i1"],times="0",original-location="main"}
(gdb)
continue&
&"continue&\n"
~"+continue&\n"
~"Continuing.\n"
^running
*running,thread-id="all"
(gdb)
~"\nProgram"
~" received signal SIGTRAP, Trace/breakpoint trap.\n"
~"0xeffffffe in ?? ()\n"
*stopped,reason="signal-received",signal-name="SIGTRAP",signal-meaning="Trace/breakpoint trap",frame={addr="0xeffffffe",func="??",args=[],arch="armv8-m.main"},thread-id="1",stopped-threads="all"
-data-list-register-names
^done,register-names=["r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12","sp","lr","pc","","","","","","","","","","xpsr","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","msp","psp","primask","basepri","faultmask","control","fpscr","s0","s1","s2","s3","s4","s5","s6","s7","s8","s9","s10","s11","s12","s13","s14","s15","s16","s17","s18","s19","s20","s21","s22","s23","s24","s25","s26","s27","s28","s29","s30","s31","d0","d1","d2","d3","d4","d5","d6","d7","d8","d9","d10","d11","d12","d13","d14","d15","msp_s","msplim_s","psp_s","psplim_s","msp_ns","msplim_ns","psp_ns","psplim_ns","control_s","faultmask_s","basepri_s","primask_s","control_ns","faultmask_ns","basepri_ns","primask_ns"]
(gdb)
-data-list-register-values x
^done,register-values=[{number="0",value="0x0"},{number="1",value="0x0"},{number="2",value="0x0"},{number="3",value="0x80730"},{number="4",value="0x40000100"},{number="5",value="0x101"},{number="6",value="0x3ff01"},{number="7",value="0x0"},{number="8",value="0xffffffff"},{number="9",value="0x40001430"},{number="10",value="0xffffffff"},{number="11",value="0xffffffff"},{number="12",value="0xffffffff"},{number="13",value="0x20001e58"},{number="14",value="0x20001e69"},{number="15",value="0xeffffffe"},{number="25",value="0x41000003"},{number="91",value="0x20001e58"},{number="92",value="0x0"},{number="93",value="0x1"},{number="94",value="0x0"},{number="95",value="0x0"},{number="96",value="0x0"},{number="97",value="0x0"},{number="98",value="0x0"},{number="99",value="0x0"},{number="100",value="0x0"},{number="101",value="0x0"},{number="102",value="0x0"},{number="103",value="0x0"},{number="104",value="0x0"},{number="105",value="0x0"},{number="106",value="0x0"},{number="107",value="0x0"},{number="108",value="0x0"},{number="109",value="0x0"},{number="110",value="0x0"},{number="111",value="0x0"},{number="112",value="0x0"},{number="113",value="0x0"},{number="114",value="0x0"},{number="115",value="0x0"},{number="116",value="0x0"},{number="117",value="0x0"},{number="118",value="0x0"},{number="119",value="0x0"},{number="120",value="0x0"},{number="121",value="0x0"},{number="122",value="0x0"},{number="123",value="0x0"},{number="124",value="0x0"},{number="125",value="0x0"},{number="126",value="0x0"},{number="127",value="0x0"},{number="128",value="0x0"},{number="129",value="0x0"},{number="130",value="0x0"},{number="131",value="0x0"},{number="132",value="0x0"},{number="133",value="0x0"},{number="134",value="0x0"},{number="135",value="0x0"},{number="136",value="0x0"},{number="137",value="0x0"},{number="138",value="0x0"},{number="139",value="0x0"},{number="140",value="0x0"},{number="141",value="0x0"},{number="142",value="0x0"},{number="143",value="0x0"},{number="144",value="0x0"},{number="145",value="0x0"},{number="146",value="0x20001e58"},{number="147",value="0x0"},{number="148",value="0x0"},{number="149",value="0x0"},{number="150",value="0x0"},{number="151",value="0x0"},{number="152",value="0xfffffffc"},{number="153",value="0x0"},{number="154",value="0x0"},{number="155",value="0x0"},{number="156",value="0x0"},{number="157",value="0x1"},{number="158",value="0x0"},{number="159",value="0x0"},{number="160",value="0x0"},{number="161",value="0x0"}]
(gdb)

So, this discards JLinkGDBServerCL.exe and arm-none-eabi-gdb.exe. I've attached the log as gdb_works.txt

Next, I added some log statements in IoManager._get_responses_windows:

    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 = []

        logger.debug("_get_responses_windows 109")

        while True:
            responses_list = []
            #logger.debug("_get_responses_windows 113")
            try:
                self.stdout.flush()
                raw_output = self.stdout.readline().replace(b"\r", b"\n")
                logger.debug(f"raw_output 117 {raw_output}")
                responses_list = self._get_responses_list(raw_output, "stdout")
            except IOError as e:
                pass

            try:
                self.stderr.flush()
                raw_output = self.stderr.readline().replace(b"\r", b"\n")
                logger.debug(f"raw_output 126 {raw_output}")
                responses_list += self._get_responses_list(raw_output, "stderr")
            except IOError as e:
                pass

Looking at the log file, for the commands that produce a reply, I can see:

DEBUG:pygdbmi.IoManager:writing: -data-list-register-names
DEBUG:pygdbmi.IoManager:_get_responses_windows 109
DEBUG:pygdbmi.IoManager:raw_output 117 b'^done,register-names=["r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12","sp","lr","pc","","","","","","","","","","xpsr","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","msp","psp","primask","basepri","faultmask","control","fpscr","s0","s1","s2","s3","s4","s5","s6","s7","s8","s9","s10","s11","s12","s13","s14","s15","s16","s17","s18","s19","s20","s21","s22","s23","s24","s25","s26","s27","s28","s29","s30","s31","d0","d1","d2","d3","d4","d5","d6","d7","d8","d9","d10","d11","d12","d13","d14","d15","msp_s","msplim_s","psp_s","psplim_s","msp_ns","msplim_ns","psp_ns","psplim_ns","control_s","faultmask_s","basepri_s","primask_s","control_ns","faultmask_ns","basepri_ns","primask_ns"]\n\n'
DEBUG:pygdbmi.IoManager:_get_responses_list (b'^done,register-names=["r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","r10'
 b'","r11","r12","sp","lr","pc","","","","","","","","","","xpsr","","","","","'
 b'","","","","","","","","","","","","","","","","","","","","","","","","",""'
 b',"","","","","","","","","","","","","","","","","","","","","","","","","",'
 b'"","","","","","","","","","","msp","psp","primask","basepri","faultmask","c'
 b'ontrol","fpscr","s0","s1","s2","s3","s4","s5","s6","s7","s8","s9","s10","s11'
 b'","s12","s13","s14","s15","s16","s17","s18","s19","s20","s21","s22","s23","s'
 b'24","s25","s26","s27","s28","s29","s30","s31","d0","d1","d2","d3","d4","d5",'
 b'"d6","d7","d8","d9","d10","d11","d12","d13","d14","d15","msp_s","msplim_s","'
 b'psp_s","psplim_s","msp_ns","msplim_ns","psp_ns","psplim_ns","control_s","fau'
 b'ltmask_s","basepri_s","primask_s","control_ns","faultmask_ns","basepri_ns","'
 b'primask_ns"]\n\n')
DEBUG:pygdbmi.IoManager:{'message': 'done',
 'payload': {'register-names': ['r0',
                                'r1',
                                'r2',
                                'r3',
                                'r4',
                                'r5',
                                'r6',
                                'r7',
                                'r8',
                                'r9',
                                'r10',
                                'r11',
                                'r12',
                                'sp',
                                'lr',
                                'pc',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                'xpsr',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                '',
                                'msp',
                                'psp',
                                'primask',
                                'basepri',
                                'faultmask',
                                'control',
                                'fpscr',
                                's0',
                                's1',
                                's2',
                                's3',
                                's4',
                                's5',
                                's6',
                                's7',
                                's8',
                                's9',
                                's10',
                                's11',
                                's12',
                                's13',
                                's14',
                                's15',
                                's16',
                                's17',
                                's18',
                                's19',
                                's20',
                                's21',
                                's22',
                                's23',
                                's24',
                                's25',
                                's26',
                                's27',
                                's28',
                                's29',
                                's30',
                                's31',
                                'd0',
                                'd1',
                                'd2',
                                'd3',
                                'd4',
                                'd5',
                                'd6',
                                'd7',
                                'd8',
                                'd9',
                                'd10',
                                'd11',
                                'd12',
                                'd13',
                                'd14',
                                'd15',
                                'msp_s',
                                'msplim_s',
                                'psp_s',
                                'psplim_s',
                                'msp_ns',
                                'msplim_ns',
                                'psp_ns',
                                'psplim_ns',
                                'control_s',
                                'faultmask_s',
                                'basepri_s',
                                'primask_s',
                                'control_ns',
                                'faultmask_ns',
                                'basepri_ns',
                                'primask_ns']},
 'stream': 'stdout',
 'token': None,
 'type': 'result'}

OK, so far so good, but when I send -data-list-register-values x:

DEBUG:pygdbmi.IoManager:writing: -data-list-register-values x
DEBUG:pygdbmi.IoManager:_get_responses_windows 109

And that's it, I don't get a DEBUG:pygdbmi.IoManager:raw_output debug message. This tells me that _get_responses_windows keeps looping forever catching IOError exceptions until it times out.

If I look at the gdb.txt file, GDB seems to be replying with the register values:

^done,register-values=[{number="0",value="0x0"},{number="1",value="0x0"},{number="2",value="0x0"},{number="3",value="0x80730"},{number="4",value="0x40000100"},{number="5",value="0x101"},{number="6",value="0x3ff01"},{number="7",value="0x0"},{number="8",value="0xffffffff"},{number="9",value="0x40001430"},{number="10",value="0xffffffff"},{number="11",value="0xffffffff"},{number="12",value="0xffffffff"},{number="13",value="0x20001e58"},{number="14",value="0x20001e69"},{number="15",value="0xeffffffe"},{number="25",value="0x41000003"},{number="91",value="0x20001e58"},{number="92",value="0x0"},{number="93",value="0x1"},{number="94",value="0x0"},{number="95",value="0x0"},{number="96",value="0x0"},{number="97",value="0x0"},{number="98",value="0x0"},{number="99",value="0x0"},{number="100",value="0x0"},{number="101",value="0x0"},{number="102",value="0x0"},{number="103",value="0x0"},{number="104",value="0x0"},{number="105",value="0x0"},{number="106",value="0x0"},{number="107",value="0x0"},{number="108",value="0x0"},{number="109",value="0x0"},{number="110",value="0x0"},{number="111",value="0x0"},{number="112",value="0x0"},{number="113",value="0x0"},{number="114",value="0x0"},{number="115",value="0x0"},{number="116",value="0x0"},{number="117",value="0x0"},{number="118",value="0x0"},{number="119",value="0x0"},{number="120",value="0x0"},{number="121",value="0x0"},{number="122",value="0x0"},{number="123",value="0x0"},{number="124",value="0x0"},{number="125",value="0x0"},{number="126",value="0x0"},{number="127",value="0x0"},{number="128",value="0x0"},{number="129",value="0x0"},{number="130",value="0x0"},{number="131",value="0x0"},{number="132",value="0x0"},{number="133",value="0x0"},{number="134",value="0x0"},{number="135",value="0x0"},{number="136",value="0x0"},{number="137",value="0x0"},{number="138",value="0x0"},{number="139",value="0x0"},{number="140",value="0x0"},{number="141",value="0x0"},{number="142",value="0x0"},{number="143",value="0x0"},{number="144",value="0x0"},{number="145",value="0x0"},{number="146",value="0x20001e58"},{number="147",value="0x0"},{number="148",value="0x0"},{number="149",value="0x0"},{number="150",value="0x0"},{number="151",value="0x0"},{number="152",value="0xfffffffc"},{number="153",value="0x0"},{number="154",value="0x0"},{number="155",value="0x0"},{number="156",value="0x0"},{number="157",value="0x1"},{number="158",value="0x0"},{number="159",value="0x0"},{number="160",value="0x0"},{number="161",value="0x0"}]
(gdb) 
~"Exception condition detected on fd 0\n"
~"error detected on stdin\n"

The last two lines are specially worrisome:

~"Exception condition detected on fd 0\n"
~"error detected on stdin\n"

Any ideas on how to test if the stdout PIPE is stuck?

I've attached pygdbmi log file (myapp.log), and GDB's log (gdb.txt).

myapp.log

Many thanks!!!

Please complete the following information:

  • OS: Windows 10 64 bits
  • Python: Python 3.8.5
  • pygdbmi version (pip freeze output):
pip freeze
-ffi @ file:///C:/ci/cffi_1600695147257/work
alabaster==0.7.12
anaconda-client==1.7.2
anaconda-navigator==1.10.0
anaconda-project==0.8.3
# Editable install with no version control (antigravity==0.0.1)
-e c:\git\swt_root\new_project
appdirs==1.4.4
argh==0.26.2
argon2-cffi @ file:///C:/ci/argon2-cffi_1596828587441/work
asn1crypto @ file:///tmp/build/80754af9/asn1crypto_1596577642040/work
astroid @ file:///C:/ci/astroid_1592495994461/work
astropy==4.0.2
astunparse==1.6.3
async-generator==1.10
atomicwrites==1.4.0
attrs @ file:///tmp/build/80754af9/attrs_1604765588209/work
autopep8 @ file:///tmp/build/80754af9/autopep8_1596578164842/work
Babel @ file:///tmp/build/80754af9/babel_1605108370292/work
backcall==0.2.0
backports.functools-lru-cache==1.6.1
backports.shutil-get-terminal-size==1.0.0
backports.tempfile==1.0
backports.weakref==1.0.post1
bcrypt @ file:///C:/ci/bcrypt_1597918155848/work
beautifulsoup4 @ file:///tmp/build/80754af9/beautifulsoup4_1601924105527/work
behave==1.2.6
-e git+ssh://[email protected]/asgswm/test-infrastructure.git@7539ba6f22e32ab2cebf31535f644b566028a5cd#egg=behave_steps_common&subdirectory=behave_steps_common
bitarray @ file:///C:/ci/bitarray_1605047058594/work
bkcharts==0.2
bleach @ file:///tmp/build/80754af9/bleach_1600439572647/work
bokeh @ file:///C:/ci/bokeh_1603279774334/work
boto==2.49.0
Bottleneck==1.3.2
brotlipy==0.7.0
-e git+ssh://[email protected]/asgswm/test-infrastructure.git@7539ba6f22e32ab2cebf31535f644b566028a5cd#egg=buildtoolchain&subdirectory=buildtoolchain
certifi==2020.6.20
cffi==1.14.5
chardet==3.0.4
chevron==0.14.0
click==7.1.2
cloudpickle @ file:///tmp/build/80754af9/cloudpickle_1598884132938/work
clyent==1.2.2
colorama @ file:///tmp/build/80754af9/colorama_1603211150991/work
comtypes==1.1.7
conda==4.9.2
conda-build==3.20.5
conda-package-handling @ file:///C:/ci/conda-package-handling_1603004884858/work
conda-verify==3.4.2
contextlib2==0.6.0.post1
cryptography @ file:///C:/ci/cryptography_1598892121735/work
-e git+ssh://[email protected]/asgswm/test-infrastructure.git@7539ba6f22e32ab2cebf31535f644b566028a5cd#egg=ctkdriver&subdirectory=ctkdriver
cycler==0.10.0
Cython @ file:///C:/ci/cython_1594830140812/work
cytoolz==0.11.0
dask @ file:///tmp/build/80754af9/dask-core_1602083700509/work
decorator==4.4.2
defusedxml==0.6.0
diff-match-patch @ file:///tmp/build/80754af9/diff-match-patch_1594828741838/work
distlib==0.3.1
distributed @ file:///C:/ci/distributed_1605066638460/work
docutils==0.16
-e git+ssh://[email protected]/asgswm/doxygenflare.git@56a4d9dc68100680f2a23c403aad54cc9472aad4#egg=DoxygenFlare
entrypoints==0.3
et-xmlfile==1.0.1
fastcache==1.1.0
filelock==3.0.12
flake8 @ file:///tmp/build/80754af9/flake8_1601911421857/work
Flask==1.1.2
fs==2.4.12
fsspec @ file:///tmp/build/80754af9/fsspec_1602684995936/work
future==0.18.2
-e git+ssh://[email protected]/asgswm/test-infrastructure.git@7539ba6f22e32ab2cebf31535f644b566028a5cd#egg=gdbdrivermi&subdirectory=gdbdrivermi
gevent @ file:///C:/ci/gevent_1602672263874/work
glob2==0.7
greenlet @ file:///C:/ci/greenlet_1600869667188/work
h5py==2.10.0
HeapDict==1.0.1
html2text==2020.1.16
html5lib @ file:///tmp/build/80754af9/html5lib_1593446221756/work
idna @ file:///tmp/build/80754af9/idna_1593446292537/work
imageio @ file:///tmp/build/80754af9/imageio_1594161405741/work
imagesize==1.2.0
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1602276842396/work
iniconfig @ file:///tmp/build/80754af9/iniconfig_1602780191262/work
intervaltree @ file:///tmp/build/80754af9/intervaltree_1598376443606/work
ipykernel @ file:///C:/ci/ipykernel_1596208574668/work/dist/ipykernel-5.3.4-py3-none-any.whl
ipython @ file:///C:/ci/ipython_1604083205321/work
ipython-genutils==0.2.0
ipywidgets @ file:///tmp/build/80754af9/ipywidgets_1601490159889/work
isort @ file:///tmp/build/80754af9/isort_1602603989581/work
itsdangerous==1.1.0
jdcal==1.4.1
jedi @ file:///C:/ci/jedi_1592831614595/work
Jinja2==2.11.2
joblib @ file:///tmp/build/80754af9/joblib_1601912903842/work
json5==0.9.5
jsonschema @ file:///tmp/build/80754af9/jsonschema_1602607155483/work
jupyter==1.0.0
jupyter-client @ file:///tmp/build/80754af9/jupyter_client_1601311786391/work
jupyter-console @ file:///tmp/build/80754af9/jupyter_console_1598884538475/work
jupyter-core==4.6.3
jupyterlab==2.2.6
jupyterlab-pygments @ file:///tmp/build/80754af9/jupyterlab_pygments_1601490720602/work
jupyterlab-server @ file:///tmp/build/80754af9/jupyterlab_server_1594164409481/work
keyring @ file:///C:/ci/keyring_1598866735485/work
kiwisolver==1.3.1
lazy-object-proxy==1.4.3
libarchive-c==2.9
llvmlite==0.34.0
locket==0.2.0
lxml==4.6.2
markdown2==2.3.10
MarkupSafe==1.1.1
matplotlib==3.3.4
mccabe==0.6.1
menuinst==1.4.16
mistune==0.8.4
mkl-fft==1.2.0
mkl-random==1.1.1
mkl-service==2.3.0
mock==4.0.2
more-itertools @ file:///tmp/build/80754af9/more-itertools_1605111547926/work
mpmath==1.1.0
msgpack==1.0.0
multipledispatch==0.6.0
navigator-updater==0.2.1
nbclient @ file:///tmp/build/80754af9/nbclient_1602783176460/work
nbconvert @ file:///C:/ci/nbconvert_1602277416184/work
nbformat @ file:///tmp/build/80754af9/nbformat_1602783287752/work
nest-asyncio @ file:///tmp/build/80754af9/nest-asyncio_1605115881283/work
networkx @ file:///tmp/build/80754af9/networkx_1598376031484/work
nltk @ file:///tmp/build/80754af9/nltk_1592496090529/work
nose==1.3.7
notebook @ file:///C:/ci/notebook_1602668179504/work
numba==0.51.2
numexpr==2.7.1
numpy==1.20.1
numpydoc @ file:///tmp/build/80754af9/numpydoc_1605117425582/work
olefile==0.46
-e git+ssh://[email protected]/asgswm/test-infrastructure.git@7539ba6f22e32ab2cebf31535f644b566028a5cd#egg=onsemiaudio&subdirectory=onsemiaudio
openpyxl @ file:///tmp/build/80754af9/openpyxl_1598113097404/work
packaging==20.4
pandas @ file:///C:/ci/pandas_1602070092559/work
pandocfilters @ file:///C:/ci/pandocfilters_1605102367649/work
paramiko @ file:///tmp/build/80754af9/paramiko_1598886428689/work
paramiko-expect==0.2.8
parse==1.19.0
parse-type==0.5.2
parso==0.7.0
partd==1.1.0
path @ file:///C:/ci/path_1598376662686/work
pathlib2==2.3.5
pathtools==0.1.2
patsy==0.5.1
pdoc==1.1.0
pep8==1.7.1
pexpect==4.8.0
pickleshare==0.7.5
Pillow==8.1.0
pkginfo==1.6.1
pluggy==0.13.1
ply==3.11
prometheus-client==0.8.0
prompt-toolkit @ file:///tmp/build/80754af9/prompt-toolkit_1602688806899/work
psutil==5.8.0
ptyprocess==0.7.0
py @ file:///tmp/build/80754af9/py_1593446248552/work
pycodestyle==2.6.0
pycosat==0.6.3
pycparser==2.20
pycurl==7.43.0.6
pydash==4.9.2
pydocstyle @ file:///tmp/build/80754af9/pydocstyle_1598885001695/work
-e git+https://github.com/nathanhi/pyfatfs.git@6b9fd267852eb06a4b09b8e7995ad1e778e766a4#egg=pyfatfs
pyflakes==2.2.0
-e git+https://github.com/cs01/pygdbmi.git@23358b9bf6b4957eaac70b579b6858fa4395538a#egg=pygdbmi
Pygments @ file:///tmp/build/80754af9/pygments_1604103097372/work
PyHamcrest==2.0.2
pylink-square==0.8.2
pylint @ file:///C:/ci/pylint_1598624093998/work
PyNaCl @ file:///C:/ci/pynacl_1595009196976/work
pyodbc===4.0.0-unsupported
pyOpenSSL @ file:///tmp/build/80754af9/pyopenssl_1594392929924/work
pyparsing==2.4.7
pyreadline==2.1
pyrsistent @ file:///C:/ci/pyrsistent_1600141795660/work
PySocks==1.7.1
pystache==0.5.4
pytest==0.0.0
python-dateutil==2.8.1
python-jsonrpc-server @ file:///tmp/build/80754af9/python-jsonrpc-server_1600278539111/work
python-language-server @ file:///tmp/build/80754af9/python-language-server_1600454544709/work
pytz==2020.1
PyWavelets==1.1.1
pywin32==227
pywin32-ctypes==0.2.0
pywinpty==0.5.7
PyYAML==5.3.1
pyzmq==19.0.2
QDarkStyle==2.8.1
QtAwesome @ file:///tmp/build/80754af9/qtawesome_1602272867890/work
qtconsole @ file:///tmp/build/80754af9/qtconsole_1600870028330/work
QtPy==1.9.0
regex @ file:///C:/ci/regex_1602770258877/work
requests @ file:///tmp/build/80754af9/requests_1592841827918/work
rope @ file:///tmp/build/80754af9/rope_1602264064449/work
Rtree==0.9.4
ruamel-yaml==0.15.87
scikit-image==0.16.2
scikit-learn @ file:///C:/ci/scikit-learn_1592863447244/work
scipy==1.6.0
seaborn @ file:///tmp/build/80754af9/seaborn_1600553570093/work
Send2Trash==1.5.0
simplegeneric==0.8.1
singledispatch @ file:///tmp/build/80754af9/singledispatch_1602523705405/work
sip==4.19.13
six==1.15.0
snowballstemmer==2.0.0
sortedcollections==1.2.1
sortedcontainers==2.2.2
sounddevice==0.4.1
soupsieve==2.0.1
Sphinx @ file:///tmp/build/80754af9/sphinx_1597428793432/work
sphinx-markdown-builder==0.5.4
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==1.0.3
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.4
sphinxcontrib-websupport @ file:///tmp/build/80754af9/sphinxcontrib-websupport_1597081412696/work
spyder @ file:///C:/ci/spyder_1599052052164/work
spyder-kernels @ file:///C:/ci/spyder-kernels_1599052729967/work
SQLAlchemy @ file:///C:/ci/sqlalchemy_1603819281407/work
statsmodels==0.12.0
sympy @ file:///C:/ci/sympy_1605119639065/work
tables==3.6.1
tblib @ file:///tmp/build/80754af9/tblib_1597928476713/work
terminado==0.9.1
testpath==0.4.4
threadpoolctl @ file:///tmp/tmp9twdgx9k/threadpoolctl-2.1.0-py3-none-any.whl
toml @ file:///tmp/build/80754af9/toml_1592853716807/work
toolz @ file:///tmp/build/80754af9/toolz_1601054250827/work
tornado==6.0.4
tox==3.21.4
tqdm @ file:///tmp/build/80754af9/tqdm_1602185206534/work
traitlets @ file:///tmp/build/80754af9/traitlets_1602787416690/work
typing-extensions @ file:///tmp/build/80754af9/typing_extensions_1598376058250/work
ujson @ file:///C:/ci/ujson_1602507951182/work
unicodecsv==0.14.1
unify==0.5
untokenize==0.1.1
urllib3 @ file:///tmp/build/80754af9/urllib3_1603305693037/work
virtualenv==20.4.2
watchdog @ file:///C:/ci/watchdog_1593447396356/work
wcwidth @ file:///tmp/build/80754af9/wcwidth_1593447189090/work
webencodings==0.5.1
Werkzeug==1.0.1
wexpect==4.0.0
widgetsnbextension==3.5.1
win-inet-pton==1.1.0
win-unicode-console==0.5
wincertstore==0.2
wrapt==1.11.2
xlrd==1.2.0
XlsxWriter @ file:///tmp/build/80754af9/xlsxwriter_1602692860603/work
xlwings==0.20.8
xlwt==1.3.0
xmltodict==0.12.0
yapf @ file:///tmp/build/80754af9/yapf_1593528177422/work
zict==2.0.0
zipp @ file:///tmp/build/80754af9/zipp_1604001098328/work
zope.event==4.5.0
zope.interface @ file:///C:/ci/zope.interface_1598606124374/work

interrupt_gdb terminates gdb [win]

Im currently facing an issue where gdb silently terminates when i execute interrupt_gdb().
I think it's a windows and or gdb version related problem. It's very annoying because i can not halt the target.

System: Windows 10
Gdb: GNU gdb (GNU Tools for ARM Embedded Processors) 7.10.1.20160616-cvs
pygdbmi: v0.9.0.3

from pygdbmi.gdbcontroller import GdbController

gdbmi = GdbController(gdb_path="arm-none-eabi-gdb")

gdbmi.write("symbol-file application.axf")
gdbmi.write("-target-select remote localhost:2331")
gdbmi.write("-exec-continue")
gdbmi.interrupt_gdb()
gdbmi.write("-exec-continue")

The last command yields to the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "python-3.6.6.amd64\lib\site-packages\pygdbmi\gdbcontroller.py", line 204, in write
    self.verify_valid_gdb_subprocess()
  File "python-3.6.6.amd64\lib\site-packages\pygdbmi\gdbcontroller.py", line 180, in verify_valid_gdb_subprocess
    % str(self.gdb_process.poll())
pygdbmi.gdbcontroller.NoGdbProcessError: gdb process has already finished with return code: 2

Any ideas how to solve this?

over-processed escape characters?

in regular gdb, if I print a json, result:
image
in gdb with --interpreter=mi2 , if I print the same json, result:
image
in pygdbmi , if I print the same json, result:
image
so imo, the mi added escape characters in output stream automatically, and pygdbmi did it again
should I parse the payload twice (or three times 'cause origin string still contains \ and json parser won't accept it) to get correct json array string or is there any better way suggested?

missing sdist on pypi for 0.9.0.1

I need the "tests" exclusion to build an wheel for this, because my build system is complaining about "tests" and my automated whl builder can only see the source for 0.9.0.0. I'm not allowed to use whls from the internet because of security policies.

Incompatible behavior in GDB command line and pygdbmi

Is your feature request related to a problem? Please describe.
I have an example program that printf's a variable i in a fixed loop from 0 to 3.
When I run the same in GDB as:
gdb --interpreter=mi3 a.out
-break-insert main
-exec-run
then repeatedly do -exec-step

This way I can see the stdout of my small test program with the MI3 messages intermixed, all fitting to the program flow.

I see no way to achieve the same in pygdbmi. The output of my program is only seen after it exits. So I can first see the program flow and after that I can see the output, but I can't link this to the program flow any more.

Describe the solution you'd like
This behavior is the behavior of gdb itself, when doing subprocess.Popen on gdb and doing the same steps, I can see the same behavior. So I don't think this is a bug of pygdbmi. gdb outputs the data this way. But the behavior does not help, some compatibility way would help, or any other way to link the output to the lines that produced them. If I run the same program in a /bin/bash or using pygdbmi, I see different behavior.

Describe alternatives you've considered
I tried subprocess.Popen in an own script but got the same behavior.

Additional context
I run gdb-10.1 on Linux

My test program is:
#include "stdio.h"
#include "stdlib.h"

void fct(void) {
for(int i = 0; i < 3; i++) {
printf("i %d\n", i);
}
}

int main(int argc, char** argv) {
printf("Hi there\n");

fct();

return EXIT_SUCCESS;
}

add async interfaces

Add async alternatives to all sync methods. This will make pygdbmi more efficient because it will be event-based, not polling based.

Version of code descrepancy?

Salutations,

Firstly awesome project.

I am still investigating this issue as it appears to be odd.

To the issue, I was noticing that nexti commands weren't always handled the same when I saw odd skips in certain places in a program. I noticed some oddity where nexti on mov ebp, esp was resulting the program running past the next instruction.

Anyway, I thought to look and see if I was supposed to perform the next . I looked at the example code and there is the command responses = gdbmi.write("-exec-next") This appears to now be removed from the code?

Is this command supposed to handle next differently ? Should it be ok to just call nexti as responses = gdbmi.write("nexti")

Unable to install pygdbmi==0.7.4.2 ImportError: cannot import name 'POINTER'

When trying to install pygdbmi==0.7.4.2 I get the below error:

C:\> pip install pygdbmi
Collecting pygdbmi
  Using cached pygdbmi-0.7.4.2.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "C:\Users\ago\AppData\Local\Temp\pip-build-j0g63a_a\pygdbmi\setup.py", line 5, in <module>
        from pygdbmi.tests import test_app
      File "C:\Users\ago\AppData\Local\Temp\pip-build-j0g63a_a\pygdbmi\pygdbmi\tests\test_app.py", line 14, in <module>
        from pygdbmi.gdbcontroller import GdbController, NoGdbProcessError
      File "C:\Users\ago\AppData\Local\Temp\pip-build-j0g63a_a\pygdbmi\pygdbmi\gdbcontroller.py", line 20, in <module>
        from ctypes.wintypes import HANDLE, DWORD, POINTER, BOOL
    ImportError: cannot import name 'POINTER'
C:\> python --version
Python 3.4.3

The previous version installs fine:

C:\> pip install pygdbmi==0.7.4.0
Collecting pygdbmi==0.7.4.0
  Downloading pygdbmi-0.7.4.0.tar.gz
Installing collected packages: pygdbmi
  Running setup.py install for pygdbmi ... done
Successfully installed pygdbmi-0.7.4.0

Payload for textual messages not unescaped

Describe the bug

When parsing output from GDB, pygdmi doesn't unescape the text.
For instance ~"a\nb" (that is, the Python string '~a\\nb') becomes a literal a\nb (that is, the Python string "a\\nb").

To Reproduce

Try parsing the output of help echo (shortened for this example):

print(
    gdbmiparser.parse_response(
        r'~"Print a constant string.  Give string as argument.\nC escape sequences may be used in the argument."'
    )["payload"]
)

This prints this:

Print a constant string.  Give string as argument.\nC escape sequences may be used in the argument.

But I'd expect to get this:

Print a constant string.  Give string as argument.
C escape sequences may be used in the argument.

Expected behavior

Escape sequences should be transformed.

Please complete the following information:

  • OS: macOS
  • pygdbmi version (pip freeze output):
$ pip freeze | grep pygdbmi
pygdbmi==0.10.0.1

Additional context

This is related to #57.

If you are interested I can try to make a PR for this issue.

get_gdb_response doesn't parse tab char correctly

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Using GDBController's write('-data-disassemble -s addr -e addr -- 5', read_response=False)and get_gdb_response to read instructions is converting \t tabs characters into t instead of spaces or the tab character.

Expected behavior
For example call8t0x42005600 is received instead of call8\t0x42005600 or call8 0x42005600

Screenshots
If applicable, add screenshots to help explain your problem.

Please complete the following information:

  • OS: Windows 11
  • pygdbmi version (pip freeze output): 0.9.0.2

Additional context
Add any other context about the problem here.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.