Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[cdt-debug-dev] MI investigation

This note is a summary of the state of our MI investigation.

MI has been under development for a number of years.
The goal is a better interface for loosely coupled UIs,
with
     more granular commands
     a stable keyword=value response syntax
     separation of the logical output streams

There is MI documentation in the GDB users manual but it is not
completely reliable. What follows describes the current state
of MI in GDB 5.1.1

OUTPUT STREAMS

The response to an MI command is an MI result and a prompt, possibly
preceded
and/or followed by asynchronous MI output intermixed with stream output.
The command can be prefixed by an (arbitrary) number, in which case
the MI output is prefixed by the same number.

MI results begin with one of  ^done, ^running, ^connected,
^error, and ^exit, possibly followed by comma-separated name=value pairs.

Asynchronous MI output comes in 3 types, with different prefix characters.
'+' - asynch. updates of the status of a long-running debugger operation.
     It is ignorable.
     The only one defined is the "+download" response used with remote
hosts.
'=' - specified as "supplementary information that the client should handle
     (e.g., a new breakpoint information)."
     Currently none of these are issued.
'*' - asynch. state changes of the target.  The only one of these issued
     today is "*stopped".   An "exec-" MI command elicits a "^running"
     response first, then when/if the target stops (by hitting a
breakpoint,
     watchpoint, end of stepping range etc.) the additional "*stopped"
     output is generated.

Stream output also comes in 3 types, again with 3 prefix characters:
'~' - console output to be displayed in a CLI console window, containing
     the response to CLI commands.
'&' - log messages from GDB's internal diagnostics
'@' - textual output from the running target
     In fact, this only works for remote targets.
     When debugging locally the debuggee interacts directly with
     stdin/stdout/stderr.   Obviously this can cause great confusion
     if the program output begins with one of the prefix characters.

MI CHANGES

In the past year or so the format of MI outputs has changed, but for
backward compatibility recent GDBs support both mi0 and mi1 styles.
An example of the difference is the result from a -break-list command.

With mi0:
^done,BreakpointTable={hdr={"Num","Type","Disp","Enb","Address","What"},
bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr
="0x080485c9",
func="main",file="test.c",line="12",times="0"}}

With mi1:
^done,BreakpointTable={nr_rows="1",nr_cols="6",hdr=[{width="3",alignment="
-1",
col_name="number",colhdr="Num"},{width="14",alignment="-1",col_name="type",
colhdr="Type"},{width="4",alignment="-1",col_name="disp",colhdr="Disp"},
{width="3",alignment="-1",col_name="enabled",colhdr="Enb"},
{width="10",alignment="-1",col_name="addr",colhdr="Address"},
{width="40",alignment="2",col_name="what",colhdr="What"}],
body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",
addr="0x080485c9",func="main",file="test.c",line="12",times="0"}]}


COMMANDS

These MI commands are documented but not implemented in GDB 5.1.1:

      -display-delete
      -display-disable
      -display-enable
      -display-insert
      -display-list
      -exec-abort
      -exec-show-arguments
      -file-list-exec-sections
      -file-list-exec-source-files
      -file-list-shared-libraries
      -file-list-symbol-files
      -stack-info-frame
      -symbol-info-address
      -symbol-info-file
      -symbol-info-function
      -symbol-info-line
      -symbol-info-symbol
      -symbol-list-functions
      -symbol-list-types
      -symbol-list-variables
      -symbol-locate
      -symbol-type
      -target-attach
      -target-compare-sections
      -target-exec-status
      -target-list-available-targets
      -target-list-current-targets
      -target-list-parameters
      -thread-info
      -thread-list-all-threads

These commands are implemented but not documented:
      -data-write-memory
      -data-write-register-values

This command only works with asynchronous targets, which does not
include local Linux debugging:
       -exec-interrupt


CLI SUPPORT

The statements in the manual and GDB source warning that the CLI-in-MI
function will disappear are recognized as inadequate but there is no
clear consensus on what the eventual answer will be.

There are two parts to this issue:
1. Supplement the incomplete MI command set
2. Providing a command line interface for GUI users to access "power user"
capabilities, create and use user-defined commands, invoke scripts, etc.

