GDB (API)
/home/stan/gdb/src/gdb/tui/tui.c
Go to the documentation of this file.
00001 /* General functions for the WDB TUI.
00002 
00003    Copyright (C) 1998-2013 Free Software Foundation, Inc.
00004 
00005    Contributed by Hewlett-Packard Company.
00006 
00007    This file is part of GDB.
00008 
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; either version 3 of the License, or
00012    (at your option) any later version.
00013 
00014    This program is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017    GNU General Public License for more details.
00018 
00019    You should have received a copy of the GNU General Public License
00020    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00021 
00022 #include "defs.h"
00023 #include "gdbcmd.h"
00024 #include "tui/tui.h"
00025 #include "tui/tui-hooks.h"
00026 #include "tui/tui-data.h"
00027 #include "tui/tui-layout.h"
00028 #include "tui/tui-io.h"
00029 #include "tui/tui-regs.h"
00030 #include "tui/tui-stack.h"
00031 #include "tui/tui-win.h"
00032 #include "tui/tui-winsource.h"
00033 #include "tui/tui-windata.h"
00034 #include "target.h"
00035 #include "frame.h"
00036 #include "breakpoint.h"
00037 #include "inferior.h"
00038 #include "symtab.h"
00039 #include "source.h"
00040 
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include <ctype.h>
00044 #include <signal.h>
00045 #include <fcntl.h>
00046 #if 0
00047 #include <termio.h>
00048 #endif
00049 #include <setjmp.h>
00050 
00051 #include "gdb_curses.h"
00052 
00053 /* This redefines CTRL if it is not already defined, so it must come
00054    after terminal state releated include files like <term.h> and
00055    "gdb_curses.h".  */
00056 #include "readline/readline.h"
00057 
00058 /* Tells whether the TUI is active or not.  */
00059 int tui_active = 0;
00060 static int tui_finish_init = 1;
00061 
00062 enum tui_key_mode tui_current_key_mode = TUI_COMMAND_MODE;
00063 
00064 struct tui_char_command
00065 {
00066   unsigned char key;
00067   const char *cmd;
00068 };
00069 
00070 /* Key mapping to gdb commands when the TUI is using the single key
00071    mode.  */
00072 static const struct tui_char_command tui_commands[] = {
00073   { 'c', "continue" },
00074   { 'd', "down" },
00075   { 'f', "finish" },
00076   { 'n', "next" },
00077   { 'r', "run" },
00078   { 's', "step" },
00079   { 'u', "up" },
00080   { 'v', "info locals" },
00081   { 'w', "where" },
00082   { 0, 0 },
00083 };
00084 
00085 static Keymap tui_keymap;
00086 static Keymap tui_readline_standard_keymap;
00087 
00088 /* TUI readline command.
00089    Switch the output mode between TUI/standard gdb.  */
00090 static int
00091 tui_rl_switch_mode (int notused1, int notused2)
00092 {
00093   if (tui_active)
00094     {
00095       tui_disable ();
00096       rl_prep_terminal (0);
00097     }
00098   else
00099     {
00100       rl_deprep_terminal ();
00101       tui_enable ();
00102     }
00103 
00104   /* Clear the readline in case switching occurred in middle of
00105      something.  */
00106   if (rl_end)
00107     rl_kill_text (0, rl_end);
00108 
00109   /* Since we left the curses mode, the terminal mode is restored to
00110      some previous state.  That state may not be suitable for readline
00111      to work correctly (it may be restored in line mode).  We force an
00112      exit of the current readline so that readline is re-entered and
00113      it will be able to setup the terminal for its needs.  By
00114      re-entering in readline, we also redisplay its prompt in the
00115      non-curses mode.  */
00116   rl_newline (1, '\n');
00117 
00118   /* Make sure the \n we are returning does not repeat the last
00119      command.  */
00120   dont_repeat ();
00121   return 0;
00122 }
00123 
00124 /* TUI readline command.
00125    Change the TUI layout to show a next layout.
00126    This function is bound to CTRL-X 2.  It is intended to provide
00127    a functionality close to the Emacs split-window command.  We
00128    always show two windows (src+asm), (src+regs) or (asm+regs).  */
00129 static int
00130 tui_rl_change_windows (int notused1, int notused2)
00131 {
00132   if (!tui_active)
00133     tui_rl_switch_mode (0 /* notused */, 0 /* notused */);
00134 
00135   if (tui_active)
00136     {
00137       enum tui_layout_type new_layout;
00138       enum tui_register_display_type regs_type = TUI_UNDEFINED_REGS;
00139 
00140       new_layout = tui_current_layout ();
00141 
00142       /* Select a new layout to have a rolling layout behavior with
00143          always two windows (except when undefined).  */
00144       switch (new_layout)
00145         {
00146         case SRC_COMMAND:
00147           new_layout = SRC_DISASSEM_COMMAND;
00148           break;
00149 
00150         case DISASSEM_COMMAND:
00151           new_layout = SRC_DISASSEM_COMMAND;
00152           break;
00153 
00154         case SRC_DATA_COMMAND:
00155           new_layout = SRC_DISASSEM_COMMAND;
00156           break;
00157 
00158         case SRC_DISASSEM_COMMAND:
00159           new_layout = DISASSEM_DATA_COMMAND;
00160           break;
00161           
00162         case DISASSEM_DATA_COMMAND:
00163           new_layout = SRC_DATA_COMMAND;
00164           break;
00165 
00166         default:
00167           new_layout = SRC_COMMAND;
00168           break;
00169         }
00170       tui_set_layout (new_layout, regs_type);
00171     }
00172   return 0;
00173 }
00174 
00175 /* TUI readline command.
00176    Delete the second TUI window to only show one.  */
00177 static int
00178 tui_rl_delete_other_windows (int notused1, int notused2)
00179 {
00180   if (!tui_active)
00181     tui_rl_switch_mode (0 /* notused */, 0 /* notused */);
00182 
00183   if (tui_active)
00184     {
00185       enum tui_layout_type new_layout;
00186       enum tui_register_display_type regs_type = TUI_UNDEFINED_REGS;
00187 
00188       new_layout = tui_current_layout ();
00189 
00190       /* Kill one window.  */
00191       switch (new_layout)
00192         {
00193         case SRC_COMMAND:
00194         case SRC_DATA_COMMAND:
00195         case SRC_DISASSEM_COMMAND:
00196         default:
00197           new_layout = SRC_COMMAND;
00198           break;
00199 
00200         case DISASSEM_COMMAND:
00201         case DISASSEM_DATA_COMMAND:
00202           new_layout = DISASSEM_COMMAND;
00203           break;
00204         }
00205       tui_set_layout (new_layout, regs_type);
00206     }
00207   return 0;
00208 }
00209 
00210 /* TUI readline command.
00211    Switch the active window to give the focus to a next window.  */
00212 static int
00213 tui_rl_other_window (int count, int key)
00214 {
00215   struct tui_win_info *win_info;
00216 
00217   if (!tui_active)
00218     tui_rl_switch_mode (0 /* notused */, 0 /* notused */);
00219 
00220   win_info = tui_next_win (tui_win_with_focus ());
00221   if (win_info)
00222     {
00223       tui_set_win_focus_to (win_info);
00224       if (TUI_DATA_WIN && TUI_DATA_WIN->generic.is_visible)
00225         tui_refresh_data_win ();
00226       keypad (TUI_CMD_WIN->generic.handle, (win_info != TUI_CMD_WIN));
00227     }
00228   return 0;
00229 }
00230 
00231 /* TUI readline command.
00232    Execute the gdb command bound to the specified key.  */
00233 static int
00234 tui_rl_command_key (int count, int key)
00235 {
00236   int i;
00237 
00238   reinitialize_more_filter ();
00239   for (i = 0; tui_commands[i].cmd; i++)
00240     {
00241       if (tui_commands[i].key == key)
00242         {
00243           /* Insert the command in the readline buffer.
00244              Avoid calling the gdb command here since it creates
00245              a possible recursion on readline if prompt_for_continue
00246              is called (See PR 9584).  The command will also appear
00247              in the readline history which turns out to be better.  */
00248           rl_insert_text (tui_commands[i].cmd);
00249           rl_newline (1, '\n');
00250 
00251           /* Switch to gdb command mode while executing the command.
00252              This way the gdb's continue prompty will be displayed.  */
00253           tui_set_key_mode (TUI_ONE_COMMAND_MODE);
00254           return 0;
00255         }
00256     }
00257   return 0;
00258 }
00259 
00260 /* TUI readline command.
00261    Temporarily leave the TUI SingleKey mode to allow editing
00262    a gdb command with the normal readline.  Once the command
00263    is executed, the TUI SingleKey mode is installed back.  */
00264 static int
00265 tui_rl_command_mode (int count, int key)
00266 {
00267   tui_set_key_mode (TUI_ONE_COMMAND_MODE);
00268   return rl_insert (count, key);
00269 }
00270 
00271 /* TUI readline command.
00272    Switch between TUI SingleKey mode and gdb readline editing.  */
00273 static int
00274 tui_rl_next_keymap (int notused1, int notused2)
00275 {
00276   if (!tui_active)
00277     tui_rl_switch_mode (0 /* notused */, 0 /* notused */);
00278 
00279   tui_set_key_mode (tui_current_key_mode == TUI_COMMAND_MODE
00280                     ? TUI_SINGLE_KEY_MODE : TUI_COMMAND_MODE);
00281   return 0;
00282 }
00283 
00284 /* Readline hook to redisplay ourself the gdb prompt.
00285    In the SingleKey mode, the prompt is not printed so that
00286    the command window is cleaner.  It will be displayed if
00287    we temporarily leave the SingleKey mode.  */
00288 static int
00289 tui_rl_startup_hook (void)
00290 {
00291   rl_already_prompted = 1;
00292   if (tui_current_key_mode != TUI_COMMAND_MODE && immediate_quit == 0)
00293     tui_set_key_mode (TUI_SINGLE_KEY_MODE);
00294   tui_redisplay_readline ();
00295   return 0;
00296 }
00297 
00298 /* Change the TUI key mode by installing the appropriate readline
00299    keymap.  */
00300 void
00301 tui_set_key_mode (enum tui_key_mode mode)
00302 {
00303   tui_current_key_mode = mode;
00304   rl_set_keymap (mode == TUI_SINGLE_KEY_MODE
00305                  ? tui_keymap : tui_readline_standard_keymap);
00306   tui_show_locator_content ();
00307 }
00308 
00309 /* Initialize readline and configure the keymap for the switching
00310    key shortcut.  */
00311 void
00312 tui_initialize_readline (void)
00313 {
00314   int i;
00315   Keymap tui_ctlx_keymap;
00316 
00317   rl_initialize ();
00318 
00319   rl_add_defun ("tui-switch-mode", tui_rl_switch_mode, -1);
00320   rl_add_defun ("gdb-command", tui_rl_command_key, -1);
00321   rl_add_defun ("next-keymap", tui_rl_next_keymap, -1);
00322 
00323   tui_keymap = rl_make_bare_keymap ();
00324   tui_ctlx_keymap = rl_make_bare_keymap ();
00325   tui_readline_standard_keymap = rl_get_keymap ();
00326 
00327   for (i = 0; tui_commands[i].cmd; i++)
00328     rl_bind_key_in_map (tui_commands[i].key, tui_rl_command_key, tui_keymap);
00329 
00330   rl_generic_bind (ISKMAP, "\\C-x", (char*) tui_ctlx_keymap, tui_keymap);
00331 
00332   /* Bind all other keys to tui_rl_command_mode so that we switch
00333      temporarily from SingleKey mode and can enter a gdb command.  */
00334   for (i = ' '; i < 0x7f; i++)
00335     {
00336       int j;
00337 
00338       for (j = 0; tui_commands[j].cmd; j++)
00339         if (tui_commands[j].key == i)
00340           break;
00341 
00342       if (tui_commands[j].cmd)
00343         continue;
00344 
00345       rl_bind_key_in_map (i, tui_rl_command_mode, tui_keymap);
00346     }
00347 
00348   rl_bind_key_in_map ('a', tui_rl_switch_mode, emacs_ctlx_keymap);
00349   rl_bind_key_in_map ('a', tui_rl_switch_mode, tui_ctlx_keymap);
00350   rl_bind_key_in_map ('A', tui_rl_switch_mode, emacs_ctlx_keymap);
00351   rl_bind_key_in_map ('A', tui_rl_switch_mode, tui_ctlx_keymap);
00352   rl_bind_key_in_map (CTRL ('A'), tui_rl_switch_mode, emacs_ctlx_keymap);
00353   rl_bind_key_in_map (CTRL ('A'), tui_rl_switch_mode, tui_ctlx_keymap);
00354   rl_bind_key_in_map ('1', tui_rl_delete_other_windows, emacs_ctlx_keymap);
00355   rl_bind_key_in_map ('1', tui_rl_delete_other_windows, tui_ctlx_keymap);
00356   rl_bind_key_in_map ('2', tui_rl_change_windows, emacs_ctlx_keymap);
00357   rl_bind_key_in_map ('2', tui_rl_change_windows, tui_ctlx_keymap);
00358   rl_bind_key_in_map ('o', tui_rl_other_window, emacs_ctlx_keymap);
00359   rl_bind_key_in_map ('o', tui_rl_other_window, tui_ctlx_keymap);
00360   rl_bind_key_in_map ('q', tui_rl_next_keymap, tui_keymap);
00361   rl_bind_key_in_map ('s', tui_rl_next_keymap, emacs_ctlx_keymap);
00362   rl_bind_key_in_map ('s', tui_rl_next_keymap, tui_ctlx_keymap);
00363 }
00364 
00365 /* Enter in the tui mode (curses).
00366    When in normal mode, it installs the tui hooks in gdb, redirects
00367    the gdb output, configures the readline to work in tui mode.
00368    When in curses mode, it does nothing.  */
00369 void
00370 tui_enable (void)
00371 {
00372   if (!tui_allowed_p ())
00373     error (_("TUI mode not allowed"));
00374 
00375   if (tui_active)
00376     return;
00377 
00378   /* To avoid to initialize curses when gdb starts, there is a defered
00379      curses initialization.  This initialization is made only once
00380      and the first time the curses mode is entered.  */
00381   if (tui_finish_init)
00382     {
00383       WINDOW *w;
00384 
00385       w = initscr ();
00386   
00387       cbreak ();
00388       noecho ();
00389       /* timeout (1); */
00390       nodelay(w, FALSE);
00391       nl();
00392       keypad (w, TRUE);
00393       rl_initialize ();
00394       tui_set_term_height_to (LINES);
00395       tui_set_term_width_to (COLS);
00396       def_prog_mode ();
00397 
00398       tui_show_frame_info (0);
00399       tui_set_layout (SRC_COMMAND, TUI_UNDEFINED_REGS);
00400       tui_set_win_focus_to (TUI_SRC_WIN);
00401       keypad (TUI_CMD_WIN->generic.handle, TRUE);
00402       wrefresh (TUI_CMD_WIN->generic.handle);
00403       tui_finish_init = 0;
00404     }
00405   else
00406     {
00407      /* Save the current gdb setting of the terminal.
00408         Curses will restore this state when endwin() is called.  */
00409      def_shell_mode ();
00410      clearok (stdscr, TRUE);
00411    }
00412 
00413   /* Install the TUI specific hooks.  */
00414   tui_install_hooks ();
00415   rl_startup_hook = tui_rl_startup_hook;
00416 
00417   tui_update_variables ();
00418   
00419   tui_setup_io (1);
00420 
00421   tui_active = 1;
00422   if (deprecated_safe_get_selected_frame ())
00423      tui_show_frame_info (deprecated_safe_get_selected_frame ());
00424 
00425   /* Restore TUI keymap.  */
00426   tui_set_key_mode (tui_current_key_mode);
00427   tui_refresh_all_win ();
00428 
00429   /* Update gdb's knowledge of its terminal.  */
00430   target_terminal_save_ours ();
00431   tui_update_gdb_sizes ();
00432 }
00433 
00434 /* Leave the tui mode.
00435    Remove the tui hooks and configure the gdb output and readline
00436    back to their original state.  The curses mode is left so that
00437    the terminal setting is restored to the point when we entered.  */
00438 void
00439 tui_disable (void)
00440 {
00441   if (!tui_active)
00442     return;
00443 
00444   /* Restore initial readline keymap.  */
00445   rl_set_keymap (tui_readline_standard_keymap);
00446 
00447   /* Remove TUI hooks.  */
00448   tui_remove_hooks ();
00449   rl_startup_hook = 0;
00450   rl_already_prompted = 0;
00451 
00452   /* Leave curses and restore previous gdb terminal setting.  */
00453   endwin ();
00454 
00455   /* gdb terminal has changed, update gdb internal copy of it
00456      so that terminal management with the inferior works.  */
00457   tui_setup_io (0);
00458 
00459   /* Update gdb's knowledge of its terminal.  */
00460   target_terminal_save_ours ();
00461 
00462   tui_active = 0;
00463   tui_update_gdb_sizes ();
00464 }
00465 
00466 void
00467 strcat_to_buf (char *buf, int buflen, 
00468                const char *item_to_add)
00469 {
00470   if (item_to_add != (char *) NULL && buf != (char *) NULL)
00471     {
00472       if ((strlen (buf) + strlen (item_to_add)) <= buflen)
00473         strcat (buf, item_to_add);
00474       else
00475         strncat (buf, item_to_add, (buflen - strlen (buf)));
00476     }
00477 }
00478 
00479 #if 0
00480 /* Solaris <sys/termios.h> defines CTRL.  */
00481 #ifndef CTRL
00482 #define CTRL(x)         (x & ~0140)
00483 #endif
00484 
00485 #define FILEDES         2
00486 #define CHK(val, dft)   (val<=0 ? dft : val)
00487 
00488 static void
00489 tui_reset (void)
00490 {
00491   struct termio mode;
00492 
00493   /* Reset the teletype mode bits to a sensible state.
00494      Copied tset.c.  */
00495 #if defined (TIOCGETC)
00496   struct tchars tbuf;
00497 #endif /* TIOCGETC */
00498 #ifdef UCB_NTTY
00499   struct ltchars ltc;
00500 
00501   if (ldisc == NTTYDISC)
00502     {
00503       ioctl (FILEDES, TIOCGLTC, &ltc);
00504       ltc.t_suspc = CHK (ltc.t_suspc, CTRL ('Z'));
00505       ltc.t_dsuspc = CHK (ltc.t_dsuspc, CTRL ('Y'));
00506       ltc.t_rprntc = CHK (ltc.t_rprntc, CTRL ('R'));
00507       ltc.t_flushc = CHK (ltc.t_flushc, CTRL ('O'));
00508       ltc.t_werasc = CHK (ltc.t_werasc, CTRL ('W'));
00509       ltc.t_lnextc = CHK (ltc.t_lnextc, CTRL ('V'));
00510       ioctl (FILEDES, TIOCSLTC, &ltc);
00511     }
00512 #endif /* UCB_NTTY */
00513 #ifdef TIOCGETC
00514   ioctl (FILEDES, TIOCGETC, &tbuf);
00515   tbuf.t_intrc = CHK (tbuf.t_intrc, CTRL ('?'));
00516   tbuf.t_quitc = CHK (tbuf.t_quitc, CTRL ('\\'));
00517   tbuf.t_startc = CHK (tbuf.t_startc, CTRL ('Q'));
00518   tbuf.t_stopc = CHK (tbuf.t_stopc, CTRL ('S'));
00519   tbuf.t_eofc = CHK (tbuf.t_eofc, CTRL ('D'));
00520   /* brkc is left alone.  */
00521   ioctl (FILEDES, TIOCSETC, &tbuf);
00522 #endif /* TIOCGETC */
00523   mode.sg_flags &= ~(RAW
00524 #ifdef CBREAK
00525                      | CBREAK
00526 #endif /* CBREAK */
00527                      | VTDELAY | ALLDELAY);
00528   mode.sg_flags |= XTABS | ECHO | CRMOD | ANYP;
00529 
00530   return;
00531 }
00532 #endif
00533 
00534 void
00535 tui_show_source (const char *fullname, int line)
00536 {
00537   struct symtab_and_line cursal = get_current_source_symtab_and_line ();
00538 
00539   /* Make sure that the source window is displayed.  */
00540   tui_add_win_to_layout (SRC_WIN);
00541 
00542   tui_update_source_windows_with_line (cursal.symtab, line);
00543   tui_update_locator_fullname (fullname);
00544 }
00545 
00546 void
00547 tui_show_assembly (struct gdbarch *gdbarch, CORE_ADDR addr)
00548 {
00549   tui_add_win_to_layout (DISASSEM_WIN);
00550   tui_update_source_windows_with_addr (gdbarch, addr);
00551 }
00552 
00553 int
00554 tui_is_window_visible (enum tui_win_type type)
00555 {
00556   if (tui_active == 0)
00557     return 0;
00558 
00559   if (tui_win_list[type] == 0)
00560     return 0;
00561   
00562   return tui_win_list[type]->generic.is_visible;
00563 }
00564 
00565 int
00566 tui_get_command_dimension (unsigned int *width, 
00567                            unsigned int *height)
00568 {
00569   if (!tui_active || (TUI_CMD_WIN == NULL))
00570     {
00571       return 0;
00572     }
00573   
00574   *width = TUI_CMD_WIN->generic.width;
00575   *height = TUI_CMD_WIN->generic.height;
00576   return 1;
00577 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines