Bug 11688 - wrap MI commands in python
Summary: wrap MI commands in python
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: python (show other bugs)
Version: unknown
: P2 normal
Target Milestone: 14.1
Assignee: Tom Tromey
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-06-10 20:32 UTC by Tom Tromey
Modified: 2023-05-24 17:00 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
a quick and ugly hack on this... (4.25 KB, patch)
2011-08-26 06:56 UTC, matt rice
Details | Diff
2nd implementation of ui-out for python (4.14 KB, patch)
2012-01-06 22:14 UTC, matt rice
Details | Diff
an implementation of mi_execute for python... (2.19 KB, patch)
2012-01-06 22:16 UTC, matt rice
Details | Diff
a gdb script for testing... not an actual testcase yet. (728 bytes, application/octet-stream)
2012-01-06 22:18 UTC, matt rice
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Tom Tromey 2010-06-10 20:32:51 UTC
It would be nice to automate full access to gdb internals via MI.

The idea would be, expose all MI commands in a new module, gdb.mi.
(Or perhaps versioned: gdb.mi2, gdb.mi3, ...)

The wrapper would turn python-style arguments into what the MI commands expect.

We'd make a new ui_out object that knows how to create Python objects.
The wrapper function would return the python object created when the MI command
is invoked.

For documentation we could simply refer to the MI docs, with some explanation
of how the translations are done.
Comment 1 matt rice 2011-08-26 06:56:16 UTC
Created attachment 5914 [details]
a quick and ugly hack on this...

here is a quick ugly patch for this which i am abandoning, though
I got it partially working, the mi_execute() python function does
some truly awful things, such that I think that specific approach is a dead end..

the py-mi-out needs error checking/a careful review of reference counting.
and it was only tested with -break-insert/-break-list and -trace-status.

I just think its more worth my time to do real python API's which have nicer output, than the amount of effort that this will require to get this functioning correctly and into a commitable form.
Comment 2 Tom Tromey 2011-08-26 16:34:07 UTC
This patch looks pretty good as a start.

There are some minor nits (formatting, some missing error checks)
but nothing too major.

It would be nice to expose the MI commands more naturally to Python,
but I that isn't really a requirement.

I tend to agree that writing Python APIs is probably a better approach.
Although I filed this bug, I'm not convinced that exposing MI in this
way is worth doing.
Comment 3 matt rice 2011-08-28 10:33:56 UTC
So I guess i changed my mind about working on this, with my main motivation being that it might make an ok alternative wire format to mi for an interface, e.g. using python on the client side with eval, dodging an mi parser all-together... 

something like this, with print repr on the gdb side, and eval on the client side... seems worth experimenting with anyways.

(gdb) py print eval(repr(gdb.mi_execute('break-insert', 'main')))
{'bkpt': {'disp': 'keep', 'file': 'test.c', 'number': 3, 'func': 'main', 'line': 34, 'original-location': 'main', 'addr': '0x0000000000400509', 'enabled': 'y', 'times': 0, 'fullname': '/home/ratmice/tests/test.c', 'type': 'breakpoint'}}

i've pretty much redone the python mi_execute command, to be less of a hack
and managed to coax it into outputting dictionaries, or lists instead of lists of lists or tuples, i think its nicer...

(gdb) py stuff.append(gdb.mi_execute("break-insert", "main"))
(gdb) py x = stuff[-1]['bkpt']['number']
(gdb) py gdb.mi_execute("break-after", (x, 76))
(gdb) py print x
3
(gdb) info b 3
Num     Type           Disp Enb Address            What
3       breakpoint     keep y   0x0000000000400509 in main at test.c:34
	ignore next 76 hits
Comment 4 Tom Tromey 2012-01-02 19:44:15 UTC
Would you mind if I (eventually) extracted the ui-out portions of this
separately?  I think I have a use for that code in normal-stop event emission.
Comment 5 matt rice 2012-01-03 21:59:06 UTC
No I wouldn't mind at all, although I would prefer to base it on my 2nd version of the patch, I seem to have misplaced it, I'll redo the ui-out portions of that patch and post it here prior to '(eventually)'
Comment 6 matt rice 2012-01-06 22:14:29 UTC
Created attachment 6151 [details]
2nd implementation of ui-out for python

here's the ui-out portion from my latest attempt at this separated from the mi_execute stuff,  I'm not entirely pleased with the python objects this creates, as it does not always return consistent types.

break-list is a nice easy way to hit all of the edge cases where ui-out does this.

# first it returns None... for no breakpoints
gdb.mi_execute("break-list", None)['body'] == None
gdb.mi_execute("break-insert", ("main"))
# then it returns a dictionary
gdb.mi_execute("break-list", None)['body']['bkpt']['number']
gdb.mi_execute("break-insert", ("main"))
# now its been promoted to a list as there are 2 breakpoints.
gdb.mi_execute("break-list", None)['body']['bkpt'][-1]['number']

thus i am hesitant to think it returns objects of acceptable quality, unless used in a fashion which doesn't hit these edge cases.

It does seem possible that we might be able to rid ourselves of these
by expanding the existing ui_out_type,

enum ui_out_type
  {
    ui_out_type_tuple,
    ui_out_type_list
  };

the necessary additions would be something along the lines of:
ui_out_type_tuple_with_duplicate_keys
ui_out_type_deprecated_tuple_list
ui_out_type_deprecated_tuple_list_with_duplicate_keys

(duplicate keys are the cause of object->array promotion,
and empty lists/tuples are the cause of None.)

that would also mean updating all callers, which seems like quite the endeavor.

Other than that the code still needs lots of error handling, but alas I don't really want to finish that if the type schizophrenia means its a dead end.

all of this does make me think that a 'py-mi-version' independent of mi-version for the return values might be warranted.
Comment 7 matt rice 2012-01-06 22:16:53 UTC
Created attachment 6152 [details]
an implementation of mi_execute for python...

heres a different version of mi_execute, which gets rid of ^done being printed on stdout, and does different argument handling.
Comment 8 matt rice 2012-01-06 22:18:00 UTC
Created attachment 6153 [details]
a gdb script for testing... not an actual testcase yet.
Comment 9 Tom Tromey 2023-03-23 18:04:04 UTC
I have a patch for this.
I think maybe the break-info bugs were fixed as part of the MI upgrades?
Anyway the output seems generally sane to me now and if we do find
other bad spots, we ought to fix those.
Comment 10 matt rice 2023-03-24 12:11:50 UTC
Spiffy, I will keep an eye out for it on the lists/here, and look forward to giving it a try!
(Unless i have missed it already, in which case I don't seem to be able to find it)
Comment 11 Tom Tromey 2023-03-24 16:18:42 UTC
I haven't sent it yet, probably will next week.
Comment 13 Sourceware Commits 2023-05-23 19:48:04 UTC
The master branch has been updated by Tom Tromey <tromey@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=c97d123d6701fbf462e96db001cea07ed32e4efa

commit c97d123d6701fbf462e96db001cea07ed32e4efa
Author: Tom Tromey <tromey@adacore.com>
Date:   Thu Mar 16 10:57:32 2023 -0600

    Implement gdb.execute_mi
    
    This adds a new Python function, gdb.execute_mi, that can be used to
    invoke an MI command but get the output as a Python object, rather
    than a string.  This is done by implementing a new ui_out subclass
    that builds a Python object.
    
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=11688
    Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Comment 14 Tom Tromey 2023-05-24 17:00:25 UTC
Fixed.