*gdb_design.txt*    For Vim version 6.2.     Last change: 2004 Mar 28


                      VIMGDB INTERNALS by Xavier de Gaye

VimGDB internals                        *gdbint*
This document describes some aspects of VimGDB internals.

1. File list                            |gdbint-filelist|
2. Gdb modules                          |gdbint-modules|
3. Out Of Band functions                |gdbint-oob|
4. Vim core                             |gdbint-vimcore|
5. Known bugs                           |gdbint-bugs|
6. Changes log                          |gdbint-changes|

==============================================================================
1. File list                            *gdbint-filelist*

This section lists all files changed or added to Vim source distribution in
order to implement VimGDB.

    gdb.c                       new
    gdb.h                       new
    gdb_lvl2.c                  new
    gdb_lvl3.c                  new
    macros/gdb_mappings.vim     new and not required by gdb

Main changes to Vim core source code:

    os_unix.c                   see |gdbint-vimcore|
    normal.c                    see |gdbint-vimcore|
    buffer.c                    see |gdbint-vimcore|
    gui.c                       GUI support: follows os_unix.c model
    gui_gtk_x11.c               GUI support: follows os_unix.c model
    gui_x11.c                   GUI support: follows os_unix.c model

Enable the window input-line and customize this window for VimGDB with
mappings for <Tab>, CTRL-Z and with gdbvim file type:

    ex_getln.c

Syntax:

    syntax/gdb.vim              exhaustive implementation of gdb syntax
    syntax/gdbvim.vim           gdb console syntax, gdb.vim is sourced
    syntax/gdbvar.vim           gdb variables window syntax

The following Vim files have been changed or added for housekeeping purpose:

  o Gdb is a feature:

    feature.h                   include |+signs| when FEAT_GDB is defined
    configure.in
    config.mk.in
    Makefile
    config.h.in
    version.c
    eval.c                      support for the new builtin function gdb()

  o Gdb adds new code to Vim source code:

    globals.h
    structs.h
    proto.h
    proto/gdb.pro               new
    main.c                      gdb_new() and gdb_delete()
    buffer.c                    clean up in free_buffer()
    window.c                    gdb console not last in only_one_window()
    screen.c                    status line gdb label in win_redr_status()
    option.c                    options 'gdbprg', 'asm' and 'gdbvariables'
    option.h                    options 'gdbprg', 'asm' and 'gdbvariables'


==============================================================================
2. Gdb modules                          *gdbint-modules*

The Gdb modules provide an objet oriented type interface to Vim core source
code.

gdb.h defines a gdb_T structure that can be viewed as a class. External code
(i.e. Vim code) uses an opaque handle to this structure. There is only one
instance of this structure for the whole Vim session.

The following diagram describes the data flow between the GDB process, VimGDB
and user commands entered with the Vim gdb() builtin function (the
corresponding C function is named f_gdb()).


  GDB                     VimGDB                            User interface

  GDB -->------------- parse_output
 output                     |
                   process_annotation --> prompt user -
                            |                          |
             --- yes <-- IS_OOBACTIVE                  |
            |               |                          |
          O |      process_completion --> prompt user -
          u |               |                          |
          t |          gdb_redraw                      |
            |               |                          |
          o |      firstcmd && prompt annotation       |
          f |               |                          |
            v               v                          v
          b |               |                          |
          a |    normal_cmd |                          | [Window input-line]
          n |        |      |                          |
          d |   gdb_winput..................gdb_setwinput -- f_gdb("")
            |        |      |
          d |        |      |                               [GDB command]
          a |        |      |
          t |       gdb_docmd ----------<------------------- f_gdb("cmd")
          a |        |
            |        |
  GDB <-gdb_send_cmd-
 input


The link "......." between gdb_winput and gdb_setwinput denotes that by
setting the prompt to be inserted later in the window input-line in
this->winput_cmd, gdb_setwinput triggers an indirect ulterior invocation of
gdb_winput when Vim will return to main_loop.


VimGDB modes:
------------
The VimGDB modules:

    gdb_lvl2.c: only level 2 specific code
    gdb_lvl3.c: level 3 specific and code common to both levels
    gdb.c:      code non specific to any mode

