TUI: don't let exceptions escape while handling readline key bindings
authorPedro Alves <palves@redhat.com>
Wed, 29 Oct 2014 11:58:12 +0000 (11:58 +0000)
committerPedro Alves <palves@redhat.com>
Wed, 29 Oct 2014 14:36:21 +0000 (14:36 +0000)
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.

gdb/ChangeLog
gdb/tui/tui.c

index 676793106721281de6635222b2154d9fb879f945..88c18e07af342315d3ef53a5eb35475069d28e31 100644 (file)
@@ -1,3 +1,8 @@
+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  Joel Brobecker  <brobecker@adacore.com>
 
        * arm-tdep.c (arm_skip_stack_protector): Return early if
index ca66ccd0f4f4249d15d5dba515fdb0e744f790d7..cb85fb02200e6947caf0eed4a0bec96f5ad4ad60 100644 (file)
@@ -90,15 +90,30 @@ static Keymap tui_readline_standard_keymap;
 static int
 tui_rl_switch_mode (int notused1, int notused2)
 {
-  if (tui_active)
+  volatile struct gdb_exception ex;
+
+  /* Don't let exceptions escape.  We're in the middle of a readline
+     callback that isn't prepared for that.  */
+  TRY_CATCH (ex, RETURN_MASK_ALL)
     {
-      tui_disable ();
-      rl_prep_terminal (0);
+      if (tui_active)
+       {
+         tui_disable ();
+         rl_prep_terminal (0);
+       }
+      else
+       {
+         /* If tui_enable throws, we'll re-prep below.  */
+         rl_deprep_terminal ();
+         tui_enable ();
+       }
     }
-  else
+  if (ex.reason < 0)
     {
-      rl_deprep_terminal ();
-      tui_enable ();
+      exception_print (gdb_stderr, ex);
+
+      if (!tui_active)
+       rl_prep_terminal (0);
     }
 
   /* Clear the readline in case switching occurred in middle of