mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-21 04:42:53 +08:00
8480a37e14
We currently pass frames to function by value, as `frame_info_ptr`. This is somewhat expensive: - the size of `frame_info_ptr` is 64 bytes, which is a bit big to pass by value - the constructors and destructor link/unlink the object in the global `frame_info_ptr::frame_list` list. This is an `intrusive_list`, so it's not so bad: it's just assigning a few points, there's no memory allocation as if it was `std::list`, but still it's useless to do that over and over. As suggested by Tom Tromey, change many function signatures to accept `const frame_info_ptr &` instead of `frame_info_ptr`. Some functions reassign their `frame_info_ptr` parameter, like: void the_func (frame_info_ptr frame) { for (; frame != nullptr; frame = get_prev_frame (frame)) { ... } } I wondered what to do about them, do I leave them as-is or change them (and need to introduce a separate local variable that can be re-assigned). I opted for the later for consistency. It might not be clear why some functions take `const frame_info_ptr &` while others take `frame_info_ptr`. Also, if a function took a `frame_info_ptr` because it did re-assign its parameter, I doubt that we would think to change it to `const frame_info_ptr &` should the implementation change such that it doesn't need to take `frame_info_ptr` anymore. It seems better to have a simple rule and apply it everywhere. Change-Id: I59d10addef687d157f82ccf4d54f5dde9a963fd0 Approved-By: Andrew Burgess <aburgess@redhat.com>
288 lines
7.6 KiB
C
288 lines
7.6 KiB
C
/* GDB hooks for TUI.
|
|
|
|
Copyright (C) 2001-2024 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 "gdbsupport/event-loop.h"
|
|
#include "event-top.h"
|
|
#include "frame.h"
|
|
#include "breakpoint.h"
|
|
#include "ui-out.h"
|
|
#include "top.h"
|
|
#include "observable.h"
|
|
#include "source.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-status.h"
|
|
#include "tui/tui-winsource.h"
|
|
|
|
#include "gdb_curses.h"
|
|
|
|
static void tui_on_objfiles_changed ()
|
|
{
|
|
if (tui_active)
|
|
tui_display_main ();
|
|
}
|
|
|
|
static void
|
|
tui_new_objfile_hook (struct objfile* objfile)
|
|
{ tui_on_objfiles_changed (); }
|
|
|
|
static void
|
|
tui_all_objfiles_removed (program_space *pspace)
|
|
{ tui_on_objfiles_changed (); }
|
|
|
|
/* Observer for the register_changed notification. */
|
|
|
|
static void
|
|
tui_register_changed (const frame_info_ptr &frame, int regno)
|
|
{
|
|
frame_info_ptr fi;
|
|
|
|
if (!tui_is_window_visible (DATA_WIN))
|
|
return;
|
|
|
|
/* The frame of the register that was changed may differ from the selected
|
|
frame, but we only want to show the register values of the selected frame.
|
|
And even if the frames differ a register change made in one can still show
|
|
up in the other. So we always use the selected frame here, and ignore
|
|
FRAME. */
|
|
fi = get_selected_frame (NULL);
|
|
TUI_DATA_WIN->check_register_values (fi);
|
|
}
|
|
|
|
/* 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 (nullptr);
|
|
}
|
|
|
|
/* 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 (b);
|
|
}
|
|
|
|
static void
|
|
tui_event_modify_breakpoint (struct breakpoint *b)
|
|
{
|
|
tui_update_all_breakpoint_info (nullptr);
|
|
}
|
|
|
|
/* This is set to true if the next window refresh should come from the
|
|
current stack frame. */
|
|
|
|
static bool from_stack;
|
|
|
|
/* This is set to true if the next window refresh should come from the
|
|
current source symtab. */
|
|
|
|
static bool from_source_symtab;
|
|
|
|
/* Refresh TUI's frame and register information. This is a hook intended to be
|
|
used to update the screen after potential frame and register changes. */
|
|
|
|
static void
|
|
tui_refresh_frame_and_register_information ()
|
|
{
|
|
if (!from_stack && !from_source_symtab)
|
|
return;
|
|
|
|
target_terminal::scoped_restore_terminal_state term_state;
|
|
target_terminal::ours_for_output ();
|
|
|
|
if (from_stack)
|
|
{
|
|
frame_info_ptr fi;
|
|
if (has_stack_frames ())
|
|
{
|
|
fi = get_selected_frame (NULL);
|
|
|
|
/* 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_DATA_WIN->check_register_values (fi);
|
|
}
|
|
else
|
|
{
|
|
/* Make sure that the source window is displayed. */
|
|
tui_add_win_to_layout (SRC_WIN);
|
|
|
|
struct symtab_and_line sal = get_current_source_symtab_and_line ();
|
|
tui_update_source_windows_with_line (sal);
|
|
}
|
|
}
|
|
|
|
/* Dummy callback for deprecated_print_frame_info_listing_hook which is called
|
|
from print_frame_info. */
|
|
|
|
static void
|
|
tui_dummy_print_frame_info_listing_hook (struct symtab *s,
|
|
int line,
|
|
int stopline,
|
|
int noerror)
|
|
{
|
|
}
|
|
|
|
/* 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 ();
|
|
from_stack = true;
|
|
}
|
|
|
|
/* Observer for the before_prompt notification. */
|
|
|
|
static void
|
|
tui_before_prompt (const char *current_gdb_prompt)
|
|
{
|
|
tui_refresh_frame_and_register_information ();
|
|
from_stack = false;
|
|
from_source_symtab = false;
|
|
}
|
|
|
|
/* Observer for the normal_stop notification. */
|
|
|
|
static void
|
|
tui_normal_stop (struct bpstat *bs, int print_frame)
|
|
{
|
|
from_stack = true;
|
|
}
|
|
|
|
/* Observer for user_selected_context_changed. */
|
|
|
|
static void
|
|
tui_context_changed (user_selected_what ignore)
|
|
{
|
|
from_stack = true;
|
|
}
|
|
|
|
/* Observer for current_source_symtab_and_line_changed. */
|
|
|
|
static void
|
|
tui_symtab_changed ()
|
|
{
|
|
from_source_symtab = true;
|
|
}
|
|
|
|
/* Token associated with observers registered while TUI hooks are
|
|
installed. */
|
|
static const gdb::observers::token tui_observers_token {};
|
|
|
|
/* Attach or detach a single observer, according to ATTACH. */
|
|
|
|
template<typename T>
|
|
static void
|
|
attach_or_detach (T &observable, typename T::func_type func, bool attach)
|
|
{
|
|
if (attach)
|
|
observable.attach (func, tui_observers_token, "tui-hooks");
|
|
else
|
|
observable.detach (tui_observers_token);
|
|
}
|
|
|
|
/* Attach or detach TUI observers, according to ATTACH. */
|
|
|
|
static void
|
|
tui_attach_detach_observers (bool attach)
|
|
{
|
|
attach_or_detach (gdb::observers::breakpoint_created,
|
|
tui_event_create_breakpoint, attach);
|
|
attach_or_detach (gdb::observers::breakpoint_deleted,
|
|
tui_event_delete_breakpoint, attach);
|
|
attach_or_detach (gdb::observers::breakpoint_modified,
|
|
tui_event_modify_breakpoint, attach);
|
|
attach_or_detach (gdb::observers::inferior_exit,
|
|
tui_inferior_exit, attach);
|
|
attach_or_detach (gdb::observers::before_prompt,
|
|
tui_before_prompt, attach);
|
|
attach_or_detach (gdb::observers::normal_stop,
|
|
tui_normal_stop, attach);
|
|
attach_or_detach (gdb::observers::register_changed,
|
|
tui_register_changed, attach);
|
|
attach_or_detach (gdb::observers::user_selected_context_changed,
|
|
tui_context_changed, attach);
|
|
attach_or_detach (gdb::observers::current_source_symtab_and_line_changed,
|
|
tui_symtab_changed, attach);
|
|
}
|
|
|
|
/* Install the TUI specific hooks. */
|
|
void
|
|
tui_install_hooks (void)
|
|
{
|
|
/* If this hook is not set to something then print_frame_info will
|
|
assume that the CLI, not the TUI, is active, and will print the frame info
|
|
for us in such a way that we are not prepared to handle. This hook is
|
|
otherwise effectively obsolete. */
|
|
deprecated_print_frame_info_listing_hook
|
|
= tui_dummy_print_frame_info_listing_hook;
|
|
|
|
/* Install the event hooks. */
|
|
tui_attach_detach_observers (true);
|
|
}
|
|
|
|
/* Remove the TUI specific hooks. */
|
|
void
|
|
tui_remove_hooks (void)
|
|
{
|
|
deprecated_print_frame_info_listing_hook = 0;
|
|
|
|
/* Remove our observers. */
|
|
tui_attach_detach_observers (false);
|
|
}
|
|
|
|
void _initialize_tui_hooks ();
|
|
void
|
|
_initialize_tui_hooks ()
|
|
{
|
|
/* Install the permanent hooks. */
|
|
gdb::observers::new_objfile.attach (tui_new_objfile_hook, "tui-hooks");
|
|
gdb::observers::all_objfiles_removed.attach (tui_all_objfiles_removed,
|
|
"tui-hooks");
|
|
}
|