Level 3 mode uses GDB CLI and annotations level 3. This mode uses the GDB
"interpreter-exec" command to send GDB/MI commands and fetch the breakpoint
table and to manage the variables window.

gdb_setup_cli() selects the appropriate mode depending on the
"interpreter-exec" command support by GDB. gdb_lvl2_init() and
gdb_lvl3_init() assign their own pointer to the oobfunc array in gdb_T
and the appropriate function pointers in gdb_T in order to implement the
proper mode. These are, among others, a parser function and the function
invoked to send GDB commands.

A hook is provided in exec_gdb() so that a future pure GDB/MI implementation
may plug its own functions and oob array.

VimGDB can be compiled for exclusive support of level 2 mode, or exclusive
support of level 3 mode, or for both (see appropriate defines in gdb.h).
When annotations level 2 becomes obsolete for all existing GDB
implementations, undefine GDB_LVL2_SUPPORT in gdb.h.


Screen updates:
--------------
Screen updates are managed by Vim core. However, VimGDB changes the screen
content while in low level functions. Therefore, the screen must be updated
by VimGDB in these circumstances. This is done through the gdb.c function
gdb_redraw(). One of these cases is when writing GDB output to the gdb
console, as is shown in the following call graph:

    main_loop    } main.c
        normal_cmd  } normal.c
            safe_vgetc          } getchar.c
                vgetc           }
                    vgetorpeek  }
                        inchar  }
                            ui_inchar   } ui.c
                                mch_inchar  } os_unix.c
                                    gdb_process_output  } gdb.c
                                        parse_output    }
                                            gdb_redraw  }

Track gdb_redraw() invocations to get all screen updates done by VimGDB.


Data insulation:
---------------
Vim internal data is not written to directly by VimGDB except:

    got_int                 described in |gdbint-vimcore|
    RedrawingDisabled       to force redrawing
    emsg_skip               to avoid displaying unwanted error msgs
    cmd_silent
    msg_didout


Memory:
------
Memory leaks can be traced with GNU mtrace. VimGDB memory leaks are traced
when Vim is compiled with "-DGDB_MTRACE -DHAVE_MTRACE". Set MALLOC_TRACE
environment variable to an mtrace log file and use mtrace on this file to
search for memory leaks. There must be none.

Except for the gdb_T structure, no memory allocation is done by VimGDB before
the first GDB process is started. Virtual memory used by the gdb buffer is
limited to 64 K.


==============================================================================
3. Out Of Band functions                *gdbint-oob*

VimGDB can be extended by implementing an oobfunc_T function and adding it to
the oobfunc array. All functions in oobfunc array are successively invoked at
each GDB "prompt" annotation in the array order. Some functions might not
always need to process something in which case they return NULL on their
(first) invocation with OOB_CMD state. The gdb console status line, assembly
buffers, breakpoints and GDB/MI variables are implemented using Out Of Band
functions.


Highlighting breakpoints in assembly code:
-----------------------------------------
Setting a breakpoint and highlighting it in assembly code when the
corresponding function is not yet disassembled involves the interaction of
three Out Of Band functions. The following pseudo code describes how this is
done.

Note: The matter is complicated by the fact that GDB may send ANO_BP_INVALID
when stepping or continuing, even though the table did not change.

States:
    BPS_BP_HIT      got ANO_BREAKPOINT and ('enable once' or ! in bpinfo)
    BPS_INVALID     got ANO_BP_INVALID
                 or got ANO_BREAKPOINT and ('enable once' or ! in bpinfo)
    BPS_FR_INVALID  got ANO_FRAME_INVALID
    BPS_BP_SET      a "break" type GDB command is being processed

get_lastbp()
    if asm != 0                 // assembly is on
            && BPS_INVALID      // GDB reports bp table changed
            && BPS_BP_SET       // a break GDB command is being processed
    {
        set this->asm_add to address of last bp in GDB bp table
        so that function is disassembled in get_asm()
    }

