binutils-gdb/gdb/tui/tui.c

689 lines
18 KiB
C
Raw Normal View History

/* General functions for the WDB TUI.
2002-03-01 07:19:28 +01:00
Copyright (C) 1998-2016 Free Software Foundation, Inc.
2002-03-01 07:19:28 +01:00
Contributed by Hewlett-Packard Company.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "gdbcmd.h"
#include "tui/tui.h"
#include "tui/tui-hooks.h"
#include "tui/tui-data.h"
#include "tui/tui-layout.h"
#include "tui/tui-io.h"
#include "tui/tui-regs.h"
#include "tui/tui-stack.h"
#include "tui/tui-win.h"
#include "tui/tui-winsource.h"
#include "tui/tui-windata.h"
#include "target.h"
#include "frame.h"
#include "breakpoint.h"
#include "inferior.h"
#include "symtab.h"
#include "source.h"
Fix terminal state corruption when starting a program from within TUI The TUI terminal state becomes corrupted (e.g. key sequences such as Alt_F and Alt_B no longer work) when one attaches to an inferior process (via "run" or "attach") from within TUI. This terminal corruption remains until you switch out of TUI mode. This happens because the terminal state is not properly saved when switching to and out from TUI mode. Although the functions tui_enable() and tui_disable() both call the function target_terminal_save_ours() to save the terminal state, this function is a no-op unless GDB has already attached to an inferior process. This is because only the "native" target has a useful implementation of target_terminal_save_ours() (namely child_terminal_save_ours()) and we only have the "native" target in our target vector if GDB has already attached to an inferior process. So without an inferior process, switching to and from TUI mode does not actually save the terminal state. Therefore when you attach to an inferior process from within TUI mode, the proper terminal state is not restored (after swapping from the inferior's terminal back to the GDB terminal). To fix this we just have to ensure that the terminal state is always being properly saved when switching from and to TUI mode. To achieve this, this patch removes the polymorphic function target_terminal_save_ours() and replaces it with a regular function gdb_save_tty_state() that always saves the terminal state. Tested on x86_64-unknown-linux-gnu by running "make check", no new regressions. gdb/ChangeLog: * target.h (struct target_ops::to_terminal_save_ours): Remove declaration. (target_terminal_save_ours): Remove macro. * target-delegates.c: Regenerate. * inf-child.c (inf_child_target): Don't set the nonexistent field to_terminal_save_ours. * inferior.h (child_terminal_save_ours): Remove declaration. * terminal.h (gdb_save_tty_state): New declaration. * inflow.c (child_terminal_save_ours): Rename to ... (gdb_save_tty_state): ... this. * tui/tui.c: Include terminal.h. (tui_enable): Use gdb_save_tty_state instead of target_terminal_save_ours. (tui_disable): Likewise.
2014-08-25 16:40:32 +02:00
#include "terminal.h"
#include "top.h"
#include <ctype.h>
#include <signal.h>
#include <fcntl.h>
#if 0
#include <termio.h>
#endif
#include <setjmp.h>
#include "gdb_curses.h"
PR tui/16138, PR tui/17519, and misc failures to initialize the terminal PR tui/16138 is about failure to initialize curses resulting in GDB exiting instead of throwing an error. E.g.: $ TERM=foo gdb (gdb) layout asm Error opening terminal: foo. $ The problem is that we're calling initscr to initialize the screen. As mentioned in http://pubs.opengroup.org/onlinepubs/7908799/xcurses/initscr.html: If errors occur, initscr() writes an appropriate error message to standard error and exits. ^^^^^ Instead, we should use newterm: "A program that needs an indication of error conditions, so it can continue to run in a line-oriented mode if the terminal cannot support a screen-oriented program, would also use this function." After the patch: $ TERM=foo gdb -q -nx (gdb) layout asm Cannot enable the TUI: error opening terminal [TERM=foo] (gdb) And then PR tui/17519 is about GDB not validating whether the terminal has the necessary capabilities when enabling the TUI. If one tries to enable the TUI with TERM=dumb (and e.g., from a shell within emacs), GDB ends up with a clear screen, the cursor is placed at the bottom/right corner of the screen, there's no prompt, typing shows no echo, and there's no indication of what's going on. c-x,a gets you out of the TUI, but it's completely non-obvious. After the patch, we get: $ TERM=dumb gdb -q -nx (gdb) layout asm Cannot enable the TUI: terminal doesn't support cursor addressing [TERM=dumb] (gdb) While at it, I've moved all the tui_allowed_p validation to tui_enable, and expanded the error messages. Previously we'd get: $ gdb -q -nx -i=mi (gdb) layout asm &"layout asm\n" &"TUI mode not allowed\n" ^error,msg="TUI mode not allowed" and: $ gdb -q -nx -ex "layout asm" > foo TUI mode not allowed While now we get: $ gdb -q -nx -i=mi (gdb) layout asm &"layout asm\n" &"Cannot enable the TUI when the interpreter is 'mi'\n" ^error,msg="Cannot enable the TUI when the interpreter is 'mi'" (gdb) and: $ gdb -q -nx -ex "layout asm" > foo Cannot enable the TUI when output is not a terminal Tested on x86_64 Fedora 20. gdb/ 2014-10-29 Pedro Alves <palves@redhat.com> PR tui/16138 PR tui/17519 * tui/tui-interp.c (tui_is_toplevel): Delete global. (tui_allowed_p): Delete function. * tui/tui.c: Include "interps.h". (tui_enable): Don't use tui_allowed_p. Error out here with detailed error messages if the TUI is the top level interpreter, or if output is not a terminal. Use newterm instead of initscr, and error out if initializing the terminal fails. Also error out if the terminal doesn't support cursor addressing. * tui/tui.h (tui_allowed_p): Delete declaration.
2014-10-29 15:23:57 +01:00
#include "interps.h"
/* This redefines CTRL if it is not already defined, so it must come
after terminal state releated include files like <term.h> and
2004-04-09 15:44:02 +02:00
"gdb_curses.h". */
#include "readline/readline.h"
/* Tells whether the TUI is active or not. */
int tui_active = 0;
static int tui_finish_init = 1;
enum tui_key_mode tui_current_key_mode = TUI_COMMAND_MODE;
struct tui_char_command
{
unsigned char key;
const char *cmd;
};
/* Key mapping to gdb commands when the TUI is using the single key
mode. */
static const struct tui_char_command tui_commands[] = {
{ 'c', "continue" },
{ 'd', "down" },
{ 'f', "finish" },
{ 'n', "next" },
{ 'r', "run" },
{ 's', "step" },
{ 'u', "up" },
{ 'v', "info locals" },
{ 'w', "where" },
{ 0, 0 },
};
static Keymap tui_keymap;
static Keymap tui_readline_standard_keymap;
/* TUI readline command.
Switch the output mode between TUI/standard gdb. */
static int
tui_rl_switch_mode (int notused1, int notused2)
{
TUI: don't let exceptions escape while handling readline key bindings I noticed that with: $ TERM=dumb ./gdb -q -nx <c-x,a> Cannot enable the TUI: terminal doesn't support cursor addressing [TERM=dumb] (gdb) The next key the user types is silently eaten. The problem is that we're throwing an exception while in a readline callback that isn't prepared for that: (top-gdb) bt #0 tui_enable () at /home/pedro/gdb/mygit/build/../src/gdb/tui/tui.c:388 #1 0x000000000051f47b in tui_rl_switch_mode (notused1=1, notused2=1) at /home/pedro/gdb/mygit/build/../src/gdb/tui/tui.c:101 #2 0x0000000000768d6f in _rl_dispatch_subseq (key=1, map=0xd069c0 <emacs_ctlx_keymap>, got_subseq=0) at /home/pedro/gdb/mygit/build/../src/readline/readline.c:774 #3 0x0000000000768acb in _rl_dispatch_callback (cxt=0x1ce6190) at /home/pedro/gdb/mygit/build/../src/readline/readline.c:686 #4 0x000000000078120b in rl_callback_read_char () at /home/pedro/gdb/mygit/build/../src/readline/callback.c:170 #5 0x0000000000619445 in rl_callback_read_char_wrapper (client_data=0x0) at /home/pedro/gdb/mygit/build/../src/gdb/event-top.c:166 #6 0x000000000061981b in stdin_event_handler (error=0, client_data=0x0) at /home/pedro/gdb/mygit/build/../src/gdb/event-top.c:372 #7 0x000000000061840e in handle_file_event (data=...) at /home/pedro/gdb/mygit/build/../src/gdb/event-loop.c:762 #8 0x00000000006178f5 in process_event () at /home/pedro/gdb/mygit/build/../src/gdb/event-loop.c:339 #9 0x00000000006179bc in gdb_do_one_event () at /home/pedro/gdb/mygit/build/../src/gdb/event-loop.c:403 #10 0x0000000000617a0c in start_event_loop () at /home/pedro/gdb/mygit/build/../src/gdb/event-loop.c:428 Here, in _rl_dispatch_subseq: 769 770 rl_executing_keymap = map; 771 772 rl_dispatching = 1; 773 RL_SETSTATE(RL_STATE_DISPATCHING); 774 (*map[key].function)(rl_numeric_arg * rl_arg_sign, key); 775 RL_UNSETSTATE(RL_STATE_DISPATCHING); 776 rl_dispatching = 0; 777 778 /* If we have input pending, then the last command was a prefix 779 command. Don't change the state of rl_last_func. Otherwise, GDB is called from line 774, but longjmp'ing at that point leaves rl_dispatching and RL_STATE_DISPATCHING set. Fix this by wrapping tui_rl_switch_mode in a TRY_CATCH. gdb/ 2014-10-29 Pedro Alves <palves@redhat.com> * tui/tui.c (tui_rl_switch_mode): Wrap tui_enable/tui_disable in TRY_CATCH.
2014-10-29 12:58:12 +01:00
/* Don't let exceptions escape. We're in the middle of a readline
callback that isn't prepared for that. */
Split TRY_CATCH into TRY + CATCH This patch splits the TRY_CATCH macro into three, so that we go from this: ~~~ volatile gdb_exception ex; TRY_CATCH (ex, RETURN_MASK_ERROR) { } if (ex.reason < 0) { } ~~~ to this: ~~~ TRY { } CATCH (ex, RETURN_MASK_ERROR) { } END_CATCH ~~~ Thus, we'll be getting rid of the local volatile exception object, and declaring the caught exception in the catch block. This allows reimplementing TRY/CATCH in terms of C++ exceptions when building in C++ mode, while still allowing to build GDB in C mode (using setjmp/longjmp), as a transition step. TBC, after this patch, is it _not_ valid to have code between the TRY and the CATCH blocks, like: TRY { } // some code here. CATCH (ex, RETURN_MASK_ERROR) { } END_CATCH Just like it isn't valid to do that with C++'s native try/catch. By switching to creating the exception object inside the CATCH block scope, we can get rid of all the explicitly allocated volatile exception objects all over the tree, and map the CATCH block more directly to C++'s catch blocks. The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was done with a script, rerun from scratch at every rebase, no manual editing involved. After the mechanical conversion, a few places needed manual intervention, to fix preexisting cases where we were using the exception object outside of the TRY_CATCH block, and cases where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH after this patch]. The result was folded into this patch so that GDB still builds at each incremental step. END_CATCH is necessary for two reasons: First, because we name the exception object in the CATCH block, which requires creating a scope, which in turn must be closed somewhere. Declaring the exception variable in the initializer field of a for block, like: #define CATCH(EXCEPTION, mask) \ for (struct gdb_exception EXCEPTION; \ exceptions_state_mc_catch (&EXCEPTION, MASK); \ EXCEPTION = exception_none) would avoid needing END_CATCH, but alas, in C mode, we build with C90, which doesn't allow mixed declarations and code. Second, because when TRY/CATCH are wired to real C++ try/catch, as long as we need to handle cleanup chains, even if there's no CATCH block that wants to catch the exception, we need for stop at every frame in the unwind chain and run cleanups, then rethrow. That will be done in END_CATCH. After we require C++, we'll still need TRY/CATCH/END_CATCH until cleanups are completely phased out -- TRY/CATCH in C++ mode will save/restore the current cleanup chain, like in C mode, and END_CATCH catches otherwise uncaugh exceptions, runs cleanups and rethrows, so that C++ cleanups and exceptions can coexist. IMO, this still makes the TRY/CATCH code look a bit more like a newcomer would expect, so IMO worth it even if we weren't considering C++. gdb/ChangeLog. 2015-03-07 Pedro Alves <palves@redhat.com> * common/common-exceptions.c (struct catcher) <exception>: No longer a pointer to volatile exception. Now an exception value. <mask>: Delete field. (exceptions_state_mc_init): Remove all parameters. Adjust. (exceptions_state_mc): No longer pop the catcher here. (exceptions_state_mc_catch): New function. (throw_exception): Adjust. * common/common-exceptions.h (exceptions_state_mc_init): Remove all parameters. (exceptions_state_mc_catch): Declare. (TRY_CATCH): Rename to ... (TRY): ... this. Remove EXCEPTION and MASK parameters. (CATCH, END_CATCH): New. All callers adjusted. gdb/gdbserver/ChangeLog: 2015-03-07 Pedro Alves <palves@redhat.com> Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH instead.
2015-03-07 16:14:14 +01:00
TRY
{
TUI: don't let exceptions escape while handling readline key bindings I noticed that with: $ TERM=dumb ./gdb -q -nx <c-x,a> Cannot enable the TUI: terminal doesn't support cursor addressing [TERM=dumb] (gdb) The next key the user types is silently eaten. The problem is that we're throwing an exception while in a readline callback that isn't prepared for that: (top-gdb) bt #0 tui_enable () at /home/pedro/gdb/mygit/build/../src/gdb/tui/tui.c:388 #1 0x000000000051f47b in tui_rl_switch_mode (notused1=1, notused2=1) at /home/pedro/gdb/mygit/build/../src/gdb/tui/tui.c:101 #2 0x0000000000768d6f in _rl_dispatch_subseq (key=1, map=0xd069c0 <emacs_ctlx_keymap>, got_subseq=0) at /home/pedro/gdb/mygit/build/../src/readline/readline.c:774 #3 0x0000000000768acb in _rl_dispatch_callback (cxt=0x1ce6190) at /home/pedro/gdb/mygit/build/../src/readline/readline.c:686 #4 0x000000000078120b in rl_callback_read_char () at /home/pedro/gdb/mygit/build/../src/readline/callback.c:170 #5 0x0000000000619445 in rl_callback_read_char_wrapper (client_data=0x0) at /home/pedro/gdb/mygit/build/../src/gdb/event-top.c:166 #6 0x000000000061981b in stdin_event_handler (error=0, client_data=0x0) at /home/pedro/gdb/mygit/build/../src/gdb/event-top.c:372 #7 0x000000000061840e in handle_file_event (data=...) at /home/pedro/gdb/mygit/build/../src/gdb/event-loop.c:762 #8 0x00000000006178f5 in process_event () at /home/pedro/gdb/mygit/build/../src/gdb/event-loop.c:339 #9 0x00000000006179bc in gdb_do_one_event () at /home/pedro/gdb/mygit/build/../src/gdb/event-loop.c:403 #10 0x0000000000617a0c in start_event_loop () at /home/pedro/gdb/mygit/build/../src/gdb/event-loop.c:428 Here, in _rl_dispatch_subseq: 769 770 rl_executing_keymap = map; 771 772 rl_dispatching = 1; 773 RL_SETSTATE(RL_STATE_DISPATCHING); 774 (*map[key].function)(rl_numeric_arg * rl_arg_sign, key); 775 RL_UNSETSTATE(RL_STATE_DISPATCHING); 776 rl_dispatching = 0; 777 778 /* If we have input pending, then the last command was a prefix 779 command. Don't change the state of rl_last_func. Otherwise, GDB is called from line 774, but longjmp'ing at that point leaves rl_dispatching and RL_STATE_DISPATCHING set. Fix this by wrapping tui_rl_switch_mode in a TRY_CATCH. gdb/ 2014-10-29 Pedro Alves <palves@redhat.com> * tui/tui.c (tui_rl_switch_mode): Wrap tui_enable/tui_disable in TRY_CATCH.
2014-10-29 12:58:12 +01:00
if (tui_active)
{
tui_disable ();
rl_prep_terminal (0);
}
else
{
/* If tui_enable throws, we'll re-prep below. */
rl_deprep_terminal ();
tui_enable ();
}
}
Split TRY_CATCH into TRY + CATCH This patch splits the TRY_CATCH macro into three, so that we go from this: ~~~ volatile gdb_exception ex; TRY_CATCH (ex, RETURN_MASK_ERROR) { } if (ex.reason < 0) { } ~~~ to this: ~~~ TRY { } CATCH (ex, RETURN_MASK_ERROR) { } END_CATCH ~~~ Thus, we'll be getting rid of the local volatile exception object, and declaring the caught exception in the catch block. This allows reimplementing TRY/CATCH in terms of C++ exceptions when building in C++ mode, while still allowing to build GDB in C mode (using setjmp/longjmp), as a transition step. TBC, after this patch, is it _not_ valid to have code between the TRY and the CATCH blocks, like: TRY { } // some code here. CATCH (ex, RETURN_MASK_ERROR) { } END_CATCH Just like it isn't valid to do that with C++'s native try/catch. By switching to creating the exception object inside the CATCH block scope, we can get rid of all the explicitly allocated volatile exception objects all over the tree, and map the CATCH block more directly to C++'s catch blocks. The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was done with a script, rerun from scratch at every rebase, no manual editing involved. After the mechanical conversion, a few places needed manual intervention, to fix preexisting cases where we were using the exception object outside of the TRY_CATCH block, and cases where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH after this patch]. The result was folded into this patch so that GDB still builds at each incremental step. END_CATCH is necessary for two reasons: First, because we name the exception object in the CATCH block, which requires creating a scope, which in turn must be closed somewhere. Declaring the exception variable in the initializer field of a for block, like: #define CATCH(EXCEPTION, mask) \ for (struct gdb_exception EXCEPTION; \ exceptions_state_mc_catch (&EXCEPTION, MASK); \ EXCEPTION = exception_none) would avoid needing END_CATCH, but alas, in C mode, we build with C90, which doesn't allow mixed declarations and code. Second, because when TRY/CATCH are wired to real C++ try/catch, as long as we need to handle cleanup chains, even if there's no CATCH block that wants to catch the exception, we need for stop at every frame in the unwind chain and run cleanups, then rethrow. That will be done in END_CATCH. After we require C++, we'll still need TRY/CATCH/END_CATCH until cleanups are completely phased out -- TRY/CATCH in C++ mode will save/restore the current cleanup chain, like in C mode, and END_CATCH catches otherwise uncaugh exceptions, runs cleanups and rethrows, so that C++ cleanups and exceptions can coexist. IMO, this still makes the TRY/CATCH code look a bit more like a newcomer would expect, so IMO worth it even if we weren't considering C++. gdb/ChangeLog. 2015-03-07 Pedro Alves <palves@redhat.com> * common/common-exceptions.c (struct catcher) <exception>: No longer a pointer to volatile exception. Now an exception value. <mask>: Delete field. (exceptions_state_mc_init): Remove all parameters. Adjust. (exceptions_state_mc): No longer pop the catcher here. (exceptions_state_mc_catch): New function. (throw_exception): Adjust. * common/common-exceptions.h (exceptions_state_mc_init): Remove all parameters. (exceptions_state_mc_catch): Declare. (TRY_CATCH): Rename to ... (TRY): ... this. Remove EXCEPTION and MASK parameters. (CATCH, END_CATCH): New. All callers adjusted. gdb/gdbserver/ChangeLog: 2015-03-07 Pedro Alves <palves@redhat.com> Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH instead.
2015-03-07 16:14:14 +01:00
CATCH (ex, RETURN_MASK_ALL)
{
TUI: don't let exceptions escape while handling readline key bindings I noticed that with: $ TERM=dumb ./gdb -q -nx <c-x,a> Cannot enable the TUI: terminal doesn't support cursor addressing [TERM=dumb] (gdb) The next key the user types is silently eaten. The problem is that we're throwing an exception while in a readline callback that isn't prepared for that: (top-gdb) bt #0 tui_enable () at /home/pedro/gdb/mygit/build/../src/gdb/tui/tui.c:388 #1 0x000000000051f47b in tui_rl_switch_mode (notused1=1, notused2=1) at /home/pedro/gdb/mygit/build/../src/gdb/tui/tui.c:101 #2 0x0000000000768d6f in _rl_dispatch_subseq (key=1, map=0xd069c0 <emacs_ctlx_keymap>, got_subseq=0) at /home/pedro/gdb/mygit/build/../src/readline/readline.c:774 #3 0x0000000000768acb in _rl_dispatch_callback (cxt=0x1ce6190) at /home/pedro/gdb/mygit/build/../src/readline/readline.c:686 #4 0x000000000078120b in rl_callback_read_char () at /home/pedro/gdb/mygit/build/../src/readline/callback.c:170 #5 0x0000000000619445 in rl_callback_read_char_wrapper (client_data=0x0) at /home/pedro/gdb/mygit/build/../src/gdb/event-top.c:166 #6 0x000000000061981b in stdin_event_handler (error=0, client_data=0x0) at /home/pedro/gdb/mygit/build/../src/gdb/event-top.c:372 #7 0x000000000061840e in handle_file_event (data=...) at /home/pedro/gdb/mygit/build/../src/gdb/event-loop.c:762 #8 0x00000000006178f5 in process_event () at /home/pedro/gdb/mygit/build/../src/gdb/event-loop.c:339 #9 0x00000000006179bc in gdb_do_one_event () at /home/pedro/gdb/mygit/build/../src/gdb/event-loop.c:403 #10 0x0000000000617a0c in start_event_loop () at /home/pedro/gdb/mygit/build/../src/gdb/event-loop.c:428 Here, in _rl_dispatch_subseq: 769 770 rl_executing_keymap = map; 771 772 rl_dispatching = 1; 773 RL_SETSTATE(RL_STATE_DISPATCHING); 774 (*map[key].function)(rl_numeric_arg * rl_arg_sign, key); 775 RL_UNSETSTATE(RL_STATE_DISPATCHING); 776 rl_dispatching = 0; 777 778 /* If we have input pending, then the last command was a prefix 779 command. Don't change the state of rl_last_func. Otherwise, GDB is called from line 774, but longjmp'ing at that point leaves rl_dispatching and RL_STATE_DISPATCHING set. Fix this by wrapping tui_rl_switch_mode in a TRY_CATCH. gdb/ 2014-10-29 Pedro Alves <palves@redhat.com> * tui/tui.c (tui_rl_switch_mode): Wrap tui_enable/tui_disable in TRY_CATCH.
2014-10-29 12:58:12 +01:00
exception_print (gdb_stderr, ex);
if (!tui_active)
rl_prep_terminal (0);
}
Split TRY_CATCH into TRY + CATCH This patch splits the TRY_CATCH macro into three, so that we go from this: ~~~ volatile gdb_exception ex; TRY_CATCH (ex, RETURN_MASK_ERROR) { } if (ex.reason < 0) { } ~~~ to this: ~~~ TRY { } CATCH (ex, RETURN_MASK_ERROR) { } END_CATCH ~~~ Thus, we'll be getting rid of the local volatile exception object, and declaring the caught exception in the catch block. This allows reimplementing TRY/CATCH in terms of C++ exceptions when building in C++ mode, while still allowing to build GDB in C mode (using setjmp/longjmp), as a transition step. TBC, after this patch, is it _not_ valid to have code between the TRY and the CATCH blocks, like: TRY { } // some code here. CATCH (ex, RETURN_MASK_ERROR) { } END_CATCH Just like it isn't valid to do that with C++'s native try/catch. By switching to creating the exception object inside the CATCH block scope, we can get rid of all the explicitly allocated volatile exception objects all over the tree, and map the CATCH block more directly to C++'s catch blocks. The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was done with a script, rerun from scratch at every rebase, no manual editing involved. After the mechanical conversion, a few places needed manual intervention, to fix preexisting cases where we were using the exception object outside of the TRY_CATCH block, and cases where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH after this patch]. The result was folded into this patch so that GDB still builds at each incremental step. END_CATCH is necessary for two reasons: First, because we name the exception object in the CATCH block, which requires creating a scope, which in turn must be closed somewhere. Declaring the exception variable in the initializer field of a for block, like: #define CATCH(EXCEPTION, mask) \ for (struct gdb_exception EXCEPTION; \ exceptions_state_mc_catch (&EXCEPTION, MASK); \ EXCEPTION = exception_none) would avoid needing END_CATCH, but alas, in C mode, we build with C90, which doesn't allow mixed declarations and code. Second, because when TRY/CATCH are wired to real C++ try/catch, as long as we need to handle cleanup chains, even if there's no CATCH block that wants to catch the exception, we need for stop at every frame in the unwind chain and run cleanups, then rethrow. That will be done in END_CATCH. After we require C++, we'll still need TRY/CATCH/END_CATCH until cleanups are completely phased out -- TRY/CATCH in C++ mode will save/restore the current cleanup chain, like in C mode, and END_CATCH catches otherwise uncaugh exceptions, runs cleanups and rethrows, so that C++ cleanups and exceptions can coexist. IMO, this still makes the TRY/CATCH code look a bit more like a newcomer would expect, so IMO worth it even if we weren't considering C++. gdb/ChangeLog. 2015-03-07 Pedro Alves <palves@redhat.com> * common/common-exceptions.c (struct catcher) <exception>: No longer a pointer to volatile exception. Now an exception value. <mask>: Delete field. (exceptions_state_mc_init): Remove all parameters. Adjust. (exceptions_state_mc): No longer pop the catcher here. (exceptions_state_mc_catch): New function. (throw_exception): Adjust. * common/common-exceptions.h (exceptions_state_mc_init): Remove all parameters. (exceptions_state_mc_catch): Declare. (TRY_CATCH): Rename to ... (TRY): ... this. Remove EXCEPTION and MASK parameters. (CATCH, END_CATCH): New. All callers adjusted. gdb/gdbserver/ChangeLog: 2015-03-07 Pedro Alves <palves@redhat.com> Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH instead.
2015-03-07 16:14:14 +01:00
END_CATCH
/* Clear the readline in case switching occurred in middle of
something. */
if (rl_end)
rl_kill_text (0, rl_end);
/* Since we left the curses mode, the terminal mode is restored to
some previous state. That state may not be suitable for readline
to work correctly (it may be restored in line mode). We force an
exit of the current readline so that readline is re-entered and
it will be able to setup the terminal for its needs. By
re-entering in readline, we also redisplay its prompt in the
non-curses mode. */
rl_newline (1, '\n');
/* Make sure the \n we are returning does not repeat the last
command. */
dont_repeat ();
return 0;
}
/* TUI readline command.
Change the TUI layout to show a next layout.
This function is bound to CTRL-X 2. It is intended to provide
a functionality close to the Emacs split-window command. We
always show two windows (src+asm), (src+regs) or (asm+regs). */
static int
tui_rl_change_windows (int notused1, int notused2)
{
if (!tui_active)
tui_rl_switch_mode (0 /* notused */, 0 /* notused */);
if (tui_active)
{
enum tui_layout_type new_layout;
2004-02-06 Andrew Cagney <cagney@redhat.com> * tui/tui-data.h (struct tui_list): Rename _TuiList. (enum tui_data_type): Rename _TuiDataType. (struct tui_layout_def): Rename _TuiLayoutDef. (struct tui_source_element): Rename _TuiSourceElement. (struct tui_data_element): Rename _TuiDataElement. (struct tui_command_element): Rename _TuiCommandElement. (struct tui_locator_element): Rename _TuiLocatorElement. (union tui_which_element): Define. (struct tui_win_element): Rename _TuiWinElement. (struct tui_data_info): Rename _TuiDataInfo. (struct tui_source_info): Rename _TuiSourceInfo. (struct tui_command_info): Rename _TuiCommandInfo. (tui_initialize_static_data): Rename initializeStaticData. (tui_alloc_generic_win_info): Rename allocGenericWinInfo. (tui_alloc_win_info): Rename allocWinInfo. (tui_init_generic_part): Rename initGenericPart. (tui_init_win_info): Rename initWinInfo. (tui_alloc_content): Rename allocContent. (tui_add_content_elements): Rename addContentElements. (tui_init_content_element): Rename initContentElement. (tui_free_window): Rename freeWindow. (tui_free_win_content): Rename freeWinContent. (tui_free_data_content): Rename freeDataContent. (tui_free_all_source_wins_content): Rename freeAllSourceWinsContent. (tui_del_window): Rename tuiDelWindow. (tui_del_data_windows): Rename tuiDelDataWindows. (tui_partial_win_by_name): Rename partialWinByName. (tui_win_name): Rename winName. (tui_current_layout): Rename currentLayout. (tui_set_current_layout_to): Rename setCurrentLayoutTo. (tui_term_height): Rename termHeight. (tui_set_term_height_to): Rename setTermHeightTo. (tui_term_width): Rename termWidth. (tui_set_term_width_to): Rename setTermWidthTo. (tui_set_gen_win_origin): Rename setGenWinOrigin. (tui_locator_win_info_ptr): Rename locatorWinInfoPtr. (tui_source_exec_info_win_ptr): Rename tui_gen_win_info. (tui_disassem_exec_info_win_ptr): Rename disassemExecInfoWinPtr. (tui_source_windows): Rename sourceWindows. (tui_clear_source_windows): Rename clearSourceWindows. (tui_clear_source_windows_detail): Rename clearSourceWindowsDetail. (tui_clear_win_detail): Rename clearWinDetail. (tui_add_to_source_windows): Rename tuiAddToSourceWindows. (tui_default_tab_len): Rename tuiDefaultTabLen. (tui_set_default_tab_len): Rename tuiSetDefaultTabLen. (tui_win_with_focus): Rename tuiWinWithFocus. (tui_set_win_with_focus): Rename tuiSetWinWithFocus. (tui_layout_def): Rename tuiLayoutDef. (tui_win_resized): Rename tuiWinResized. (tui_set_win_resized_to): Rename tuiSetWinResizedTo. (tui_next_win): Rename tuiNextWin. (tui_prev_win): Rename tuiPrevWin. (tui_add_to_source_windows): Rename addToSourceWindows. * tui/tui-winsource.c, tui/tui-win.c: Update references. * tui/tui-layout.c, tui/tui-source.c: Ditto. * tui/tui-stack.c, tui/tui-io.c: Ditto. * tui/tui.c, tui/tui-data.c: Ditto. * tui/tui-interp.c, tui/tui-data.c: Ditto. * tui/tui-disasm.c, tui/tui-command.c: Ditto.
2004-02-07 05:40:36 +01:00
new_layout = tui_current_layout ();
/* Select a new layout to have a rolling layout behavior with
always two windows (except when undefined). */
switch (new_layout)
{
case SRC_COMMAND:
new_layout = SRC_DISASSEM_COMMAND;
break;
case DISASSEM_COMMAND:
new_layout = SRC_DISASSEM_COMMAND;
break;
case SRC_DATA_COMMAND:
new_layout = SRC_DISASSEM_COMMAND;
break;
case SRC_DISASSEM_COMMAND:
new_layout = DISASSEM_DATA_COMMAND;
break;
case DISASSEM_DATA_COMMAND:
new_layout = SRC_DATA_COMMAND;
break;
default:
new_layout = SRC_COMMAND;
break;
}
gdb: Remove register class specific layout names. The layout command supports the layout names $FREGS, $GREGS, $SREGS, and $REGS. The intention of these layout names was to display the tui register window with a specific set of registers. First, these layout names no longer work, and haven't for a while, using any of them will just result in switching to the general register view. Second there is already the command 'tui reg GROUP' command to set the displayed register set to GROUP, so making the layout command also control the register set feels like unnecessary overloading of the layout command. This commit removes all code relating to supporting the register set specific names from the layout command. Afterwards the user can select an available layout using the layout command, and control the choice of register set using the 'tui reg GROUP' command. gdb/ChangeLog: * tui/tui-layout.c (tui_set_layout): Remove tui_register_display_type parameter. Remove all checking of this parameter, and reindent function. Update header comment. (tui_set_layout_for_display_command): Rename to... (tui_set_layout_by_name): ...this, and don't check for different register class types, don't pass a tui_register_display_type to tui_set_layout. Update header comment. (layout_names): Remove register set specific names. * tui/tui-layout.h (tui_set_layout): Remove tui_register_display_type parameter. * tui/tui.c (tui_rl_change_windows): Don't pass a tui_register_display_type to tui_set_layout. (tui_rl_delete_other_windows): Likewise. (tui_enable): Likewise. * tui/tui-data.h (TUI_FLOAT_REGS_NAME): Remove. (TUI_FLOAT_REGS_NAME_LOWER): Remove. (TUI_GENERAL_REGS_NAME): Remove. (TUI_GENERAL_REGS_NAME_LOWER): Remove. (TUI_SPECIAL_REGS_NAME): Remove. (TUI_SPECIAL_REGS_NAME_LOWER): Remove. (TUI_GENERAL_SPECIAL_REGS_NAME): Remove. (TUI_GENERAL_SPECIAL_REGS_NAME_LOWER): Remove. (enum tui_register_display_type): Remove. (struct tui_layout_def): Remove regs_display_type and float_regs_display_type fields. (struct tui_data_info): Remove regs_display_type field. (tui_layout_command): Use new name for tui_set_layout_for_display_command. * tui/tui-data.c (layout_def): Don't initialise removed fields. (tui_clear_win_detail): Don't initialise removed fields of win_info. * tui/tui-regs.c (tui_show_registers): Use new name for tui_set_layout_for_display_command. * tui/tui.h (tui_set_layout_for_display_command): Rename declaration to... (tui_set_layout_by_name): ...this. * printcmd.c (display_command): Remove tui related layout call, and reindent.
2015-05-20 23:35:07 +02:00
tui_set_layout (new_layout);
}
return 0;
}
/* TUI readline command.
Delete the second TUI window to only show one. */
static int
tui_rl_delete_other_windows (int notused1, int notused2)
{
if (!tui_active)
tui_rl_switch_mode (0 /* notused */, 0 /* notused */);
if (tui_active)
{
enum tui_layout_type new_layout;
2004-02-06 Andrew Cagney <cagney@redhat.com> * tui/tui-data.h (struct tui_list): Rename _TuiList. (enum tui_data_type): Rename _TuiDataType. (struct tui_layout_def): Rename _TuiLayoutDef. (struct tui_source_element): Rename _TuiSourceElement. (struct tui_data_element): Rename _TuiDataElement. (struct tui_command_element): Rename _TuiCommandElement. (struct tui_locator_element): Rename _TuiLocatorElement. (union tui_which_element): Define. (struct tui_win_element): Rename _TuiWinElement. (struct tui_data_info): Rename _TuiDataInfo. (struct tui_source_info): Rename _TuiSourceInfo. (struct tui_command_info): Rename _TuiCommandInfo. (tui_initialize_static_data): Rename initializeStaticData. (tui_alloc_generic_win_info): Rename allocGenericWinInfo. (tui_alloc_win_info): Rename allocWinInfo. (tui_init_generic_part): Rename initGenericPart. (tui_init_win_info): Rename initWinInfo. (tui_alloc_content): Rename allocContent. (tui_add_content_elements): Rename addContentElements. (tui_init_content_element): Rename initContentElement. (tui_free_window): Rename freeWindow. (tui_free_win_content): Rename freeWinContent. (tui_free_data_content): Rename freeDataContent. (tui_free_all_source_wins_content): Rename freeAllSourceWinsContent. (tui_del_window): Rename tuiDelWindow. (tui_del_data_windows): Rename tuiDelDataWindows. (tui_partial_win_by_name): Rename partialWinByName. (tui_win_name): Rename winName. (tui_current_layout): Rename currentLayout. (tui_set_current_layout_to): Rename setCurrentLayoutTo. (tui_term_height): Rename termHeight. (tui_set_term_height_to): Rename setTermHeightTo. (tui_term_width): Rename termWidth. (tui_set_term_width_to): Rename setTermWidthTo. (tui_set_gen_win_origin): Rename setGenWinOrigin. (tui_locator_win_info_ptr): Rename locatorWinInfoPtr. (tui_source_exec_info_win_ptr): Rename tui_gen_win_info. (tui_disassem_exec_info_win_ptr): Rename disassemExecInfoWinPtr. (tui_source_windows): Rename sourceWindows. (tui_clear_source_windows): Rename clearSourceWindows. (tui_clear_source_windows_detail): Rename clearSourceWindowsDetail. (tui_clear_win_detail): Rename clearWinDetail. (tui_add_to_source_windows): Rename tuiAddToSourceWindows. (tui_default_tab_len): Rename tuiDefaultTabLen. (tui_set_default_tab_len): Rename tuiSetDefaultTabLen. (tui_win_with_focus): Rename tuiWinWithFocus. (tui_set_win_with_focus): Rename tuiSetWinWithFocus. (tui_layout_def): Rename tuiLayoutDef. (tui_win_resized): Rename tuiWinResized. (tui_set_win_resized_to): Rename tuiSetWinResizedTo. (tui_next_win): Rename tuiNextWin. (tui_prev_win): Rename tuiPrevWin. (tui_add_to_source_windows): Rename addToSourceWindows. * tui/tui-winsource.c, tui/tui-win.c: Update references. * tui/tui-layout.c, tui/tui-source.c: Ditto. * tui/tui-stack.c, tui/tui-io.c: Ditto. * tui/tui.c, tui/tui-data.c: Ditto. * tui/tui-interp.c, tui/tui-data.c: Ditto. * tui/tui-disasm.c, tui/tui-command.c: Ditto.
2004-02-07 05:40:36 +01:00
new_layout = tui_current_layout ();
/* Kill one window. */
switch (new_layout)
{
case SRC_COMMAND:
case SRC_DATA_COMMAND:
case SRC_DISASSEM_COMMAND:
default:
new_layout = SRC_COMMAND;
break;
case DISASSEM_COMMAND:
case DISASSEM_DATA_COMMAND:
new_layout = DISASSEM_COMMAND;
break;
}
gdb: Remove register class specific layout names. The layout command supports the layout names $FREGS, $GREGS, $SREGS, and $REGS. The intention of these layout names was to display the tui register window with a specific set of registers. First, these layout names no longer work, and haven't for a while, using any of them will just result in switching to the general register view. Second there is already the command 'tui reg GROUP' command to set the displayed register set to GROUP, so making the layout command also control the register set feels like unnecessary overloading of the layout command. This commit removes all code relating to supporting the register set specific names from the layout command. Afterwards the user can select an available layout using the layout command, and control the choice of register set using the 'tui reg GROUP' command. gdb/ChangeLog: * tui/tui-layout.c (tui_set_layout): Remove tui_register_display_type parameter. Remove all checking of this parameter, and reindent function. Update header comment. (tui_set_layout_for_display_command): Rename to... (tui_set_layout_by_name): ...this, and don't check for different register class types, don't pass a tui_register_display_type to tui_set_layout. Update header comment. (layout_names): Remove register set specific names. * tui/tui-layout.h (tui_set_layout): Remove tui_register_display_type parameter. * tui/tui.c (tui_rl_change_windows): Don't pass a tui_register_display_type to tui_set_layout. (tui_rl_delete_other_windows): Likewise. (tui_enable): Likewise. * tui/tui-data.h (TUI_FLOAT_REGS_NAME): Remove. (TUI_FLOAT_REGS_NAME_LOWER): Remove. (TUI_GENERAL_REGS_NAME): Remove. (TUI_GENERAL_REGS_NAME_LOWER): Remove. (TUI_SPECIAL_REGS_NAME): Remove. (TUI_SPECIAL_REGS_NAME_LOWER): Remove. (TUI_GENERAL_SPECIAL_REGS_NAME): Remove. (TUI_GENERAL_SPECIAL_REGS_NAME_LOWER): Remove. (enum tui_register_display_type): Remove. (struct tui_layout_def): Remove regs_display_type and float_regs_display_type fields. (struct tui_data_info): Remove regs_display_type field. (tui_layout_command): Use new name for tui_set_layout_for_display_command. * tui/tui-data.c (layout_def): Don't initialise removed fields. (tui_clear_win_detail): Don't initialise removed fields of win_info. * tui/tui-regs.c (tui_show_registers): Use new name for tui_set_layout_for_display_command. * tui/tui.h (tui_set_layout_for_display_command): Rename declaration to... (tui_set_layout_by_name): ...this. * printcmd.c (display_command): Remove tui related layout call, and reindent.
2015-05-20 23:35:07 +02:00
tui_set_layout (new_layout);
}
return 0;
}
/* TUI readline command.
Switch the active window to give the focus to a next window. */
static int
tui_rl_other_window (int count, int key)
{
struct tui_win_info *win_info;
if (!tui_active)
tui_rl_switch_mode (0 /* notused */, 0 /* notused */);
win_info = tui_next_win (tui_win_with_focus ());
if (win_info)
{
tui_set_win_focus_to (win_info);
if (TUI_DATA_WIN && TUI_DATA_WIN->generic.is_visible)
tui_refresh_data_win ();
keypad (TUI_CMD_WIN->generic.handle, (win_info != TUI_CMD_WIN));
}
return 0;
}
/* TUI readline command.
Execute the gdb command bound to the specified key. */
static int
tui_rl_command_key (int count, int key)
{
int i;
reinitialize_more_filter ();
for (i = 0; tui_commands[i].cmd; i++)
{
if (tui_commands[i].key == key)
{
/* Insert the command in the readline buffer.
Avoid calling the gdb command here since it creates
a possible recursion on readline if prompt_for_continue
is called (See PR 9584). The command will also appear
in the readline history which turns out to be better. */
rl_insert_text (tui_commands[i].cmd);
rl_newline (1, '\n');
/* Switch to gdb command mode while executing the command.
This way the gdb's continue prompty will be displayed. */
tui_set_key_mode (TUI_ONE_COMMAND_MODE);
return 0;
}
}
return 0;
}
/* TUI readline command.
Temporarily leave the TUI SingleKey mode to allow editing
a gdb command with the normal readline. Once the command
is executed, the TUI SingleKey mode is installed back. */
static int
tui_rl_command_mode (int count, int key)
{
tui_set_key_mode (TUI_ONE_COMMAND_MODE);
return rl_insert (count, key);
}
/* TUI readline command.
Switch between TUI SingleKey mode and gdb readline editing. */
static int
tui_rl_next_keymap (int notused1, int notused2)
{
if (!tui_active)
tui_rl_switch_mode (0 /* notused */, 0 /* notused */);
tui_set_key_mode (tui_current_key_mode == TUI_COMMAND_MODE
? TUI_SINGLE_KEY_MODE : TUI_COMMAND_MODE);
return 0;
}
/* Readline hook to redisplay ourself the gdb prompt.
In the SingleKey mode, the prompt is not printed so that
the command window is cleaner. It will be displayed if
we temporarily leave the SingleKey mode. */
static int
tui_rl_startup_hook (void)
{
rl_already_prompted = 1;
if (tui_current_key_mode != TUI_COMMAND_MODE
&& !gdb_in_secondary_prompt_p (current_ui))
tui_set_key_mode (TUI_SINGLE_KEY_MODE);
tui_redisplay_readline ();
return 0;
}
/* Change the TUI key mode by installing the appropriate readline
keymap. */
void
tui_set_key_mode (enum tui_key_mode mode)
{
tui_current_key_mode = mode;
rl_set_keymap (mode == TUI_SINGLE_KEY_MODE
? tui_keymap : tui_readline_standard_keymap);
tui_show_locator_content ();
}
/* Initialize readline and configure the keymap for the switching
key shortcut. */
void
tui_initialize_readline (void)
{
int i;
Keymap tui_ctlx_keymap;
rl_initialize ();
rl_add_defun ("tui-switch-mode", tui_rl_switch_mode, -1);
rl_add_defun ("gdb-command", tui_rl_command_key, -1);
rl_add_defun ("next-keymap", tui_rl_next_keymap, -1);
tui_keymap = rl_make_bare_keymap ();
tui_ctlx_keymap = rl_make_bare_keymap ();
tui_readline_standard_keymap = rl_get_keymap ();
for (i = 0; tui_commands[i].cmd; i++)
rl_bind_key_in_map (tui_commands[i].key, tui_rl_command_key, tui_keymap);
rl_generic_bind (ISKMAP, "\\C-x", (char*) tui_ctlx_keymap, tui_keymap);
/* Bind all other keys to tui_rl_command_mode so that we switch
temporarily from SingleKey mode and can enter a gdb command. */
for (i = ' '; i < 0x7f; i++)
{
int j;
for (j = 0; tui_commands[j].cmd; j++)
if (tui_commands[j].key == i)
break;
if (tui_commands[j].cmd)
continue;
rl_bind_key_in_map (i, tui_rl_command_mode, tui_keymap);
}
rl_bind_key_in_map ('a', tui_rl_switch_mode, emacs_ctlx_keymap);
rl_bind_key_in_map ('a', tui_rl_switch_mode, tui_ctlx_keymap);
rl_bind_key_in_map ('A', tui_rl_switch_mode, emacs_ctlx_keymap);
rl_bind_key_in_map ('A', tui_rl_switch_mode, tui_ctlx_keymap);
rl_bind_key_in_map (CTRL ('A'), tui_rl_switch_mode, emacs_ctlx_keymap);
rl_bind_key_in_map (CTRL ('A'), tui_rl_switch_mode, tui_ctlx_keymap);
rl_bind_key_in_map ('1', tui_rl_delete_other_windows, emacs_ctlx_keymap);
rl_bind_key_in_map ('1', tui_rl_delete_other_windows, tui_ctlx_keymap);
rl_bind_key_in_map ('2', tui_rl_change_windows, emacs_ctlx_keymap);
rl_bind_key_in_map ('2', tui_rl_change_windows, tui_ctlx_keymap);
rl_bind_key_in_map ('o', tui_rl_other_window, emacs_ctlx_keymap);
rl_bind_key_in_map ('o', tui_rl_other_window, tui_ctlx_keymap);
rl_bind_key_in_map ('q', tui_rl_next_keymap, tui_keymap);
rl_bind_key_in_map ('s', tui_rl_next_keymap, emacs_ctlx_keymap);
rl_bind_key_in_map ('s', tui_rl_next_keymap, tui_ctlx_keymap);
}
PR tui/16138, PR tui/17519, and misc failures to initialize the terminal PR tui/16138 is about failure to initialize curses resulting in GDB exiting instead of throwing an error. E.g.: $ TERM=foo gdb (gdb) layout asm Error opening terminal: foo. $ The problem is that we're calling initscr to initialize the screen. As mentioned in http://pubs.opengroup.org/onlinepubs/7908799/xcurses/initscr.html: If errors occur, initscr() writes an appropriate error message to standard error and exits. ^^^^^ Instead, we should use newterm: "A program that needs an indication of error conditions, so it can continue to run in a line-oriented mode if the terminal cannot support a screen-oriented program, would also use this function." After the patch: $ TERM=foo gdb -q -nx (gdb) layout asm Cannot enable the TUI: error opening terminal [TERM=foo] (gdb) And then PR tui/17519 is about GDB not validating whether the terminal has the necessary capabilities when enabling the TUI. If one tries to enable the TUI with TERM=dumb (and e.g., from a shell within emacs), GDB ends up with a clear screen, the cursor is placed at the bottom/right corner of the screen, there's no prompt, typing shows no echo, and there's no indication of what's going on. c-x,a gets you out of the TUI, but it's completely non-obvious. After the patch, we get: $ TERM=dumb gdb -q -nx (gdb) layout asm Cannot enable the TUI: terminal doesn't support cursor addressing [TERM=dumb] (gdb) While at it, I've moved all the tui_allowed_p validation to tui_enable, and expanded the error messages. Previously we'd get: $ gdb -q -nx -i=mi (gdb) layout asm &"layout asm\n" &"TUI mode not allowed\n" ^error,msg="TUI mode not allowed" and: $ gdb -q -nx -ex "layout asm" > foo TUI mode not allowed While now we get: $ gdb -q -nx -i=mi (gdb) layout asm &"layout asm\n" &"Cannot enable the TUI when the interpreter is 'mi'\n" ^error,msg="Cannot enable the TUI when the interpreter is 'mi'" (gdb) and: $ gdb -q -nx -ex "layout asm" > foo Cannot enable the TUI when output is not a terminal Tested on x86_64 Fedora 20. gdb/ 2014-10-29 Pedro Alves <palves@redhat.com> PR tui/16138 PR tui/17519 * tui/tui-interp.c (tui_is_toplevel): Delete global. (tui_allowed_p): Delete function. * tui/tui.c: Include "interps.h". (tui_enable): Don't use tui_allowed_p. Error out here with detailed error messages if the TUI is the top level interpreter, or if output is not a terminal. Use newterm instead of initscr, and error out if initializing the terminal fails. Also error out if the terminal doesn't support cursor addressing. * tui/tui.h (tui_allowed_p): Delete declaration.
2014-10-29 15:23:57 +01:00
/* Return the TERM variable from the environment, or "<unset>"
if not set. */
static const char *
gdb_getenv_term (void)
{
const char *term;
term = getenv ("TERM");
if (term != NULL)
return term;
return "<unset>";
}
/* Enter in the tui mode (curses).
When in normal mode, it installs the tui hooks in gdb, redirects
the gdb output, configures the readline to work in tui mode.
When in curses mode, it does nothing. */
void
tui_enable (void)
{
if (tui_active)
return;
/* To avoid to initialize curses when gdb starts, there is a defered
curses initialization. This initialization is made only once
and the first time the curses mode is entered. */
if (tui_finish_init)
{
WINDOW *w;
PR tui/16138, PR tui/17519, and misc failures to initialize the terminal PR tui/16138 is about failure to initialize curses resulting in GDB exiting instead of throwing an error. E.g.: $ TERM=foo gdb (gdb) layout asm Error opening terminal: foo. $ The problem is that we're calling initscr to initialize the screen. As mentioned in http://pubs.opengroup.org/onlinepubs/7908799/xcurses/initscr.html: If errors occur, initscr() writes an appropriate error message to standard error and exits. ^^^^^ Instead, we should use newterm: "A program that needs an indication of error conditions, so it can continue to run in a line-oriented mode if the terminal cannot support a screen-oriented program, would also use this function." After the patch: $ TERM=foo gdb -q -nx (gdb) layout asm Cannot enable the TUI: error opening terminal [TERM=foo] (gdb) And then PR tui/17519 is about GDB not validating whether the terminal has the necessary capabilities when enabling the TUI. If one tries to enable the TUI with TERM=dumb (and e.g., from a shell within emacs), GDB ends up with a clear screen, the cursor is placed at the bottom/right corner of the screen, there's no prompt, typing shows no echo, and there's no indication of what's going on. c-x,a gets you out of the TUI, but it's completely non-obvious. After the patch, we get: $ TERM=dumb gdb -q -nx (gdb) layout asm Cannot enable the TUI: terminal doesn't support cursor addressing [TERM=dumb] (gdb) While at it, I've moved all the tui_allowed_p validation to tui_enable, and expanded the error messages. Previously we'd get: $ gdb -q -nx -i=mi (gdb) layout asm &"layout asm\n" &"TUI mode not allowed\n" ^error,msg="TUI mode not allowed" and: $ gdb -q -nx -ex "layout asm" > foo TUI mode not allowed While now we get: $ gdb -q -nx -i=mi (gdb) layout asm &"layout asm\n" &"Cannot enable the TUI when the interpreter is 'mi'\n" ^error,msg="Cannot enable the TUI when the interpreter is 'mi'" (gdb) and: $ gdb -q -nx -ex "layout asm" > foo Cannot enable the TUI when output is not a terminal Tested on x86_64 Fedora 20. gdb/ 2014-10-29 Pedro Alves <palves@redhat.com> PR tui/16138 PR tui/17519 * tui/tui-interp.c (tui_is_toplevel): Delete global. (tui_allowed_p): Delete function. * tui/tui.c: Include "interps.h". (tui_enable): Don't use tui_allowed_p. Error out here with detailed error messages if the TUI is the top level interpreter, or if output is not a terminal. Use newterm instead of initscr, and error out if initializing the terminal fails. Also error out if the terminal doesn't support cursor addressing. * tui/tui.h (tui_allowed_p): Delete declaration.
2014-10-29 15:23:57 +01:00
SCREEN *s;
const char *cap;
const char *interp;
/* If the top level interpreter is not the console/tui (e.g.,
MI), enabling curses will certainly lose. */
interp = interp_name (top_level_interpreter ());
if (strcmp (interp, INTERP_TUI) != 0)
error (_("Cannot enable the TUI when the interpreter is '%s'"), interp);
/* Don't try to setup curses (and print funny control
characters) if we're not outputting to a terminal. */
if (!ui_file_isatty (gdb_stdout))
error (_("Cannot enable the TUI when output is not a terminal"));
s = newterm (NULL, stdout, stdin);
#ifdef __MINGW32__
/* The MinGW port of ncurses requires $TERM to be unset in order
to activate the Windows console driver. */
if (s == NULL)
s = newterm ("unknown", stdout, stdin);
#endif
PR tui/16138, PR tui/17519, and misc failures to initialize the terminal PR tui/16138 is about failure to initialize curses resulting in GDB exiting instead of throwing an error. E.g.: $ TERM=foo gdb (gdb) layout asm Error opening terminal: foo. $ The problem is that we're calling initscr to initialize the screen. As mentioned in http://pubs.opengroup.org/onlinepubs/7908799/xcurses/initscr.html: If errors occur, initscr() writes an appropriate error message to standard error and exits. ^^^^^ Instead, we should use newterm: "A program that needs an indication of error conditions, so it can continue to run in a line-oriented mode if the terminal cannot support a screen-oriented program, would also use this function." After the patch: $ TERM=foo gdb -q -nx (gdb) layout asm Cannot enable the TUI: error opening terminal [TERM=foo] (gdb) And then PR tui/17519 is about GDB not validating whether the terminal has the necessary capabilities when enabling the TUI. If one tries to enable the TUI with TERM=dumb (and e.g., from a shell within emacs), GDB ends up with a clear screen, the cursor is placed at the bottom/right corner of the screen, there's no prompt, typing shows no echo, and there's no indication of what's going on. c-x,a gets you out of the TUI, but it's completely non-obvious. After the patch, we get: $ TERM=dumb gdb -q -nx (gdb) layout asm Cannot enable the TUI: terminal doesn't support cursor addressing [TERM=dumb] (gdb) While at it, I've moved all the tui_allowed_p validation to tui_enable, and expanded the error messages. Previously we'd get: $ gdb -q -nx -i=mi (gdb) layout asm &"layout asm\n" &"TUI mode not allowed\n" ^error,msg="TUI mode not allowed" and: $ gdb -q -nx -ex "layout asm" > foo TUI mode not allowed While now we get: $ gdb -q -nx -i=mi (gdb) layout asm &"layout asm\n" &"Cannot enable the TUI when the interpreter is 'mi'\n" ^error,msg="Cannot enable the TUI when the interpreter is 'mi'" (gdb) and: $ gdb -q -nx -ex "layout asm" > foo Cannot enable the TUI when output is not a terminal Tested on x86_64 Fedora 20. gdb/ 2014-10-29 Pedro Alves <palves@redhat.com> PR tui/16138 PR tui/17519 * tui/tui-interp.c (tui_is_toplevel): Delete global. (tui_allowed_p): Delete function. * tui/tui.c: Include "interps.h". (tui_enable): Don't use tui_allowed_p. Error out here with detailed error messages if the TUI is the top level interpreter, or if output is not a terminal. Use newterm instead of initscr, and error out if initializing the terminal fails. Also error out if the terminal doesn't support cursor addressing. * tui/tui.h (tui_allowed_p): Delete declaration.
2014-10-29 15:23:57 +01:00
if (s == NULL)
{
error (_("Cannot enable the TUI: error opening terminal [TERM=%s]"),
gdb_getenv_term ());
}
w = stdscr;
/* Check required terminal capabilities. The MinGW port of
ncurses does have them, but doesn't expose them through "cup". */
#ifndef __MINGW32__
PR tui/16138, PR tui/17519, and misc failures to initialize the terminal PR tui/16138 is about failure to initialize curses resulting in GDB exiting instead of throwing an error. E.g.: $ TERM=foo gdb (gdb) layout asm Error opening terminal: foo. $ The problem is that we're calling initscr to initialize the screen. As mentioned in http://pubs.opengroup.org/onlinepubs/7908799/xcurses/initscr.html: If errors occur, initscr() writes an appropriate error message to standard error and exits. ^^^^^ Instead, we should use newterm: "A program that needs an indication of error conditions, so it can continue to run in a line-oriented mode if the terminal cannot support a screen-oriented program, would also use this function." After the patch: $ TERM=foo gdb -q -nx (gdb) layout asm Cannot enable the TUI: error opening terminal [TERM=foo] (gdb) And then PR tui/17519 is about GDB not validating whether the terminal has the necessary capabilities when enabling the TUI. If one tries to enable the TUI with TERM=dumb (and e.g., from a shell within emacs), GDB ends up with a clear screen, the cursor is placed at the bottom/right corner of the screen, there's no prompt, typing shows no echo, and there's no indication of what's going on. c-x,a gets you out of the TUI, but it's completely non-obvious. After the patch, we get: $ TERM=dumb gdb -q -nx (gdb) layout asm Cannot enable the TUI: terminal doesn't support cursor addressing [TERM=dumb] (gdb) While at it, I've moved all the tui_allowed_p validation to tui_enable, and expanded the error messages. Previously we'd get: $ gdb -q -nx -i=mi (gdb) layout asm &"layout asm\n" &"TUI mode not allowed\n" ^error,msg="TUI mode not allowed" and: $ gdb -q -nx -ex "layout asm" > foo TUI mode not allowed While now we get: $ gdb -q -nx -i=mi (gdb) layout asm &"layout asm\n" &"Cannot enable the TUI when the interpreter is 'mi'\n" ^error,msg="Cannot enable the TUI when the interpreter is 'mi'" (gdb) and: $ gdb -q -nx -ex "layout asm" > foo Cannot enable the TUI when output is not a terminal Tested on x86_64 Fedora 20. gdb/ 2014-10-29 Pedro Alves <palves@redhat.com> PR tui/16138 PR tui/17519 * tui/tui-interp.c (tui_is_toplevel): Delete global. (tui_allowed_p): Delete function. * tui/tui.c: Include "interps.h". (tui_enable): Don't use tui_allowed_p. Error out here with detailed error messages if the TUI is the top level interpreter, or if output is not a terminal. Use newterm instead of initscr, and error out if initializing the terminal fails. Also error out if the terminal doesn't support cursor addressing. * tui/tui.h (tui_allowed_p): Delete declaration.
2014-10-29 15:23:57 +01:00
cap = tigetstr ("cup");
if (cap == NULL || cap == (char *) -1 || *cap == '\0')
{
endwin ();
delscreen (s);
error (_("Cannot enable the TUI: "
"terminal doesn't support cursor addressing [TERM=%s]"),
gdb_getenv_term ());
}
#endif
cbreak ();
noecho ();
/* timeout (1); */
nodelay(w, FALSE);
nl();
keypad (w, TRUE);
rl_initialize ();
2004-02-06 Andrew Cagney <cagney@redhat.com> * tui/tui-data.h (struct tui_list): Rename _TuiList. (enum tui_data_type): Rename _TuiDataType. (struct tui_layout_def): Rename _TuiLayoutDef. (struct tui_source_element): Rename _TuiSourceElement. (struct tui_data_element): Rename _TuiDataElement. (struct tui_command_element): Rename _TuiCommandElement. (struct tui_locator_element): Rename _TuiLocatorElement. (union tui_which_element): Define. (struct tui_win_element): Rename _TuiWinElement. (struct tui_data_info): Rename _TuiDataInfo. (struct tui_source_info): Rename _TuiSourceInfo. (struct tui_command_info): Rename _TuiCommandInfo. (tui_initialize_static_data): Rename initializeStaticData. (tui_alloc_generic_win_info): Rename allocGenericWinInfo. (tui_alloc_win_info): Rename allocWinInfo. (tui_init_generic_part): Rename initGenericPart. (tui_init_win_info): Rename initWinInfo. (tui_alloc_content): Rename allocContent. (tui_add_content_elements): Rename addContentElements. (tui_init_content_element): Rename initContentElement. (tui_free_window): Rename freeWindow. (tui_free_win_content): Rename freeWinContent. (tui_free_data_content): Rename freeDataContent. (tui_free_all_source_wins_content): Rename freeAllSourceWinsContent. (tui_del_window): Rename tuiDelWindow. (tui_del_data_windows): Rename tuiDelDataWindows. (tui_partial_win_by_name): Rename partialWinByName. (tui_win_name): Rename winName. (tui_current_layout): Rename currentLayout. (tui_set_current_layout_to): Rename setCurrentLayoutTo. (tui_term_height): Rename termHeight. (tui_set_term_height_to): Rename setTermHeightTo. (tui_term_width): Rename termWidth. (tui_set_term_width_to): Rename setTermWidthTo. (tui_set_gen_win_origin): Rename setGenWinOrigin. (tui_locator_win_info_ptr): Rename locatorWinInfoPtr. (tui_source_exec_info_win_ptr): Rename tui_gen_win_info. (tui_disassem_exec_info_win_ptr): Rename disassemExecInfoWinPtr. (tui_source_windows): Rename sourceWindows. (tui_clear_source_windows): Rename clearSourceWindows. (tui_clear_source_windows_detail): Rename clearSourceWindowsDetail. (tui_clear_win_detail): Rename clearWinDetail. (tui_add_to_source_windows): Rename tuiAddToSourceWindows. (tui_default_tab_len): Rename tuiDefaultTabLen. (tui_set_default_tab_len): Rename tuiSetDefaultTabLen. (tui_win_with_focus): Rename tuiWinWithFocus. (tui_set_win_with_focus): Rename tuiSetWinWithFocus. (tui_layout_def): Rename tuiLayoutDef. (tui_win_resized): Rename tuiWinResized. (tui_set_win_resized_to): Rename tuiSetWinResizedTo. (tui_next_win): Rename tuiNextWin. (tui_prev_win): Rename tuiPrevWin. (tui_add_to_source_windows): Rename addToSourceWindows. * tui/tui-winsource.c, tui/tui-win.c: Update references. * tui/tui-layout.c, tui/tui-source.c: Ditto. * tui/tui-stack.c, tui/tui-io.c: Ditto. * tui/tui.c, tui/tui-data.c: Ditto. * tui/tui-interp.c, tui/tui-data.c: Ditto. * tui/tui-disasm.c, tui/tui-command.c: Ditto.
2004-02-07 05:40:36 +01:00
tui_set_term_height_to (LINES);
tui_set_term_width_to (COLS);
def_prog_mode ();
tui_show_frame_info (0);
gdb: Remove register class specific layout names. The layout command supports the layout names $FREGS, $GREGS, $SREGS, and $REGS. The intention of these layout names was to display the tui register window with a specific set of registers. First, these layout names no longer work, and haven't for a while, using any of them will just result in switching to the general register view. Second there is already the command 'tui reg GROUP' command to set the displayed register set to GROUP, so making the layout command also control the register set feels like unnecessary overloading of the layout command. This commit removes all code relating to supporting the register set specific names from the layout command. Afterwards the user can select an available layout using the layout command, and control the choice of register set using the 'tui reg GROUP' command. gdb/ChangeLog: * tui/tui-layout.c (tui_set_layout): Remove tui_register_display_type parameter. Remove all checking of this parameter, and reindent function. Update header comment. (tui_set_layout_for_display_command): Rename to... (tui_set_layout_by_name): ...this, and don't check for different register class types, don't pass a tui_register_display_type to tui_set_layout. Update header comment. (layout_names): Remove register set specific names. * tui/tui-layout.h (tui_set_layout): Remove tui_register_display_type parameter. * tui/tui.c (tui_rl_change_windows): Don't pass a tui_register_display_type to tui_set_layout. (tui_rl_delete_other_windows): Likewise. (tui_enable): Likewise. * tui/tui-data.h (TUI_FLOAT_REGS_NAME): Remove. (TUI_FLOAT_REGS_NAME_LOWER): Remove. (TUI_GENERAL_REGS_NAME): Remove. (TUI_GENERAL_REGS_NAME_LOWER): Remove. (TUI_SPECIAL_REGS_NAME): Remove. (TUI_SPECIAL_REGS_NAME_LOWER): Remove. (TUI_GENERAL_SPECIAL_REGS_NAME): Remove. (TUI_GENERAL_SPECIAL_REGS_NAME_LOWER): Remove. (enum tui_register_display_type): Remove. (struct tui_layout_def): Remove regs_display_type and float_regs_display_type fields. (struct tui_data_info): Remove regs_display_type field. (tui_layout_command): Use new name for tui_set_layout_for_display_command. * tui/tui-data.c (layout_def): Don't initialise removed fields. (tui_clear_win_detail): Don't initialise removed fields of win_info. * tui/tui-regs.c (tui_show_registers): Use new name for tui_set_layout_for_display_command. * tui/tui.h (tui_set_layout_for_display_command): Rename declaration to... (tui_set_layout_by_name): ...this. * printcmd.c (display_command): Remove tui related layout call, and reindent.
2015-05-20 23:35:07 +02:00
tui_set_layout (SRC_COMMAND);
tui_set_win_focus_to (TUI_SRC_WIN);
keypad (TUI_CMD_WIN->generic.handle, TRUE);
wrefresh (TUI_CMD_WIN->generic.handle);
tui_finish_init = 0;
}
else
{
/* Save the current gdb setting of the terminal.
Curses will restore this state when endwin() is called. */
def_shell_mode ();
clearok (stdscr, TRUE);
}
/* Install the TUI specific hooks. */
tui_install_hooks ();
rl_startup_hook = tui_rl_startup_hook;
tui_update_variables ();
tui_setup_io (1);
tui_active = 1;
TUI: resize windows to new terminal size before displaying them If the user: #1 - disables the TUI #2 - resizes the terminal #3 - and then re-enables the TUI the next wgetch() returns KEY_RESIZE. This indicates to the ncurses client that ncurses detected that the terminal has been resized. We don't handle KEY_RESIZE anywhere, so it gets passed on to readline which interprets it as a multibyte character, and then the end result is that the first key press after enabling the TUI is misinterpreted. We shouldn't really need to handle KEY_RESIZE (and not all ncurses implementations have that). We have our own SIGWINCH handler, and, when we re-enable the TUI, we explicitly detect terminal resizes and resize all windows. The reason ncurses currently does detects a resize is that something within tui_enable forces a refresh/display of some window before we get to do the actual resizing. Setting a break on ncurses' 'resizeterm' function helps find the culprit(s): (top-gdb) bt #0 resizeterm (ToLines=28, ToCols=114) at ../../ncurses/base/resizeterm.c:462 #1 0x0000003b42812f3f in _nc_update_screensize (sp=0x2674730) at ../../ncurses/tinfo/lib_setup.c:443 #2 0x0000003b0821cbe0 in doupdate () at ../../ncurses/tty/tty_update.c:726 #3 0x0000003b08215539 in wrefresh (win=0x2a7bc00) at ../../ncurses/base/lib_refresh.c:65 #4 0x00000000005257cb in tui_refresh_win (win_info=0xd73d60 <_locator>) at /home/pedro/gdb/mygit/src/gdb/tui/tui-wingeneral.c:60 #5 0x000000000052265b in tui_show_locator_content () at /home/pedro/gdb/mygit/src/gdb/tui/tui-stack.c:269 #6 0x00000000005273a6 in tui_set_key_mode (mode=TUI_COMMAND_MODE) at /home/pedro/gdb/mygit/src/gdb/tui/tui.c:321 #7 0x00000000005278c7 in tui_enable () at /home/pedro/gdb/mygit/src/gdb/tui/tui.c:494 #8 0x0000000000527011 in tui_rl_switch_mode (notused1=1, notused2=1) at /home/pedro/gdb/mygit/src/gdb/tui/tui.c:108 That is, tui_enable calls tui_set_key_mode before we've resized all windows, and that refreshes a window as side effect. And if we're already debugging something (there's a frame), then we'll instead show a window from within tui_show_frame_info: (top-gdb) bt #0 resizeterm (ToLines=28, ToCols=114) at ../../ncurses/base/resizeterm.c:462 #1 0x0000003b42812f3f in _nc_update_screensize (sp=0x202e6c0) at ../../ncurses/tinfo/lib_setup.c:443 #2 0x0000003b0821cbe0 in doupdate () at ../../ncurses/tty/tty_update.c:726 #3 0x0000003b08215539 in wrefresh (win=0x2042890) at ../../ncurses/base/lib_refresh.c:65 #4 0x00000000005257cb in tui_refresh_win (win_info=0xd73d60 <_locator>) at /home/pedro/gdb/mygit/src/gdb/tui/tui-wingeneral.c:60 #5 0x000000000052265b in tui_show_locator_content () at /home/pedro/gdb/mygit/src/gdb/tui/tui-stack.c:269 #6 0x0000000000522931 in tui_show_frame_info (fi=0x16b9cc0) at /home/pedro/gdb/mygit/src/gdb/tui/tui-stack.c:364 #7 0x00000000005278ba in tui_enable () at /home/pedro/gdb/mygit/src/gdb/tui/tui.c:491 #8 0x0000000000527011 in tui_rl_switch_mode (notused1=1, notused2=1) at /home/pedro/gdb/mygit/src/gdb/tui/tui.c:108 The fix is to resize windows earlier. gdb/ChangeLog: 2015-02-17 Pedro Alves <palves@redhat.com> * tui/tui.c (tui_enable): Resize windows before anything might show a window.
2015-02-17 11:05:52 +01:00
/* Resize windows before anything might display/refresh a
window. */
if (tui_win_resized ())
{
tui_set_win_resized_to (FALSE);
tui_resize_all ();
}
TUI: resize windows to new terminal size before displaying them If the user: #1 - disables the TUI #2 - resizes the terminal #3 - and then re-enables the TUI the next wgetch() returns KEY_RESIZE. This indicates to the ncurses client that ncurses detected that the terminal has been resized. We don't handle KEY_RESIZE anywhere, so it gets passed on to readline which interprets it as a multibyte character, and then the end result is that the first key press after enabling the TUI is misinterpreted. We shouldn't really need to handle KEY_RESIZE (and not all ncurses implementations have that). We have our own SIGWINCH handler, and, when we re-enable the TUI, we explicitly detect terminal resizes and resize all windows. The reason ncurses currently does detects a resize is that something within tui_enable forces a refresh/display of some window before we get to do the actual resizing. Setting a break on ncurses' 'resizeterm' function helps find the culprit(s): (top-gdb) bt #0 resizeterm (ToLines=28, ToCols=114) at ../../ncurses/base/resizeterm.c:462 #1 0x0000003b42812f3f in _nc_update_screensize (sp=0x2674730) at ../../ncurses/tinfo/lib_setup.c:443 #2 0x0000003b0821cbe0 in doupdate () at ../../ncurses/tty/tty_update.c:726 #3 0x0000003b08215539 in wrefresh (win=0x2a7bc00) at ../../ncurses/base/lib_refresh.c:65 #4 0x00000000005257cb in tui_refresh_win (win_info=0xd73d60 <_locator>) at /home/pedro/gdb/mygit/src/gdb/tui/tui-wingeneral.c:60 #5 0x000000000052265b in tui_show_locator_content () at /home/pedro/gdb/mygit/src/gdb/tui/tui-stack.c:269 #6 0x00000000005273a6 in tui_set_key_mode (mode=TUI_COMMAND_MODE) at /home/pedro/gdb/mygit/src/gdb/tui/tui.c:321 #7 0x00000000005278c7 in tui_enable () at /home/pedro/gdb/mygit/src/gdb/tui/tui.c:494 #8 0x0000000000527011 in tui_rl_switch_mode (notused1=1, notused2=1) at /home/pedro/gdb/mygit/src/gdb/tui/tui.c:108 That is, tui_enable calls tui_set_key_mode before we've resized all windows, and that refreshes a window as side effect. And if we're already debugging something (there's a frame), then we'll instead show a window from within tui_show_frame_info: (top-gdb) bt #0 resizeterm (ToLines=28, ToCols=114) at ../../ncurses/base/resizeterm.c:462 #1 0x0000003b42812f3f in _nc_update_screensize (sp=0x202e6c0) at ../../ncurses/tinfo/lib_setup.c:443 #2 0x0000003b0821cbe0 in doupdate () at ../../ncurses/tty/tty_update.c:726 #3 0x0000003b08215539 in wrefresh (win=0x2042890) at ../../ncurses/base/lib_refresh.c:65 #4 0x00000000005257cb in tui_refresh_win (win_info=0xd73d60 <_locator>) at /home/pedro/gdb/mygit/src/gdb/tui/tui-wingeneral.c:60 #5 0x000000000052265b in tui_show_locator_content () at /home/pedro/gdb/mygit/src/gdb/tui/tui-stack.c:269 #6 0x0000000000522931 in tui_show_frame_info (fi=0x16b9cc0) at /home/pedro/gdb/mygit/src/gdb/tui/tui-stack.c:364 #7 0x00000000005278ba in tui_enable () at /home/pedro/gdb/mygit/src/gdb/tui/tui.c:491 #8 0x0000000000527011 in tui_rl_switch_mode (notused1=1, notused2=1) at /home/pedro/gdb/mygit/src/gdb/tui/tui.c:108 The fix is to resize windows earlier. gdb/ChangeLog: 2015-02-17 Pedro Alves <palves@redhat.com> * tui/tui.c (tui_enable): Resize windows before anything might show a window.
2015-02-17 11:05:52 +01:00
if (deprecated_safe_get_selected_frame ())
tui_show_frame_info (deprecated_safe_get_selected_frame ());
/* Restore TUI keymap. */
tui_set_key_mode (tui_current_key_mode);
/* Refresh the screen. */
tui_refresh_all_win ();
/* Update gdb's knowledge of its terminal. */
Fix terminal state corruption when starting a program from within TUI The TUI terminal state becomes corrupted (e.g. key sequences such as Alt_F and Alt_B no longer work) when one attaches to an inferior process (via "run" or "attach") from within TUI. This terminal corruption remains until you switch out of TUI mode. This happens because the terminal state is not properly saved when switching to and out from TUI mode. Although the functions tui_enable() and tui_disable() both call the function target_terminal_save_ours() to save the terminal state, this function is a no-op unless GDB has already attached to an inferior process. This is because only the "native" target has a useful implementation of target_terminal_save_ours() (namely child_terminal_save_ours()) and we only have the "native" target in our target vector if GDB has already attached to an inferior process. So without an inferior process, switching to and from TUI mode does not actually save the terminal state. Therefore when you attach to an inferior process from within TUI mode, the proper terminal state is not restored (after swapping from the inferior's terminal back to the GDB terminal). To fix this we just have to ensure that the terminal state is always being properly saved when switching from and to TUI mode. To achieve this, this patch removes the polymorphic function target_terminal_save_ours() and replaces it with a regular function gdb_save_tty_state() that always saves the terminal state. Tested on x86_64-unknown-linux-gnu by running "make check", no new regressions. gdb/ChangeLog: * target.h (struct target_ops::to_terminal_save_ours): Remove declaration. (target_terminal_save_ours): Remove macro. * target-delegates.c: Regenerate. * inf-child.c (inf_child_target): Don't set the nonexistent field to_terminal_save_ours. * inferior.h (child_terminal_save_ours): Remove declaration. * terminal.h (gdb_save_tty_state): New declaration. * inflow.c (child_terminal_save_ours): Rename to ... (gdb_save_tty_state): ... this. * tui/tui.c: Include terminal.h. (tui_enable): Use gdb_save_tty_state instead of target_terminal_save_ours. (tui_disable): Likewise.
2014-08-25 16:40:32 +02:00
gdb_save_tty_state ();
tui_update_gdb_sizes ();
}
/* Leave the tui mode.
Remove the tui hooks and configure the gdb output and readline
back to their original state. The curses mode is left so that
the terminal setting is restored to the point when we entered. */
void
tui_disable (void)
{
if (!tui_active)
return;
/* Restore initial readline keymap. */
rl_set_keymap (tui_readline_standard_keymap);
/* Remove TUI hooks. */
tui_remove_hooks ();
rl_startup_hook = 0;
rl_already_prompted = 0;
/* Leave curses and restore previous gdb terminal setting. */
endwin ();
/* gdb terminal has changed, update gdb internal copy of it
so that terminal management with the inferior works. */
tui_setup_io (0);
/* Update gdb's knowledge of its terminal. */
Fix terminal state corruption when starting a program from within TUI The TUI terminal state becomes corrupted (e.g. key sequences such as Alt_F and Alt_B no longer work) when one attaches to an inferior process (via "run" or "attach") from within TUI. This terminal corruption remains until you switch out of TUI mode. This happens because the terminal state is not properly saved when switching to and out from TUI mode. Although the functions tui_enable() and tui_disable() both call the function target_terminal_save_ours() to save the terminal state, this function is a no-op unless GDB has already attached to an inferior process. This is because only the "native" target has a useful implementation of target_terminal_save_ours() (namely child_terminal_save_ours()) and we only have the "native" target in our target vector if GDB has already attached to an inferior process. So without an inferior process, switching to and from TUI mode does not actually save the terminal state. Therefore when you attach to an inferior process from within TUI mode, the proper terminal state is not restored (after swapping from the inferior's terminal back to the GDB terminal). To fix this we just have to ensure that the terminal state is always being properly saved when switching from and to TUI mode. To achieve this, this patch removes the polymorphic function target_terminal_save_ours() and replaces it with a regular function gdb_save_tty_state() that always saves the terminal state. Tested on x86_64-unknown-linux-gnu by running "make check", no new regressions. gdb/ChangeLog: * target.h (struct target_ops::to_terminal_save_ours): Remove declaration. (target_terminal_save_ours): Remove macro. * target-delegates.c: Regenerate. * inf-child.c (inf_child_target): Don't set the nonexistent field to_terminal_save_ours. * inferior.h (child_terminal_save_ours): Remove declaration. * terminal.h (gdb_save_tty_state): New declaration. * inflow.c (child_terminal_save_ours): Rename to ... (gdb_save_tty_state): ... this. * tui/tui.c: Include terminal.h. (tui_enable): Use gdb_save_tty_state instead of target_terminal_save_ours. (tui_disable): Likewise.
2014-08-25 16:40:32 +02:00
gdb_save_tty_state ();
tui_active = 0;
tui_update_gdb_sizes ();
}
/* Command wrapper for enabling tui mode. */
static void
tui_enable_command (char *args, int from_tty)
{
tui_enable ();
}
/* Command wrapper for leaving tui mode. */
static void
tui_disable_command (char *args, int from_tty)
{
tui_disable ();
}
void
strcat_to_buf (char *buf, int buflen,
const char *item_to_add)
{
if (item_to_add != (char *) NULL && buf != (char *) NULL)
{
if ((strlen (buf) + strlen (item_to_add)) <= buflen)
strcat (buf, item_to_add);
else
strncat (buf, item_to_add, (buflen - strlen (buf)));
}
}
#if 0
/* Solaris <sys/termios.h> defines CTRL. */
#ifndef CTRL
#define CTRL(x) (x & ~0140)
#endif
#define FILEDES 2
#define CHK(val, dft) (val<=0 ? dft : val)
static void
tui_reset (void)
{
struct termio mode;
/* Reset the teletype mode bits to a sensible state.
Copied tset.c. */
#if defined (TIOCGETC)
struct tchars tbuf;
#endif /* TIOCGETC */
#ifdef UCB_NTTY
struct ltchars ltc;
if (ldisc == NTTYDISC)
{
ioctl (FILEDES, TIOCGLTC, &ltc);
ltc.t_suspc = CHK (ltc.t_suspc, CTRL ('Z'));
ltc.t_dsuspc = CHK (ltc.t_dsuspc, CTRL ('Y'));
ltc.t_rprntc = CHK (ltc.t_rprntc, CTRL ('R'));
ltc.t_flushc = CHK (ltc.t_flushc, CTRL ('O'));
ltc.t_werasc = CHK (ltc.t_werasc, CTRL ('W'));
ltc.t_lnextc = CHK (ltc.t_lnextc, CTRL ('V'));
ioctl (FILEDES, TIOCSLTC, &ltc);
}
#endif /* UCB_NTTY */
#ifdef TIOCGETC
ioctl (FILEDES, TIOCGETC, &tbuf);
tbuf.t_intrc = CHK (tbuf.t_intrc, CTRL ('?'));
tbuf.t_quitc = CHK (tbuf.t_quitc, CTRL ('\\'));
tbuf.t_startc = CHK (tbuf.t_startc, CTRL ('Q'));
tbuf.t_stopc = CHK (tbuf.t_stopc, CTRL ('S'));
tbuf.t_eofc = CHK (tbuf.t_eofc, CTRL ('D'));
/* brkc is left alone. */
ioctl (FILEDES, TIOCSETC, &tbuf);
#endif /* TIOCGETC */
mode.sg_flags &= ~(RAW
#ifdef CBREAK
| CBREAK
#endif /* CBREAK */
| VTDELAY | ALLDELAY);
mode.sg_flags |= XTABS | ECHO | CRMOD | ANYP;
return;
}
#endif
void
gdb/ * source.c (print_source_lines_base): Print for TUI also "fullname". * tui/tui-data.c (init_content_element): Change tui_locator_element field to full_name. * tui/tui-data.h (struct tui_locator_element): Likewise. * tui/tui-disasm.c (tui_show_disassem_and_update_source): Rename tui_update_locator_filename calls to tui_update_locator_fullname. Replace symtab->filename refererence by symtab_to_fullname call. * tui/tui-out.c (tui_field_string): Check for "fullname" now. * tui/tui-source.c (tui_set_source_content): Change tui_locator_element field to full_name. Replace symtab->filename refererence by symtab_to_fullname call. (tui_show_symtab_source): Rename parameter to fullname. Change tui_locator_element field to full_name. * tui/tui-stack.c: Include source.h. (tui_set_locator_filename): Rename the declaration to ... (tui_set_locator_fullname): ... here. Rename its parameter to fullname, updates its comment. (tui_set_locator_info): Rename its parameter to fullname. (tui_set_locator_filename): Rename the definition to ... (tui_set_locator_fullname): ... here. Rename its parameter to fullname, updates its comment. Change tui_locator_element field to full_name. (tui_set_locator_info): Rename its parameter to fullname. (tui_set_locator_info): Rename callee to tui_set_locator_fullname. (tui_update_locator_filename): Rename to ... (tui_update_locator_fullname): ... here. Rename callee to tui_set_locator_fullname. (tui_show_frame_info): Replace symtab->filename refererence by symtab_to_fullname call. * tui/tui-stack.h (tui_update_locator_filename): Rename to ... (tui_update_locator_fullname): ... here. * tui/tui-winsource.c (tui_display_main): Rename the callee to tui_update_locator_fullname. Replace symtab->filename refererence by symtab_to_fullname call. * tui/tui.c (tui_show_source): Rename its parameter to fullname. Rename the callee to tui_update_locator_fullname. * tui/tui.h (tui_show_source): Rename its parameter to fullname.
2013-02-03 17:16:42 +01:00
tui_show_source (const char *fullname, int line)
{
struct symtab_and_line cursal = get_current_source_symtab_and_line ();
/* Make sure that the source window is displayed. */
tui_add_win_to_layout (SRC_WIN);
2004-02-06 Andrew Cagney <cagney@redhat.com> * tui/tui-source.h: Do not include "defs.h". (struct tui_win_info): Declare. (tui_set_source_content_nil): Declare. * tui/tui-data.h (struct tui_win_info): Rename _TuiWinInfo. (union tui_line_or_address): Rename _TuiLineOrAddress. * tui/tui-winsource.h: Update copyright. Include "tui-data.h". (tui_update_source_window): Rename tuiUpdateSourceWindow. (tui_update_source_window_as_is): Rename tuiUpdateSourceWindowAsIs. (tui_update_source_windows_with_addr): Rename tuiUpdateSourceWindowsWithAddr. (tui_update_source_windows_with_line): Rename tuiUpdateSourceWindowsWithLine. (tui_clear_source_content): Rename tuiClearSourceContent. (tui_erase_source_content): Rename tuiEraseSourceContent. (tui_set_source_content_nil): Rename tuiSetSourceContentNil. (tui_show_source_content): Rename tuiShowSourceContent. (tui_horizontal_source_scroll): Rename tuiHorizontalSourceScroll. (tui_set_exec_info_content): Rename tuiSetExecInfoContent. (tui_show_exec_info_content): Rename tuiShowExecInfoContent. (tui_erase_exec_info_content): Rename tuiEraseExecInfoContent. (tui_clear_exec_info_content): Rename tuiClearExecInfoContent. (tui_update_exec_info): Rename tuiUpdateExecInfo. (tui_set_is_exec_point_at): Rename tuiSetIsExecPointAt. (tui_alloc_source_buffer): Rename tuiAllocSourceBuffer. (tui_line_is_displayed): Rename tuiLineIsDisplayed. (tui_addr_is_displayed): Rename tuiAddrIsDisplayed. (struct tui_win_info): Declare. * tui/tui-stack.c: Update references. * tui/tui-layout.c, tui/tui-winsource.c: Ditto. * tui/tui-win.c, tui/tui-source.c: Ditto. * tui/tui.c, tui/tui-disasm.c: Ditto.
2004-02-06 23:42:18 +01:00
tui_update_source_windows_with_line (cursal.symtab, line);
gdb/ * source.c (print_source_lines_base): Print for TUI also "fullname". * tui/tui-data.c (init_content_element): Change tui_locator_element field to full_name. * tui/tui-data.h (struct tui_locator_element): Likewise. * tui/tui-disasm.c (tui_show_disassem_and_update_source): Rename tui_update_locator_filename calls to tui_update_locator_fullname. Replace symtab->filename refererence by symtab_to_fullname call. * tui/tui-out.c (tui_field_string): Check for "fullname" now. * tui/tui-source.c (tui_set_source_content): Change tui_locator_element field to full_name. Replace symtab->filename refererence by symtab_to_fullname call. (tui_show_symtab_source): Rename parameter to fullname. Change tui_locator_element field to full_name. * tui/tui-stack.c: Include source.h. (tui_set_locator_filename): Rename the declaration to ... (tui_set_locator_fullname): ... here. Rename its parameter to fullname, updates its comment. (tui_set_locator_info): Rename its parameter to fullname. (tui_set_locator_filename): Rename the definition to ... (tui_set_locator_fullname): ... here. Rename its parameter to fullname, updates its comment. Change tui_locator_element field to full_name. (tui_set_locator_info): Rename its parameter to fullname. (tui_set_locator_info): Rename callee to tui_set_locator_fullname. (tui_update_locator_filename): Rename to ... (tui_update_locator_fullname): ... here. Rename callee to tui_set_locator_fullname. (tui_show_frame_info): Replace symtab->filename refererence by symtab_to_fullname call. * tui/tui-stack.h (tui_update_locator_filename): Rename to ... (tui_update_locator_fullname): ... here. * tui/tui-winsource.c (tui_display_main): Rename the callee to tui_update_locator_fullname. Replace symtab->filename refererence by symtab_to_fullname call. * tui/tui.c (tui_show_source): Rename its parameter to fullname. Rename the callee to tui_update_locator_fullname. * tui/tui.h (tui_show_source): Rename its parameter to fullname.
2013-02-03 17:16:42 +01:00
tui_update_locator_fullname (fullname);
}
void
* disasm.h (gdb_disassembly): Add GDBARCH parameter. (gdb_print_insn): Likewise. * disasm.c (dump_insns): Add GDBARCH parameter. Use it instead of current_gdbarch. (do_mixed_source_and_assembly): Add GDBARCH parameter. Pass to dump_insns. (do_assembly_only): Likewise. (gdb_disassembly): Add GDBARCH parameter. Use it instead of current_gdbarch. Pass to subroutines. (gdb_print_insn): Add GDBARCH parameter. Use it instead of current_gdbarch. * stack.c (struct gdb_disassembly_stub_args): Add GDBARCH member. (gdb_disassembly_stub): Pass architecture to gdb_disassembly. (do_gdb_disassembly): Add GDBARCH argument. Store into args. (print_frame_info): Pass architecture to do_gdb_disassembly. * printcmd.c (print_formatted): Pass architecture to gdb_print_insn. * mi/mi-cmd-disas.c: Include "arch-utils.h" (mi_cmd_disassemble): Pass architecture to gdb_disassembly. * cli/cli-cmds.c: Include "arch-utils.h". (print_disassembly): Add GDBARCH parameter. Pass to gdb_disassembly and tui_show_assembly. (disassemble_current_function): Pass architecture to tui_get_low_disassembly_address and print_disassembly. (disassemble_command): Pass architecture to tui_get_low_disassembly_address and print_disassembly. * tui/tui.c (tui_show_assembly): Add GDBARCH parameter. Pass to tui_update_source_windows_with_addr. * tui/tui-data.h (struct tui_locator_element): Add GDBARCH member. (struct tui_source_info): Likewise. * tui/tui-data.c (tui_clear_win_detail): Clear source_info.gdbarch. * tui/tui-disasm.c (tui_disassemble): Add GDBARCH parameter. Pass to gdb_print_insn. (tui_find_disassembly_address): Add GDBARCH parameter. Pass to tui_disassemble. (tui_set_disassem_content): Add GDBARCH parameter. Install into source_info.gdbarch. Pass to tui_disassemble. (tui_show_disassem): Add GDBARCH parameter. Pass to tui_update_source_window. (tui_show_disassem_and_update_source): Add GDBARCH parameter. Pass to tui_show_disassem and tui_update_source_window. (tui_get_begin_asm_address): Return locator architecture in addition to locator PC value. (tui_get_low_disassembly_address): Add GDBARCH parameter. Pass to tui_get_low_disassembly_address. (tui_vertical_disassem_scroll): Pass architecture to subroutines. * tui/tui-disasm.h (tui_set_disassem_content): Add GDBARCH parameter. (tui_show_disassem): Likewise. (tui_show_disassem_and_update_source): Likewise. (tui_get_begin_asm_address): Return architecture and PC value. * tui/tui.h (tui_get_low_disassembly_address): Add GDBARCH parameter. (tui_show_assembly): Add GDBARCH parameter. * tui/tui-layout.c (extract_display_start_addr): Return current window architecture in addition to current PC value. (tui_set_layout): Update calls to tui_get_low_disassembly_address and extract_display_start_addr. Pass architecture to tui_update_source_windows_with_addr. * tui/tui-source.c: Include "objfiles.h". (tui_set_source_content): Initialize window architecture. (tui_show_symtab_source): Add GDBARCH parameter. Pass to tui_update_source_window_as_is * tui/tui-source.h (tui_show_symtab_source): Add GDBARCH parameter. * tui/tui-stack.c (tui_set_locator_info): Add GDBARCH parameter. Install locator architecture. (tui_set_locator_filename): Update call. (tui_show_frame_info): Pass architecture to tui_set_locator_info and subroutines. * tui/tui-win.c (make_visible_with_new_height): Pass architecture to tui_update_source_window. * tui/tui-winsource.c: Include "objfiles.h". (tui_display_main): Update call to tui_get_begin_asm_address. Pass architecture to tui_update_source_windows_with_addr. (tui_update_source_window): Add GDBARCH parameter. Pass to tui_update_source_window_as_is. (tui_update_source_window_as_is): Add GDBARCH parameter. Pass to tui_set_disassem_content. (tui_update_source_windows_with_addr): Add GDBARCH parameter. Pass to subroutines. (tui_update_source_windows_with_line): Pass objfile architecture to subroutines. (tui_horizontal_source_scroll): Pass architecture to tui_update_source_window_as_is. * tui/tui-winsource.h (tui_update_source_window): Add GDBARCH parameter. (tui_update_source_window_as_is): Likewise. (tui_update_source_windows_with_addr): Likewise.
2009-07-02 19:17:42 +02:00
tui_show_assembly (struct gdbarch *gdbarch, CORE_ADDR addr)
{
tui_add_win_to_layout (DISASSEM_WIN);
* disasm.h (gdb_disassembly): Add GDBARCH parameter. (gdb_print_insn): Likewise. * disasm.c (dump_insns): Add GDBARCH parameter. Use it instead of current_gdbarch. (do_mixed_source_and_assembly): Add GDBARCH parameter. Pass to dump_insns. (do_assembly_only): Likewise. (gdb_disassembly): Add GDBARCH parameter. Use it instead of current_gdbarch. Pass to subroutines. (gdb_print_insn): Add GDBARCH parameter. Use it instead of current_gdbarch. * stack.c (struct gdb_disassembly_stub_args): Add GDBARCH member. (gdb_disassembly_stub): Pass architecture to gdb_disassembly. (do_gdb_disassembly): Add GDBARCH argument. Store into args. (print_frame_info): Pass architecture to do_gdb_disassembly. * printcmd.c (print_formatted): Pass architecture to gdb_print_insn. * mi/mi-cmd-disas.c: Include "arch-utils.h" (mi_cmd_disassemble): Pass architecture to gdb_disassembly. * cli/cli-cmds.c: Include "arch-utils.h". (print_disassembly): Add GDBARCH parameter. Pass to gdb_disassembly and tui_show_assembly. (disassemble_current_function): Pass architecture to tui_get_low_disassembly_address and print_disassembly. (disassemble_command): Pass architecture to tui_get_low_disassembly_address and print_disassembly. * tui/tui.c (tui_show_assembly): Add GDBARCH parameter. Pass to tui_update_source_windows_with_addr. * tui/tui-data.h (struct tui_locator_element): Add GDBARCH member. (struct tui_source_info): Likewise. * tui/tui-data.c (tui_clear_win_detail): Clear source_info.gdbarch. * tui/tui-disasm.c (tui_disassemble): Add GDBARCH parameter. Pass to gdb_print_insn. (tui_find_disassembly_address): Add GDBARCH parameter. Pass to tui_disassemble. (tui_set_disassem_content): Add GDBARCH parameter. Install into source_info.gdbarch. Pass to tui_disassemble. (tui_show_disassem): Add GDBARCH parameter. Pass to tui_update_source_window. (tui_show_disassem_and_update_source): Add GDBARCH parameter. Pass to tui_show_disassem and tui_update_source_window. (tui_get_begin_asm_address): Return locator architecture in addition to locator PC value. (tui_get_low_disassembly_address): Add GDBARCH parameter. Pass to tui_get_low_disassembly_address. (tui_vertical_disassem_scroll): Pass architecture to subroutines. * tui/tui-disasm.h (tui_set_disassem_content): Add GDBARCH parameter. (tui_show_disassem): Likewise. (tui_show_disassem_and_update_source): Likewise. (tui_get_begin_asm_address): Return architecture and PC value. * tui/tui.h (tui_get_low_disassembly_address): Add GDBARCH parameter. (tui_show_assembly): Add GDBARCH parameter. * tui/tui-layout.c (extract_display_start_addr): Return current window architecture in addition to current PC value. (tui_set_layout): Update calls to tui_get_low_disassembly_address and extract_display_start_addr. Pass architecture to tui_update_source_windows_with_addr. * tui/tui-source.c: Include "objfiles.h". (tui_set_source_content): Initialize window architecture. (tui_show_symtab_source): Add GDBARCH parameter. Pass to tui_update_source_window_as_is * tui/tui-source.h (tui_show_symtab_source): Add GDBARCH parameter. * tui/tui-stack.c (tui_set_locator_info): Add GDBARCH parameter. Install locator architecture. (tui_set_locator_filename): Update call. (tui_show_frame_info): Pass architecture to tui_set_locator_info and subroutines. * tui/tui-win.c (make_visible_with_new_height): Pass architecture to tui_update_source_window. * tui/tui-winsource.c: Include "objfiles.h". (tui_display_main): Update call to tui_get_begin_asm_address. Pass architecture to tui_update_source_windows_with_addr. (tui_update_source_window): Add GDBARCH parameter. Pass to tui_update_source_window_as_is. (tui_update_source_window_as_is): Add GDBARCH parameter. Pass to tui_set_disassem_content. (tui_update_source_windows_with_addr): Add GDBARCH parameter. Pass to subroutines. (tui_update_source_windows_with_line): Pass objfile architecture to subroutines. (tui_horizontal_source_scroll): Pass architecture to tui_update_source_window_as_is. * tui/tui-winsource.h (tui_update_source_window): Add GDBARCH parameter. (tui_update_source_window_as_is): Likewise. (tui_update_source_windows_with_addr): Likewise.
2009-07-02 19:17:42 +02:00
tui_update_source_windows_with_addr (gdbarch, addr);
}
int
tui_is_window_visible (enum tui_win_type type)
{
if (tui_active == 0)
return 0;
if (tui_win_list[type] == 0)
return 0;
return tui_win_list[type]->generic.is_visible;
}
int
tui_get_command_dimension (unsigned int *width,
unsigned int *height)
{
if (!tui_active || (TUI_CMD_WIN == NULL))
{
return 0;
}
*width = TUI_CMD_WIN->generic.width;
*height = TUI_CMD_WIN->generic.height;
return 1;
}
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_tui;
void
_initialize_tui (void)
{
struct cmd_list_element **tuicmd;
tuicmd = tui_get_cmd_list ();
add_cmd ("enable", class_tui, tui_enable_command,
_("Enable TUI display mode."),
tuicmd);
add_cmd ("disable", class_tui, tui_disable_command,
_("Disable TUI display mode."),
tuicmd);
}