The first is often done under the covers by MI, for example an MI "
-break-list"
actually executes the CLI "info break" command.  The key is they
should behave like MI commands and produce MI results, which they do to
a great extent.  However there are some CLI commands we use today that
do not have implemented MI equivalents, and which do not produce MI
style results
   "info program" - to find process ID so we can kill it, since
               -exec-interrupt doesn't work
   "whatis"/"ptype" -  to substitute for missing -symbol-type
   "info line"/"info line *" - to convert address <-> line#
   "maintenance print objfiles" - for missing -file-list-exec-source-files
   "info share" - for missing -file-list-shared-libraries
   "info threads" -  for missing -thread-list-all-threads
   "list" - produces no output at all

The second part is more difficult. For this we want to provide a high
fidelity
CLI interface, with standard CLI output in the console window.
At the same time, we need to keep the GUI up to date with any state
changes in the debugger or the target, such as new breakpoints, running
state,
or stack frame changes,  preferably by notifications in the MI stream when
these things do change.
Current gdbs (up to 5.1.1) don't help with either of these problems.
MI users have to fake generating CLI-like output for console commands,
and have to query the debug state after a command to find out if anything
has changed.
However, Apple has done a lot of work in this area with a version of GDB
they use under their Project Builder IDE for OS X, and which they have
made available for integration back into the main GDB codebase.



APPLE MI EXTENSIONS

Apple's extensions address two major MI deficiencies with CLI support.
First, they have made the interpreter dynamically switchable,
and introduced an MI command -interpreter-exec interpreter "command" which
can be used to run console (CLI) commands with true CLI output.
The difference is illustrated in this example:

(gdb) info break
&"info break\n"
^done,BreakpointTable={hdr
={"Number","Type","Disposition","Enabled","Address",
"What","StackFrame","Condition","IgnoreCount","Commands"},bkpt={number="1",
type="breakpoint",disp="keep",enabled="y",addr="0x080485c9",func="main",
file="test.c",line="12",times="0"}}
(gdb) -interpreter-exec console "info break"
Number Type           Disposition Enabled Address    WhatStackFrame
Condition IgnoreCount Commands
1      breakpoint     keep        y   0x080485c9 in main at test.c     :12
^done
(gdb)


Secondly, Apple has added hooks in GDB to capture state change information
when these true CLI mode console commands are run using -interpreter-exec.
The information is appended to the MI result rather than using an
asynchronous notification.
These notifications are provided:
  Breakpoint delete =>
      ^done,MI_HOOK_RESULT=(HOOK_TYPE="breakpoint_delete",bkptno="n")
  Breakpoing modify =>
     ^done,MI_HOOK_RESULT=(HOOK_TYPE="breakpoint_modify",bkpt=(...))
  Breakpoing create =>
     ^done,MI_HOOK_RESULT=(HOOK_TYPE="breakpoint_create",bkpt=(...))
  Frame changed =>
     ^done,MI_HOOK_RESULT=(HOOK_TYPE="frame_changed",frame="n")
  Thread context (i.e., current thread) changed =>
     ^done,MI_HOOK_RESULT=(HOOK_TYPE="thread_changed",thread="n")
The information is cumulative if a complex command causes more than one
change.

They also introduced a few other hooks that also take effect
when -interpreter-exec console is being used:

1. If an -interpreter-exec  CLI command asks for "(y or n)" confirmation,
   always answer "y".
2. If an -interpreter-exec  CLI command needs multiline input (e.g.
"define",
   "document", "if", or "while), prompt with the MI async notification
     =read-one-line,prompt="prompt"
3. If an -interpreter-exec  CLI command steps or continues the target,
   generate the notifications "^stepping" or "^continuing"
4. If an -interpreter-exec  CLI command attempts to run the target,
   don't do it, instead send the notification
      =rerun
   back to the UI



ASSESSMENT

The value that MI provides today is in
     stream separation
     robustly parseable output
     supported interface

but with these limitations
     stream separation isn't reliable
     some necessary machine output is still in CLI format
     some necessary output isn't available ("list")
     CLI console output has to be faked
     inadequate notification of state changes

The question now is whether the current MI implementation provides
enough value to target it now, given we will have to implement
workarounds for the limitations, and given that nobody believes it is
complete and so will continue to be a moving target for some time.
My view is it would it make more sense to help fix MI first,
e.g. by helping to integrate the Apple work and fix the stream
separation problem, and move to it when it is more stable and complete.


REFERENCES

Questions about GDB-MI Interface
http://sources.redhat.com/ml/gdb/2002-04/msg00394.html

Target Output Streaming in MI
http://sources.redhat.com/ml/gdb/2002-05/msg00022.html




Brian



Back to the top