gdb_get_asm()
    disassemble this->asm_add
    reuse an old buffer if needed, in this case, in the reused buffer:
        remove Vim bp signs and corresponding bps in bpinfo list
        remove frame sign
    edit buf containing this->asm_add

get_bp()
    when asm is on, the GDB bp table must be fetched whenever stepping
    as we may be editing a newly disassembled function and therefore
    must set again all bps belonging to this buffer:

    if BPS_INVALID                      // GDB reports table changed
            || (asm && BPS_FR_INVALID)  // in case stepping in a new asm buf
        process_record() for all bps in GDB bp table

process_record()
    if record already in bpinfo list
        update
        change sign if needed
    else
    {
        if an asm bp (<function+in>)
            search all buffers in the asm buffer pool whose name starts
            with function and find the one containing instruction address
        else
            get source file and line number

        if BPS_INVALID
            || (asm && BPS_FR_INVALID && buf == fr_buf)
        {
            edit the file or buffer
            add bp sign
            restore the frame sign if needed

            if editing the frame buffer (fr_buf)
                    && (BPS_BP_HIT || (asm && BPS_FR_INVALID))
            {
                set frame sign on top if needed
                set the cursor at frame sign
            }
        }
    }


==============================================================================
4. Vim core                             *gdbint-vimcore*

Both following sections describe how is handled GDB output processing when
Vim is run in plain terminal (non GUI) mode. This is implemented by changes
made in os_unix.c and normal.c. The same processing is done when in GUI mode
but the function names and source files are different.

GDB output processing:
---------------------
At the top level, in normal.c, safe_vgetc() is redirected so that GDB output
is processed only when the low level Vim functions mch_inchar() and
RealWaitForChar() are invoked from Vim normal mode commands functions.

At the low level, mch_inchar() and RealWaitForChar() cooperate so that
gdb_process_output() is invoked whenever enabled by the top level, and there
is something to read from GDB's pseudo terminal and the timeout is not zero.


Gdb window input-line popup:
---------------------------
The following pseudo code  describes how gdb_process_output() triggers a
window input_line popup:

    main_loop
        normal_cmd
        {
            ...
                vgetorpeek
                {
                    ...
                        mch_inchar
                        {
                            gdb_process_output
                            {
                                // when VimGDB decides that the window
                                // input_line must be popped up
                                got_int = TRUE
                                gdb_setwinput
                                {
                                    set winput_cmd, the string to be
                                    inserted later in the window input-line
                                    return TRUE
                                }
                            }
                            return 0
                        }
                    got_int is TRUE so:
                        flush all input
                        flush stuff and typeahead buffer
                        interrupting all pending mappings and commands
                }
            if winput_cmd != NULL
                gdb_winput          // launch the window input-line
        }


Signs:
-----
The |+signs| feature must behave differently when |+gdb| is running. These
changes are implemented in buffer.c:

sign_mark_adjust()
    sign->lnum stays unchanged, whatever the changes made to the buffer, to
    stay consistent with GDB's breakpoint line numbers


==============================================================================
5. Known bugs                           *gdbint-bugs*

Bugs are ordered in decreasing priority order.

A "hack" item in a bug description means that it is considered to be a GDB
bug and VimGDB is temporarily implementing this "hack" to fix it. When GDB
fixes the bug, the "hack" will be removed from VimGDB and from this list.


1 - Annotations missing after detach and enabled once breakpoints

    date: 2004/02/09
    bug:
        a) when a breakpoint is 'enable once', it becomes disabled the next
        time it is hit. GDB does not send a 'breakpoints-invalid' annotation
        in this case to annotate the change
        b) after a detach command, GDB does not send a 'frames-invalid'
        annotation.
    hack:
        a) see gdb.c compile-conditionnal BP_INVALID_ANO_MISSING
        b) CMD_DETACH is parsed by gdb.c
    status:
        bug report sent to bug-gdb

