0a75489fab
In some cases tui_show_frame_info() may get called while the inferior's terminal settings are still in effect. But when we call this function we absolutely need to have our terminal settings in effect because the function is responsible for redrawing TUI's windows following a change in the selected frame or a change in the PC. If our terminal settings are not in effect, the screen does not get redrawn properly, causing temporary display artifacts (which can be fixed via ^L). This scenario happens most prominently when stepping through a program in TUI while a watchpoint is in effect. Here is an example backtrace for when tui_show_frame_info() gets called while target_terminal_is_inferior() == 1: #1 0x00000000004988ee in tui_selected_frame_level_changed_hook (level=0) #2 0x0000000000617b99 in select_frame (fi=0x18c9820) #3 0x0000000000617c3f in get_selected_frame (message=message@entry=0x0) #4 0x00000000004ce534 in update_watchpoint (b=b@entry=0x2d9a760, reparse=reparse@entry=0) #5 0x00000000004d625e in insert_breakpoints () #6 0x0000000000531cfe in keep_going (ecs=ecs@entry=0x7ffea7884ac0) #7 0x00000000005326d7 in process_event_stop_test (ecs=ecs@entry=0x7ffea7884ac0) #8 0x000000000053596e in handle_inferior_event_1 (ecs=0x7ffea7884ac0) The fix is simple: call target_terminal_ours_for_output() before calling tui_show_frame_info() in TUI's frame-changed hook, making sure to restore the original terminal settings afterwards. gdb/ChangeLog: * tui/tui-hooks.c (tui_selected_frame_level_changed_hook): Call target_terminal_ours_for_output() before calling tui_show_frame_info(), and restore the original terminal settings afterwards.
254 lines
6.9 KiB
C
254 lines
6.9 KiB
C
/* GDB hooks for TUI.
|
|
|
|
Copyright (C) 2001-2015 Free Software Foundation, Inc.
|
|
|
|
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 "symtab.h"
|
|
#include "inferior.h"
|
|
#include "command.h"
|
|
#include "bfd.h"
|
|
#include "symfile.h"
|
|
#include "objfiles.h"
|
|
#include "target.h"
|
|
#include "gdbcore.h"
|
|
#include "event-loop.h"
|
|
#include "event-top.h"
|
|
#include "frame.h"
|
|
#include "breakpoint.h"
|
|
#include "ui-out.h"
|
|
#include "top.h"
|
|
#include "observer.h"
|
|
#include <unistd.h>
|
|
#include <fcntl.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-win.h"
|
|
#include "tui/tui-stack.h"
|
|
#include "tui/tui-windata.h"
|
|
#include "tui/tui-winsource.h"
|
|
|
|
#include "gdb_curses.h"
|
|
|
|
/* This redefines CTRL if it is not already defined, so it must come
|
|
after terminal state releated include files like <term.h> and
|
|
"gdb_curses.h". */
|
|
#include "readline/readline.h"
|
|
|
|
int tui_target_has_run = 0;
|
|
|
|
static void
|
|
tui_new_objfile_hook (struct objfile* objfile)
|
|
{
|
|
if (tui_active)
|
|
tui_display_main ();
|
|
}
|
|
|
|
/* Prevent recursion of deprecated_register_changed_hook(). */
|
|
static int tui_refreshing_registers = 0;
|
|
|
|
static void
|
|
tui_register_changed_hook (int regno)
|
|
{
|
|
struct frame_info *fi;
|
|
|
|
fi = get_selected_frame (NULL);
|
|
if (tui_refreshing_registers == 0)
|
|
{
|
|
tui_refreshing_registers = 1;
|
|
tui_check_data_values (fi);
|
|
tui_refreshing_registers = 0;
|
|
}
|
|
}
|
|
|
|
/* Breakpoint creation hook.
|
|
Update the screen to show the new breakpoint. */
|
|
static void
|
|
tui_event_create_breakpoint (struct breakpoint *b)
|
|
{
|
|
tui_update_all_breakpoint_info ();
|
|
}
|
|
|
|
/* Breakpoint deletion hook.
|
|
Refresh the screen to update the breakpoint marks. */
|
|
static void
|
|
tui_event_delete_breakpoint (struct breakpoint *b)
|
|
{
|
|
tui_update_all_breakpoint_info ();
|
|
}
|
|
|
|
static void
|
|
tui_event_modify_breakpoint (struct breakpoint *b)
|
|
{
|
|
tui_update_all_breakpoint_info ();
|
|
}
|
|
|
|
/* Called when a command is about to proceed the inferior. */
|
|
|
|
static void
|
|
tui_about_to_proceed (void)
|
|
{
|
|
/* Leave tui mode (optional). */
|
|
#if 0
|
|
if (tui_active)
|
|
{
|
|
target_terminal_ours ();
|
|
endwin ();
|
|
target_terminal_inferior ();
|
|
}
|
|
#endif
|
|
tui_target_has_run = 1;
|
|
}
|
|
|
|
/* The selected frame has changed. This is happens after a target
|
|
stop or when the user explicitly changes the frame
|
|
(up/down/thread/...). */
|
|
static void
|
|
tui_selected_frame_level_changed_hook (int level)
|
|
{
|
|
struct frame_info *fi;
|
|
CORE_ADDR pc;
|
|
struct cleanup *old_chain;
|
|
|
|
/* Negative level means that the selected frame was cleared. */
|
|
if (level < 0)
|
|
return;
|
|
|
|
old_chain = make_cleanup_restore_target_terminal ();
|
|
target_terminal_ours_for_output ();
|
|
|
|
fi = get_selected_frame (NULL);
|
|
/* Ensure that symbols for this frame are read in. Also, determine
|
|
the source language of this frame, and switch to it if
|
|
desired. */
|
|
if (get_frame_pc_if_available (fi, &pc))
|
|
{
|
|
struct symtab *s;
|
|
|
|
s = find_pc_line_symtab (pc);
|
|
/* elz: This if here fixes the problem with the pc not being
|
|
displayed in the tui asm layout, with no debug symbols. The
|
|
value of s would be 0 here, and select_source_symtab would
|
|
abort the command by calling the 'error' function. */
|
|
if (s)
|
|
select_source_symtab (s);
|
|
}
|
|
|
|
/* Display the frame position (even if there is no symbols or the PC
|
|
is not known). */
|
|
tui_show_frame_info (fi);
|
|
|
|
/* Refresh the register window if it's visible. */
|
|
if (tui_is_window_visible (DATA_WIN))
|
|
{
|
|
tui_refreshing_registers = 1;
|
|
tui_check_data_values (fi);
|
|
tui_refreshing_registers = 0;
|
|
}
|
|
|
|
do_cleanups (old_chain);
|
|
}
|
|
|
|
/* Called from print_frame_info to list the line we stopped in. */
|
|
static void
|
|
tui_print_frame_info_listing_hook (struct symtab *s,
|
|
int line,
|
|
int stopline,
|
|
int noerror)
|
|
{
|
|
select_source_symtab (s);
|
|
tui_show_frame_info (get_selected_frame (NULL));
|
|
}
|
|
|
|
/* Perform all necessary cleanups regarding our module's inferior data
|
|
that is required after the inferior INF just exited. */
|
|
|
|
static void
|
|
tui_inferior_exit (struct inferior *inf)
|
|
{
|
|
/* Leave the SingleKey mode to make sure the gdb prompt is visible. */
|
|
tui_set_key_mode (TUI_COMMAND_MODE);
|
|
tui_show_frame_info (0);
|
|
tui_display_main ();
|
|
}
|
|
|
|
/* Observers created when installing TUI hooks. */
|
|
static struct observer *tui_bp_created_observer;
|
|
static struct observer *tui_bp_deleted_observer;
|
|
static struct observer *tui_bp_modified_observer;
|
|
static struct observer *tui_inferior_exit_observer;
|
|
static struct observer *tui_about_to_proceed_observer;
|
|
|
|
/* Install the TUI specific hooks. */
|
|
void
|
|
tui_install_hooks (void)
|
|
{
|
|
deprecated_selected_frame_level_changed_hook
|
|
= tui_selected_frame_level_changed_hook;
|
|
deprecated_print_frame_info_listing_hook
|
|
= tui_print_frame_info_listing_hook;
|
|
|
|
/* Install the event hooks. */
|
|
tui_bp_created_observer
|
|
= observer_attach_breakpoint_created (tui_event_create_breakpoint);
|
|
tui_bp_deleted_observer
|
|
= observer_attach_breakpoint_deleted (tui_event_delete_breakpoint);
|
|
tui_bp_modified_observer
|
|
= observer_attach_breakpoint_modified (tui_event_modify_breakpoint);
|
|
tui_inferior_exit_observer
|
|
= observer_attach_inferior_exit (tui_inferior_exit);
|
|
tui_about_to_proceed_observer
|
|
= observer_attach_about_to_proceed (tui_about_to_proceed);
|
|
|
|
deprecated_register_changed_hook = tui_register_changed_hook;
|
|
}
|
|
|
|
/* Remove the TUI specific hooks. */
|
|
void
|
|
tui_remove_hooks (void)
|
|
{
|
|
deprecated_selected_frame_level_changed_hook = 0;
|
|
deprecated_print_frame_info_listing_hook = 0;
|
|
deprecated_query_hook = 0;
|
|
deprecated_register_changed_hook = 0;
|
|
|
|
/* Remove our observers. */
|
|
observer_detach_breakpoint_created (tui_bp_created_observer);
|
|
tui_bp_created_observer = NULL;
|
|
observer_detach_breakpoint_deleted (tui_bp_deleted_observer);
|
|
tui_bp_deleted_observer = NULL;
|
|
observer_detach_breakpoint_modified (tui_bp_modified_observer);
|
|
tui_bp_modified_observer = NULL;
|
|
observer_detach_inferior_exit (tui_inferior_exit_observer);
|
|
tui_inferior_exit_observer = NULL;
|
|
observer_detach_about_to_proceed (tui_about_to_proceed_observer);
|
|
tui_about_to_proceed_observer = NULL;
|
|
}
|
|
|
|
void _initialize_tui_hooks (void);
|
|
|
|
void
|
|
_initialize_tui_hooks (void)
|
|
{
|
|
/* Install the permanent hooks. */
|
|
observer_attach_new_objfile (tui_new_objfile_hook);
|
|
}
|