2 - Setting a breakpoint at an invalid instruction address in an assembly
    buffer.

    date: 2004/02/19
    test case:
        debuggee stopped in asm buffer (for example usleep) and frame sign
        highlighted in asm buffer
        set a bp in usleep at an invalid instruction address
        continue
    bug:
        two asm buffers usleep-asm and usleep-asm1, one containing the frame
        sign, one containing the bp sign
        the reason is get_lastbp() sets this->asm_add to invalid address,
        get_asm() does not find address in existing usleep-asm and therefore
        disassembles usleep in another identical usleep-asm1 buffer
    status:
        bug report sent to bug-gdb on setting bp at invalid address that
        causes inferior process to get SIGSEGV: considered not a GDB bug
        pending

3 - Undocumented breakpoint table line format

    date: 2004/03/06
    test case:
     (gdb) break read
       Breakpoint 2 at 0x40011a70: file __libc_read, line -1.
     (gdb) info breakpoints
       Num Type           Disp Enb Address    What
       1   breakpoint     keep y   0x08048604 in main at toto.c:40
        breakpoint already hit 1 time
       2   breakpoint     keep y   0x40011a70 in __libc_write at __libc_read:-1
    bug:
        invalid negative line number: cannot highlight breakpoint in assembly
        buffer
    status:
        this bug does not occur with level 3 and GDB 6.0
        CLOSED

4 - GDB command "info symbol ADDR" fails to produce function name

    date: 2004/03/07
    test case:
        (gdb) break usleep
          Breakpoint 2 at 0x8048430
        (gdb) info symbol 0x8048430
          No symbol matches 0x8048430.
        (gdb) print/a 0x8048430
          $2 = 0x8048430 <usleep>
        (gdb) info breakpoints
          Num Type           Disp Enb Address    What
          1   breakpoint     keep y   0x08048617 in main at toto.c:41
          2   breakpoint     keep y   0x08048430 <usleep>
    bug:
        GDB command "info symbol ADDR" fails to produce function name
    hack:
        see gdb_lvl3.c:gdb_get_asmfunc_hack()
    status:
        cannot reproduce it on 2004/03/27, keep the hack though
        CLOSED


==============================================================================
6. Changes log                          *gdbint-changes*

VIM62 patch 6 (cvs vim62-gdb1-6):
    configure.in, Makefile: add new modules gdb.h, gdb_lvl2.c and gdb_lvl3.c
    option.c option.h: change 'gdbdisplay' to 'gdbvariables'
    gdb.c, gdb.h, gdb_lvl2.c and gdb_lvl3.c:
        implementation of modes level 2 and level 3
        FIX: "disable" and "delete": the related sign was updated only after
        the next time the debuggee stopped
    gui.c:gui_wait_for_chars():
        break from last loop in gui_wait_for_chars() when retval OK
        FIX: first keystroke after a gdb command is hidden
    gui_gtk_x11.c: gui_mch_wait_for_chars
    gui_x11.c: gui_mch_wait_for_chars
        swap events handling: handle keystroke events before GDB events
        FIX: when hitting fast the step key: last "step" sometimes occur after
        'updatetime' timeout has elapsed
    gdb.c, os_unix.c, gui.c:
        HP-UX 11.0 uses poll(), change some compilation defines and correct
        wtime computation in gdb_process_output

VIM62 patch 5 (cvs vim62-gdb1-5):
    option.c
    option.h
    gdb.c:process_display
    gdb.c: oob function get_display
    gdb.c: oob function undisplay
        gdb display window
    gdb.c:gdb_docmd()
        give_warning("GDB busy: command discarded, please retry", TRUE);
    gdb.c:get_asmfunc()
    gdb.c:get_asmfunc_hack()
    gdb.c:get_asm()
    gdb.c:as_frset()
        when looking for an address in asm buffers, search only those buffers
        whose name starts with function name

VIM62 patch 4 (cvs vim62-gdb1-4):
    gdb.c:get_lastbp()
        see |gdbint-oob|
    gdb.c:get_asm()
        correct handling of new asm buffer names
    gdb.c:parse_note()
        restrict annotation parsing to exact token match, not just the
        beginning (ANO_BP_END was never parsed)

VIM62 patch 3 (cvs vim62-gdb1-3):
    gdb.c:get_bp(), process_record() and process_annotation()
        get_bp() is a new out of band oobfunc_T function that fetches
        the breakpoint info table.
        Support of breakpoints annotations, providing the following
        features:
            1) breakpoint sign text is the last two digits of the
               breakpoint number
            2) disabled breakpoints; GDB commands "tbreak", "thbreak",
               "disable", 'enable once' and 'enable delete' are supported.
               Disabled breakpoints are highlighted with a different color.
               An 'enable once' bp that is hit becomes disabled but does not
               generate an ANO_BP_INVALID annotation, therefore we must track
               the "disposition" and "enable" state of a bp to know
               when to trigger get_bp() in this case.
            3) breakpoints in assembly buffers. If the assembly buffer does
               not exist yet at the time the breakpoint is set, the "sign"
               will be "place"d the next time it is disassembled.
               In order to do that:
                    a) trigger get_bp() whenever program stops at a bp
                       unknown of bpinfo list and asm option is set
                    b) get_asm() is run before get_bp(), thus we must handle
                       the case where a bp sign ends up on top of the frame
                       sign, which may occur in the above case or if the
                       buffer had been previously wiped-out; this is
                       done in process_record()
            4) when receiving a frame annotation (ANO_FRAME_BEGIN or
               ANO_SOURCE), do not edit this buffer if the related
               breakpoint contains a "commands" with the "continue"
               statement
        Since we do not need anymore to parse gdb buffer for breakpoint
        data, a lot of regexp have been removed as well as the functions:
        update_output, bp_delete, bp_parse_set, bp_parse_delete

    gdb.c:process_annotation()
        Do not parse frame annotations when running a backtrace GDB
        command and receiving an ANO_FRAME_BEGIN annotation.

VIM62 patch 2 (cvs vim62-gdb1-2):
    gdb.c:fr_lite()
        Remove previous frame sign:
        GDB sends ANO_FRAME_INVALID annotations whenever stepping, running,
        etc... and these annotations invoke fr_unlite() that turns off the
        previous frame sign.
        However, when moving along the stack frame with GDB "up", "down",
        "frame" commands, we don't get annotations from GDB and must turn off
        the previous frame sign before setting a new frame sign.

    GUI support:gui.c, gui_gtk_x11.c and gui_x11.c
        These changes made to support the gdb interface with a GUI, follow
        the same model as the one used in os_unix.c for a plain terminal.
        Instead of registering as a listener on select() calls, we register a
        call back function. This has been tested with GTK. The changes made
        for GTK have been made for Motif and Athena in gui_x11.c but NOT
        tested, NOT even compiled.

VIM62 initial patch 1 (cvs vim62-gdb1-1):
    Makefile
        Run 'make autoconf' before make to rebuild 'auto/configure' and
        include feature VimGDB. This was not required with Vim61.

    buffer.c:buf_getsigntype()
        No changes required anymore. Changes were made in Vim61-gdb to reverse
        signs display order.

    buffer.c:buf_addsign()
    buffer.c:buf_delsign()
    buffer.c:insert_sign()
    structs.h - struct signlist
        Use the changes introduced in Vim62 for FEAT_NETBEANS_INTG to reorder
        properly signs list (last sign on top).

    gdb.c:edit_file()
        Do no set curbuf to 'nobuflisted' when failing to edit an asm buffer
        after user canceled the command. This bug still exists in Vim61-gdb.

    gdb.c
        screen.c:update_debug_sign() has been improved in Vim62: the phantom
        sign (sign id #2) must be added *before* the frame sign (sign id #1)
        is deleted, and deleted *after* the frame sign is added.
        This avoids having the displayed buffer with an empty sign list which
        would cause a repaint without the sign columns
        [redraw_buf_later(buf, NOT_VALID); in buffer.c:buf_delsign()]
        and thus screen flickers.

    ex_getln.c:ex_window()
        When setting folds to a plain window, the window input-line gets also
        empty fold columns.
        Fix: set option foldcolumn=0
        This bug still exists in Vim61-gdb.
        This problem also shows up in the standard window command-line.

VIM61 (cvs vim61-gdb1-1):
    buffer.c:buf_getsigntype()
        return the last added sign->typenr, not the first, so that the screen
        displays a frame highlighting on top of a breakpoint highlighting and
        is not hidden