mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
eb3ff9a551
This patch reworks the whole completion machinery, and prepares it for later enhancements. Adds a new "completion_tracker" class that is meant to hold everything about the state of the current completion operation. This class now has the responsibility of tracking the list of completion matches, and checking whether the max completions limit has been reached. You can look at this as this patch starting out by C++fying the existing "completion_tracker" in symtab.c (it's just an htab_t typedef currently), moving it to completer.h/c, and then making it a class/generalizing/enhancing it. Unlike with the current tracking, completion_tracker now checks whether the limit has been reached on each completion match list insertion. This both simplifies the max-completions handling code (maybe_add_completion_enum is gone, for example), and is a prerequisite for follow up patches. The current completion_tracker is only used for symbol completions, and the symbol code gets at the current instance via globals. This patch cleans that up by adding a completion_tracker reference to the signature of the completion functions, and passing the tracker around everywhere necessary. Then, the patch changes how the completion match list is handed over to readline. Currently, we're using the rl_completion_entry_function readline entry point, and the patch switches to rl_attempted_completion_function. A following patch will want to let GDB itself decide the common completion prefix between all matches (what readline calls the "lowest common denominator"), instead of having readline compute it, and that's not possible with the rl_completion_entry_function entry point. Also, rl_attempted_completion_function lets GDB hand over the match list to readline as an array in one go instead of passing down matches one by one, so from that angle it's a nicer entry point anyway. Lastly, the patch catches exceptions around the readline entry points, because we can't let C++ exceptions cross readline. We handle that in the readline input entry point, but the completion entry point isn't guarded, so GDB can abort if completion throws. E.g., in current master: (gdb) b -function "fun<tab> terminate called after throwing an instance of 'gdb_exception_RETURN_MASK_ERROR' Aborted (core dumped) This patch fixes that. This will be exercised in the new tests added later on in the series. gdb/ChangeLog: 2017-07-17 Pedro Alves <palves@redhat.com> * ada-lang.c (symbol_completion_match): Adjust comments. (symbol_completion_add): Replace vector parameter with completion_tracker parameter. Use it. (ada_make_symbol_completion_list): Rename to... (ada_collect_symbol_completion_matches): ... this. Add completion_tracker parameter and use it. (ada_language_defn): Adjust. * break-catch-syscall.c (catch_syscall_completer): Adjust prototype and work with completion_tracker instead of VEC. * breakpoint.c (condition_completer): Adjust prototype and work with completion_tracker instead of VEC. * c-lang.c (c_language_defn, cplus_language_defn) (asm_language_defn, minimal_language_defn): Adjust to renames. * cli/cli-cmds.c (complete_command): Rework using completion_tracker. Catch exceptions when completing. * cli/cli-decode.c (integer_unlimited_completer) (complete_on_cmdlist, complete_on_enum): Adjust prototype and work with completion_tracker instead of VEC. * command.h (struct completion_tracker): Forward declare. (completer_ftype, completer_handle_brkchars_ftype): Change types. (complete_on_cmdlist, complete_on_enum): Adjust. * completer.c: Include <algorithm>. (struct gdb_completer_state): New. (current_completion): New global. (readline_line_completion_function): Delete. (noop_completer, filename_completer) (filename_completer_handle_brkchars, complete_files_symbols) (linespec_location_completer): Adjust to work with a completion_tracker instead of a VEC. (string_or_empty): New. (collect_explicit_location_matches): Adjust to work with a completion_tracker instead of a VEC. (explicit_location_completer): Rename to ... (complete_explicit_location): ... this and adjust to work with a completion_tracker instead of a VEC. (location_completer): Adjust to work with a completion_tracker instead of a VEC. (add_struct_fields): Adjust to work with a completion_list instead of VEC. (expression_completer): Rename to ... (complete_expression): ... this and adjust to work with a completion_tracker instead of a VEC. Use complete_files_symbols. (expression_completer): Reimplement on top of complete_expression. (symbol_completer): Adjust to work with a completion_tracker instead of a VEC. (enum complete_line_internal_reason): Add describing comments. (complete_line_internal_normal_command): Adjust to work with a completion_tracker instead of a VEC. (complete_line_internal): Rename to ... (complete_line_internal_1): ... this and adjust to work with a completion_tracker instead of a VEC. Assert TEXT is NULL in the handle_brkchars phase. (new_completion_tracker): Delete. (complete_line_internal): Reimplement as TRY/CATCH wrapper around complete_line_internal_1. (free_completion_tracker): Delete. (INITIAL_COMPLETION_HTAB_SIZE): New. (completion_tracker::completion_tracker) (completion_tracker::~completion_tracker): New. (maybe_add_completion): Delete. (completion_tracker::maybe_add_completion) (completion_tracker::add_completion) (completion_tracker::add_completions): New. (throw_max_completions_reached_error): Delete. (complete_line): Adjust to work with a completion_tracker instead of a VEC. Don't create a completion_tracker_t or check for max completions here. (command_completer, command_completer_handle_brkchars) (signal_completer, reg_or_group_completer_1) (reg_or_group_completer, default_completer_handle_brkchars): Adjust to work with a completion_tracker. (gdb_completion_word_break_characters_throw): New. (gdb_completion_word_break_characters): Reimplement. (line_completion_function): Delete. (completion_tracker::recompute_lowest_common_denominator) (expand_preserving_ws) (completion_tracker::build_completion_result) (completion_result::completion_result) (completion_result::completion_result) (completion_result::~completion_result) (completion_result::completion_result) (completion_result::release_match_list, compare_cstrings) (completion_result::sort_match_list) (completion_result::reset_match_list) (gdb_rl_attempted_completion_function_throw) (gdb_rl_attempted_completion_function): New. * completer.h (completion_list, struct completion_result) (class completion_tracker): New. (complete_line): Add completion_tracker parameter. (readline_line_completion_function): Delete. (gdb_rl_attempted_completion_function): New. (noop_completer, filename_completer, expression_completer) (location_completer, symbol_completer, command_completer) (signal_completer, reg_or_group_completer): Update prototypes. (completion_tracker_t, new_completion_tracker) (make_cleanup_free_completion_tracker): Delete. (enum maybe_add_completion_enum): Delete. (maybe_add_completion): Delete. (throw_max_completions_reached_error): Delete. * corefile.c (complete_set_gnutarget): Adjust to work with a completion_tracker instead of a VEC. * cp-abi.c (cp_abi_completer): Adjust to work with a completion_tracker instead of a VEC. * d-lang.c (d_language_defn): Adjust. * disasm.c (disassembler_options_completer): Adjust to work with a completion_tracker instead of a VEC. * f-lang.c (f_make_symbol_completion_list): Rename to ... (f_collect_symbol_completion_matches): ... this. Adjust to work with a completion_tracker instead of a VEC. (f_language_defn): Adjust. * go-lang.c (go_language_defn): Adjust. * guile/scm-cmd.c (cmdscm_add_completion, cmdscm_completer): Adjust to work with a completion_tracker instead of a VEC. * infrun.c (handle_completer): Likewise. * interps.c (interpreter_completer): Likewise. * interps.h (interpreter_completer): Likewise. * language.c (unknown_language_defn, auto_language_defn) (local_language_defn): Adjust. * language.h (language_defn::la_make_symbol_completion_list): Rename to ... (language_defn::la_collect_symbol_completion_matches): ... this and adjust to work with a completion_tracker instead of a VEC. * m2-lang.c (m2_language_defn): Adjust. * objc-lang.c (objc_language_defn): Adjust. * opencl-lang.c (opencl_language_defn): Adjust. * p-lang.c (pascal_language_defn): Adjust. * python/py-cmd.c (cmdpy_completer_helper): Handle NULL word. (cmdpy_completer_handle_brkchars, cmdpy_completer): Adjust to work with a completion_tracker. * rust-lang.c (rust_language_defn): Adjust. * symtab.c (free_completion_list, do_free_completion_list) (return_val, completion_tracker): Delete. (completion_list_add_name, completion_list_add_symbol) (completion_list_add_msymbol, completion_list_objc_symbol) (completion_list_add_fields, add_symtab_completions): Add completion_tracker parameter and use it. (default_make_symbol_completion_list_break_on_1): Rename to... (default_collect_symbol_completion_matches_break_on): ... this. Add completion_tracker parameter and use it instead of allocating a completion tracker here. (default_make_symbol_completion_list_break_on): Delete old implementation. (default_make_symbol_completion_list): Delete. (default_collect_symbol_completion_matches): New. (make_symbol_completion_list): Delete. (collect_symbol_completion_matches): New. (make_symbol_completion_type): Rename to ... (collect_symbol_completion_matches_type): ... this. Add completion_tracker parameter and use it instead of VEC. (make_file_symbol_completion_list_1): Rename to... (collect_file_symbol_completion_matches): ... this. Add completion_tracker parameter and use it instead of VEC. (make_file_symbol_completion_list): Delete. (add_filename_to_list): Use completion_list instead of a VEC. (add_partial_filename_data::list): Now a completion_list. (make_source_files_completion_list): Work with a completion_list instead of a VEC. * symtab.h: Include "completer.h". (default_make_symbol_completion_list_break_on) (default_make_symbol_completion_list, make_symbol_completion_list) (make_symbol_completion_type, make_file_symbol_completion_list) (make_source_files_completion_list): Delete. (default_collect_symbol_completion_matches_break_on) (default_collect_symbol_completion_matches) (collect_symbol_completion_matches) (collect_symbol_completion_matches_type) (collect_file_symbol_completion_matches) (make_source_files_completion_list): New. * top.c (init_main): Don't install a rl_completion_entry_function hook. Install a rl_attempted_completion_function hook instead. * tui/tui-layout.c (layout_completer): Adjust to work with a completion_tracker. * tui/tui-regs.c (tui_reggroup_completer): * tui/tui-win.c (window_name_completer, focus_completer) (winheight_completer): Adjust to work with a completion_tracker. * value.c: Include "completer.h". (complete_internalvar): Adjust to work with a completion_tracker. * value.h (complete_internalvar): Likewise.
994 lines
26 KiB
C
994 lines
26 KiB
C
/* TUI layout window management.
|
|
|
|
Copyright (C) 1998-2017 Free Software Foundation, Inc.
|
|
|
|
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 "arch-utils.h"
|
|
#include "command.h"
|
|
#include "symtab.h"
|
|
#include "frame.h"
|
|
#include "source.h"
|
|
#include <ctype.h>
|
|
|
|
#include "tui/tui.h"
|
|
#include "tui/tui-data.h"
|
|
#include "tui/tui-windata.h"
|
|
#include "tui/tui-wingeneral.h"
|
|
#include "tui/tui-stack.h"
|
|
#include "tui/tui-regs.h"
|
|
#include "tui/tui-win.h"
|
|
#include "tui/tui-winsource.h"
|
|
#include "tui/tui-disasm.h"
|
|
#include "tui/tui-layout.h"
|
|
#include "gdb_curses.h"
|
|
|
|
/*******************************
|
|
** Static Local Decls
|
|
********************************/
|
|
static void show_layout (enum tui_layout_type);
|
|
static void init_gen_win_info (struct tui_gen_win_info *,
|
|
enum tui_win_type,
|
|
int, int, int, int);
|
|
static void *init_and_make_win (void *, enum tui_win_type,
|
|
int, int, int, int, int);
|
|
static void show_source_or_disasm_and_command (enum tui_layout_type);
|
|
static void make_source_or_disasm_window (struct tui_win_info **,
|
|
enum tui_win_type,
|
|
int, int);
|
|
static void make_command_window (struct tui_win_info **, int, int);
|
|
static void make_source_window (struct tui_win_info **, int, int);
|
|
static void make_disasm_window (struct tui_win_info **, int, int);
|
|
static void make_data_window (struct tui_win_info **, int, int);
|
|
static void show_source_command (void);
|
|
static void show_disasm_command (void);
|
|
static void show_source_disasm_command (void);
|
|
static void show_data (enum tui_layout_type);
|
|
static enum tui_layout_type next_layout (void);
|
|
static enum tui_layout_type prev_layout (void);
|
|
static void tui_layout_command (char *, int);
|
|
static void extract_display_start_addr (struct gdbarch **, CORE_ADDR *);
|
|
|
|
|
|
/***************************************
|
|
** DEFINITIONS
|
|
***************************************/
|
|
|
|
#define LAYOUT_USAGE "Usage: layout prev | next | <layout_name> \n"
|
|
|
|
/* Show the screen layout defined. */
|
|
static void
|
|
show_layout (enum tui_layout_type layout)
|
|
{
|
|
enum tui_layout_type cur_layout = tui_current_layout ();
|
|
|
|
if (layout != cur_layout)
|
|
{
|
|
/* Since the new layout may cause changes in window size, we
|
|
should free the content and reallocate on next display of
|
|
source/asm. */
|
|
tui_free_all_source_wins_content ();
|
|
tui_clear_source_windows ();
|
|
if (layout == SRC_DATA_COMMAND
|
|
|| layout == DISASSEM_DATA_COMMAND)
|
|
{
|
|
show_data (layout);
|
|
tui_refresh_all (tui_win_list);
|
|
}
|
|
else
|
|
{
|
|
/* First make the current layout be invisible. */
|
|
tui_make_all_invisible ();
|
|
tui_make_invisible (tui_locator_win_info_ptr ());
|
|
|
|
switch (layout)
|
|
{
|
|
/* Now show the new layout. */
|
|
case SRC_COMMAND:
|
|
show_source_command ();
|
|
tui_add_to_source_windows (TUI_SRC_WIN);
|
|
break;
|
|
case DISASSEM_COMMAND:
|
|
show_disasm_command ();
|
|
tui_add_to_source_windows (TUI_DISASM_WIN);
|
|
break;
|
|
case SRC_DISASSEM_COMMAND:
|
|
show_source_disasm_command ();
|
|
tui_add_to_source_windows (TUI_SRC_WIN);
|
|
tui_add_to_source_windows (TUI_DISASM_WIN);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
|
|
SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND. */
|
|
enum tui_status
|
|
tui_set_layout (enum tui_layout_type layout_type)
|
|
{
|
|
enum tui_status status = TUI_SUCCESS;
|
|
|
|
if (layout_type != UNDEFINED_LAYOUT)
|
|
{
|
|
enum tui_layout_type cur_layout = tui_current_layout (),
|
|
new_layout = UNDEFINED_LAYOUT;
|
|
int regs_populate = FALSE;
|
|
struct gdbarch *gdbarch;
|
|
CORE_ADDR addr;
|
|
struct tui_win_info *win_with_focus = tui_win_with_focus ();
|
|
struct tui_layout_def *layout_def = tui_layout_def ();
|
|
|
|
extract_display_start_addr (&gdbarch, &addr);
|
|
|
|
new_layout = layout_type;
|
|
|
|
regs_populate = (new_layout == SRC_DATA_COMMAND
|
|
|| new_layout == DISASSEM_DATA_COMMAND);
|
|
if (new_layout != cur_layout)
|
|
{
|
|
show_layout (new_layout);
|
|
|
|
/* Now determine where focus should be. */
|
|
if (win_with_focus != TUI_CMD_WIN)
|
|
{
|
|
switch (new_layout)
|
|
{
|
|
case SRC_COMMAND:
|
|
tui_set_win_focus_to (TUI_SRC_WIN);
|
|
layout_def->display_mode = SRC_WIN;
|
|
layout_def->split = FALSE;
|
|
break;
|
|
case DISASSEM_COMMAND:
|
|
/* The previous layout was not showing code.
|
|
This can happen if there is no source
|
|
available:
|
|
|
|
1. if the source file is in another dir OR
|
|
2. if target was compiled without -g
|
|
We still want to show the assembly though! */
|
|
|
|
tui_get_begin_asm_address (&gdbarch, &addr);
|
|
tui_set_win_focus_to (TUI_DISASM_WIN);
|
|
layout_def->display_mode = DISASSEM_WIN;
|
|
layout_def->split = FALSE;
|
|
break;
|
|
case SRC_DISASSEM_COMMAND:
|
|
/* The previous layout was not showing code.
|
|
This can happen if there is no source
|
|
available:
|
|
|
|
1. if the source file is in another dir OR
|
|
2. if target was compiled without -g
|
|
We still want to show the assembly though! */
|
|
|
|
tui_get_begin_asm_address (&gdbarch, &addr);
|
|
if (win_with_focus == TUI_SRC_WIN)
|
|
tui_set_win_focus_to (TUI_SRC_WIN);
|
|
else
|
|
tui_set_win_focus_to (TUI_DISASM_WIN);
|
|
layout_def->split = TRUE;
|
|
break;
|
|
case SRC_DATA_COMMAND:
|
|
if (win_with_focus != TUI_DATA_WIN)
|
|
tui_set_win_focus_to (TUI_SRC_WIN);
|
|
else
|
|
tui_set_win_focus_to (TUI_DATA_WIN);
|
|
layout_def->display_mode = SRC_WIN;
|
|
layout_def->split = FALSE;
|
|
break;
|
|
case DISASSEM_DATA_COMMAND:
|
|
/* The previous layout was not showing code.
|
|
This can happen if there is no source
|
|
available:
|
|
|
|
1. if the source file is in another dir OR
|
|
2. if target was compiled without -g
|
|
We still want to show the assembly though! */
|
|
|
|
tui_get_begin_asm_address (&gdbarch, &addr);
|
|
if (win_with_focus != TUI_DATA_WIN)
|
|
tui_set_win_focus_to (TUI_DISASM_WIN);
|
|
else
|
|
tui_set_win_focus_to (TUI_DATA_WIN);
|
|
layout_def->display_mode = DISASSEM_WIN;
|
|
layout_def->split = FALSE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* Now update the window content.
|
|
*/
|
|
if (!regs_populate
|
|
&& (new_layout == SRC_DATA_COMMAND
|
|
|| new_layout == DISASSEM_DATA_COMMAND))
|
|
tui_display_all_data ();
|
|
|
|
tui_update_source_windows_with_addr (gdbarch, addr);
|
|
|
|
if (regs_populate)
|
|
{
|
|
struct reggroup *group =
|
|
TUI_DATA_WIN->detail.data_display_info.current_group;
|
|
tui_show_registers (group);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
status = TUI_FAILURE;
|
|
|
|
return status;
|
|
}
|
|
|
|
/* Add the specified window to the layout in a logical way. This
|
|
means setting up the most logical layout given the window to be
|
|
added. */
|
|
void
|
|
tui_add_win_to_layout (enum tui_win_type type)
|
|
{
|
|
enum tui_layout_type cur_layout = tui_current_layout ();
|
|
|
|
switch (type)
|
|
{
|
|
case SRC_WIN:
|
|
if (cur_layout != SRC_COMMAND
|
|
&& cur_layout != SRC_DISASSEM_COMMAND
|
|
&& cur_layout != SRC_DATA_COMMAND)
|
|
{
|
|
tui_clear_source_windows_detail ();
|
|
if (cur_layout == DISASSEM_DATA_COMMAND)
|
|
show_layout (SRC_DATA_COMMAND);
|
|
else
|
|
show_layout (SRC_COMMAND);
|
|
}
|
|
break;
|
|
case DISASSEM_WIN:
|
|
if (cur_layout != DISASSEM_COMMAND
|
|
&& cur_layout != SRC_DISASSEM_COMMAND
|
|
&& cur_layout != DISASSEM_DATA_COMMAND)
|
|
{
|
|
tui_clear_source_windows_detail ();
|
|
if (cur_layout == SRC_DATA_COMMAND)
|
|
show_layout (DISASSEM_DATA_COMMAND);
|
|
else
|
|
show_layout (DISASSEM_COMMAND);
|
|
}
|
|
break;
|
|
case DATA_WIN:
|
|
if (cur_layout != SRC_DATA_COMMAND
|
|
&& cur_layout != DISASSEM_DATA_COMMAND)
|
|
{
|
|
if (cur_layout == DISASSEM_COMMAND)
|
|
show_layout (DISASSEM_DATA_COMMAND);
|
|
else
|
|
show_layout (SRC_DATA_COMMAND);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* Answer the height of a window. If it hasn't been created yet,
|
|
answer what the height of a window would be based upon its type and
|
|
the layout. */
|
|
int
|
|
tui_default_win_height (enum tui_win_type type,
|
|
enum tui_layout_type layout)
|
|
{
|
|
int h;
|
|
|
|
if (tui_win_list[type] != (struct tui_win_info *) NULL)
|
|
h = tui_win_list[type]->generic.height;
|
|
else
|
|
{
|
|
switch (layout)
|
|
{
|
|
case SRC_COMMAND:
|
|
case DISASSEM_COMMAND:
|
|
if (TUI_CMD_WIN == NULL)
|
|
h = tui_term_height () / 2;
|
|
else
|
|
h = tui_term_height () - TUI_CMD_WIN->generic.height;
|
|
break;
|
|
case SRC_DISASSEM_COMMAND:
|
|
case SRC_DATA_COMMAND:
|
|
case DISASSEM_DATA_COMMAND:
|
|
if (TUI_CMD_WIN == NULL)
|
|
h = tui_term_height () / 3;
|
|
else
|
|
h = (tui_term_height () - TUI_CMD_WIN->generic.height) / 2;
|
|
break;
|
|
default:
|
|
h = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return h;
|
|
}
|
|
|
|
|
|
/* Answer the height of a window. If it hasn't been created yet,
|
|
answer what the height of a window would be based upon its type and
|
|
the layout. */
|
|
int
|
|
tui_default_win_viewport_height (enum tui_win_type type,
|
|
enum tui_layout_type layout)
|
|
{
|
|
int h;
|
|
|
|
h = tui_default_win_height (type, layout);
|
|
|
|
if (tui_win_list[type] == TUI_CMD_WIN)
|
|
h -= 1;
|
|
else
|
|
h -= 2;
|
|
|
|
return h;
|
|
}
|
|
|
|
/* Complete possible layout names. TEXT is the complete text entered so
|
|
far, WORD is the word currently being completed. */
|
|
|
|
static void
|
|
layout_completer (struct cmd_list_element *ignore,
|
|
completion_tracker &tracker,
|
|
const char *text, const char *word)
|
|
{
|
|
static const char *layout_names [] =
|
|
{ "src", "asm", "split", "regs", "next", "prev", NULL };
|
|
|
|
complete_on_enum (tracker, layout_names, text, word);
|
|
}
|
|
|
|
/* Function to initialize gdb commands, for tui window layout
|
|
manipulation. */
|
|
|
|
/* Provide a prototype to silence -Wmissing-prototypes. */
|
|
extern initialize_file_ftype _initialize_tui_layout;
|
|
|
|
void
|
|
_initialize_tui_layout (void)
|
|
{
|
|
struct cmd_list_element *cmd;
|
|
|
|
cmd = add_com ("layout", class_tui, tui_layout_command, _("\
|
|
Change the layout of windows.\n\
|
|
Usage: layout prev | next | <layout_name> \n\
|
|
Layout names are:\n\
|
|
src : Displays source and command windows.\n\
|
|
asm : Displays disassembly and command windows.\n\
|
|
split : Displays source, disassembly and command windows.\n\
|
|
regs : Displays register window. If existing layout\n\
|
|
is source/command or assembly/command, the \n\
|
|
register window is displayed. If the\n\
|
|
source/assembly/command (split) is displayed, \n\
|
|
the register window is displayed with \n\
|
|
the window that has current logical focus.\n"));
|
|
set_cmd_completer (cmd, layout_completer);
|
|
}
|
|
|
|
|
|
/*************************
|
|
** STATIC LOCAL FUNCTIONS
|
|
**************************/
|
|
|
|
|
|
/* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, or
|
|
REGS. */
|
|
enum tui_status
|
|
tui_set_layout_by_name (const char *layout_name)
|
|
{
|
|
enum tui_status status = TUI_SUCCESS;
|
|
|
|
if (layout_name != (char *) NULL)
|
|
{
|
|
int i;
|
|
char *buf_ptr;
|
|
enum tui_layout_type new_layout = UNDEFINED_LAYOUT;
|
|
enum tui_layout_type cur_layout = tui_current_layout ();
|
|
struct cleanup *old_chain;
|
|
|
|
buf_ptr = (char *) xstrdup (layout_name);
|
|
for (i = 0; (i < strlen (layout_name)); i++)
|
|
buf_ptr[i] = toupper (buf_ptr[i]);
|
|
old_chain = make_cleanup (xfree, buf_ptr);
|
|
|
|
/* First check for ambiguous input. */
|
|
if (strlen (buf_ptr) <= 1 && *buf_ptr == 'S')
|
|
{
|
|
warning (_("Ambiguous command input."));
|
|
status = TUI_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
if (subset_compare (buf_ptr, "SRC"))
|
|
new_layout = SRC_COMMAND;
|
|
else if (subset_compare (buf_ptr, "ASM"))
|
|
new_layout = DISASSEM_COMMAND;
|
|
else if (subset_compare (buf_ptr, "SPLIT"))
|
|
new_layout = SRC_DISASSEM_COMMAND;
|
|
else if (subset_compare (buf_ptr, "REGS"))
|
|
{
|
|
if (cur_layout == SRC_COMMAND
|
|
|| cur_layout == SRC_DATA_COMMAND)
|
|
new_layout = SRC_DATA_COMMAND;
|
|
else
|
|
new_layout = DISASSEM_DATA_COMMAND;
|
|
}
|
|
else if (subset_compare (buf_ptr, "NEXT"))
|
|
new_layout = next_layout ();
|
|
else if (subset_compare (buf_ptr, "PREV"))
|
|
new_layout = prev_layout ();
|
|
else
|
|
status = TUI_FAILURE;
|
|
|
|
if (status == TUI_SUCCESS)
|
|
{
|
|
/* Make sure the curses mode is enabled. */
|
|
tui_enable ();
|
|
tui_set_layout (new_layout);
|
|
}
|
|
}
|
|
do_cleanups (old_chain);
|
|
}
|
|
else
|
|
status = TUI_FAILURE;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
static void
|
|
extract_display_start_addr (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
|
|
{
|
|
enum tui_layout_type cur_layout = tui_current_layout ();
|
|
struct gdbarch *gdbarch = get_current_arch ();
|
|
CORE_ADDR addr;
|
|
CORE_ADDR pc;
|
|
struct symtab_and_line cursal = get_current_source_symtab_and_line ();
|
|
|
|
switch (cur_layout)
|
|
{
|
|
case SRC_COMMAND:
|
|
case SRC_DATA_COMMAND:
|
|
gdbarch = TUI_SRC_WIN->detail.source_info.gdbarch;
|
|
find_line_pc (cursal.symtab,
|
|
TUI_SRC_WIN->detail.source_info.start_line_or_addr.u.line_no,
|
|
&pc);
|
|
addr = pc;
|
|
break;
|
|
case DISASSEM_COMMAND:
|
|
case SRC_DISASSEM_COMMAND:
|
|
case DISASSEM_DATA_COMMAND:
|
|
gdbarch = TUI_DISASM_WIN->detail.source_info.gdbarch;
|
|
addr = TUI_DISASM_WIN->detail.source_info.start_line_or_addr.u.addr;
|
|
break;
|
|
default:
|
|
addr = 0;
|
|
break;
|
|
}
|
|
|
|
*gdbarch_p = gdbarch;
|
|
*addr_p = addr;
|
|
}
|
|
|
|
|
|
static void
|
|
tui_layout_command (char *arg, int from_tty)
|
|
{
|
|
/* Switch to the selected layout. */
|
|
if (tui_set_layout_by_name (arg) != TUI_SUCCESS)
|
|
warning (_("Invalid layout specified.\n%s"), LAYOUT_USAGE);
|
|
|
|
}
|
|
|
|
/* Answer the previous layout to cycle to. */
|
|
static enum tui_layout_type
|
|
next_layout (void)
|
|
{
|
|
int new_layout;
|
|
|
|
new_layout = tui_current_layout ();
|
|
if (new_layout == UNDEFINED_LAYOUT)
|
|
new_layout = SRC_COMMAND;
|
|
else
|
|
{
|
|
new_layout++;
|
|
if (new_layout == UNDEFINED_LAYOUT)
|
|
new_layout = SRC_COMMAND;
|
|
}
|
|
|
|
return (enum tui_layout_type) new_layout;
|
|
}
|
|
|
|
|
|
/* Answer the next layout to cycle to. */
|
|
static enum tui_layout_type
|
|
prev_layout (void)
|
|
{
|
|
int new_layout;
|
|
|
|
new_layout = tui_current_layout ();
|
|
if (new_layout == SRC_COMMAND)
|
|
new_layout = DISASSEM_DATA_COMMAND;
|
|
else
|
|
{
|
|
new_layout--;
|
|
if (new_layout == UNDEFINED_LAYOUT)
|
|
new_layout = DISASSEM_DATA_COMMAND;
|
|
}
|
|
|
|
return (enum tui_layout_type) new_layout;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
make_command_window (struct tui_win_info **win_info_ptr,
|
|
int height, int origin_y)
|
|
{
|
|
*win_info_ptr
|
|
= (struct tui_win_info *) init_and_make_win (*win_info_ptr,
|
|
CMD_WIN,
|
|
height,
|
|
tui_term_width (),
|
|
0,
|
|
origin_y,
|
|
DONT_BOX_WINDOW);
|
|
|
|
(*win_info_ptr)->can_highlight = FALSE;
|
|
}
|
|
|
|
|
|
/* make_source_window().
|
|
*/
|
|
static void
|
|
make_source_window (struct tui_win_info **win_info_ptr,
|
|
int height, int origin_y)
|
|
{
|
|
make_source_or_disasm_window (win_info_ptr, SRC_WIN, height, origin_y);
|
|
|
|
return;
|
|
} /* make_source_window */
|
|
|
|
|
|
/* make_disasm_window().
|
|
*/
|
|
static void
|
|
make_disasm_window (struct tui_win_info **win_info_ptr,
|
|
int height, int origin_y)
|
|
{
|
|
make_source_or_disasm_window (win_info_ptr, DISASSEM_WIN, height, origin_y);
|
|
|
|
return;
|
|
} /* make_disasm_window */
|
|
|
|
|
|
static void
|
|
make_data_window (struct tui_win_info **win_info_ptr,
|
|
int height, int origin_y)
|
|
{
|
|
*win_info_ptr
|
|
= (struct tui_win_info *) init_and_make_win (*win_info_ptr,
|
|
DATA_WIN,
|
|
height,
|
|
tui_term_width (),
|
|
0,
|
|
origin_y,
|
|
BOX_WINDOW);
|
|
}
|
|
|
|
|
|
|
|
/* Show the Source/Command layout. */
|
|
static void
|
|
show_source_command (void)
|
|
{
|
|
show_source_or_disasm_and_command (SRC_COMMAND);
|
|
}
|
|
|
|
|
|
/* Show the Dissassem/Command layout. */
|
|
static void
|
|
show_disasm_command (void)
|
|
{
|
|
show_source_or_disasm_and_command (DISASSEM_COMMAND);
|
|
}
|
|
|
|
|
|
/* Show the Source/Disassem/Command layout. */
|
|
static void
|
|
show_source_disasm_command (void)
|
|
{
|
|
if (tui_current_layout () != SRC_DISASSEM_COMMAND)
|
|
{
|
|
int cmd_height, src_height, asm_height;
|
|
|
|
if (TUI_CMD_WIN != NULL)
|
|
cmd_height = TUI_CMD_WIN->generic.height;
|
|
else
|
|
cmd_height = tui_term_height () / 3;
|
|
|
|
src_height = (tui_term_height () - cmd_height) / 2;
|
|
asm_height = tui_term_height () - (src_height + cmd_height);
|
|
|
|
if (TUI_SRC_WIN == NULL)
|
|
make_source_window (&TUI_SRC_WIN, src_height, 0);
|
|
else
|
|
{
|
|
init_gen_win_info (&TUI_SRC_WIN->generic,
|
|
TUI_SRC_WIN->generic.type,
|
|
src_height,
|
|
TUI_SRC_WIN->generic.width,
|
|
TUI_SRC_WIN->detail.source_info.execution_info->width,
|
|
0);
|
|
TUI_SRC_WIN->can_highlight = TRUE;
|
|
init_gen_win_info (TUI_SRC_WIN->detail.source_info.execution_info,
|
|
EXEC_INFO_WIN,
|
|
src_height,
|
|
3,
|
|
0,
|
|
0);
|
|
tui_make_visible (&TUI_SRC_WIN->generic);
|
|
tui_make_visible (TUI_SRC_WIN->detail.source_info.execution_info);
|
|
TUI_SRC_WIN->detail.source_info.has_locator = FALSE;;
|
|
}
|
|
if (TUI_SRC_WIN != NULL)
|
|
{
|
|
struct tui_gen_win_info *locator = tui_locator_win_info_ptr ();
|
|
|
|
tui_show_source_content (TUI_SRC_WIN);
|
|
if (TUI_DISASM_WIN == NULL)
|
|
{
|
|
make_disasm_window (&TUI_DISASM_WIN, asm_height, src_height - 1);
|
|
locator
|
|
= ((struct tui_gen_win_info *)
|
|
init_and_make_win (locator,
|
|
LOCATOR_WIN,
|
|
2 /* 1 */ ,
|
|
tui_term_width (),
|
|
0,
|
|
(src_height + asm_height) - 1,
|
|
DONT_BOX_WINDOW));
|
|
}
|
|
else
|
|
{
|
|
init_gen_win_info (locator,
|
|
LOCATOR_WIN,
|
|
2 /* 1 */ ,
|
|
tui_term_width (),
|
|
0,
|
|
(src_height + asm_height) - 1);
|
|
TUI_DISASM_WIN->detail.source_info.has_locator = TRUE;
|
|
init_gen_win_info (&TUI_DISASM_WIN->generic,
|
|
TUI_DISASM_WIN->generic.type,
|
|
asm_height,
|
|
TUI_DISASM_WIN->generic.width,
|
|
TUI_DISASM_WIN->detail.source_info.execution_info->width,
|
|
src_height - 1);
|
|
init_gen_win_info (TUI_DISASM_WIN->detail.source_info.execution_info,
|
|
EXEC_INFO_WIN,
|
|
asm_height,
|
|
3,
|
|
0,
|
|
src_height - 1);
|
|
TUI_DISASM_WIN->can_highlight = TRUE;
|
|
tui_make_visible (&TUI_DISASM_WIN->generic);
|
|
tui_make_visible (TUI_DISASM_WIN->detail.source_info.execution_info);
|
|
}
|
|
if (TUI_DISASM_WIN != NULL)
|
|
{
|
|
TUI_SRC_WIN->detail.source_info.has_locator = FALSE;
|
|
TUI_DISASM_WIN->detail.source_info.has_locator = TRUE;
|
|
tui_make_visible (locator);
|
|
tui_show_locator_content ();
|
|
tui_show_source_content (TUI_DISASM_WIN);
|
|
|
|
if (TUI_CMD_WIN == NULL)
|
|
make_command_window (&TUI_CMD_WIN,
|
|
cmd_height,
|
|
tui_term_height () - cmd_height);
|
|
else
|
|
{
|
|
init_gen_win_info (&TUI_CMD_WIN->generic,
|
|
TUI_CMD_WIN->generic.type,
|
|
TUI_CMD_WIN->generic.height,
|
|
TUI_CMD_WIN->generic.width,
|
|
0,
|
|
TUI_CMD_WIN->generic.origin.y);
|
|
TUI_CMD_WIN->can_highlight = FALSE;
|
|
tui_make_visible (&TUI_CMD_WIN->generic);
|
|
}
|
|
if (TUI_CMD_WIN != NULL)
|
|
tui_refresh_win (&TUI_CMD_WIN->generic);
|
|
}
|
|
}
|
|
tui_set_current_layout_to (SRC_DISASSEM_COMMAND);
|
|
}
|
|
}
|
|
|
|
|
|
/* Show the Source/Data/Command or the Dissassembly/Data/Command
|
|
layout. */
|
|
static void
|
|
show_data (enum tui_layout_type new_layout)
|
|
{
|
|
int total_height = (tui_term_height () - TUI_CMD_WIN->generic.height);
|
|
int src_height, data_height;
|
|
enum tui_win_type win_type;
|
|
struct tui_gen_win_info *locator = tui_locator_win_info_ptr ();
|
|
|
|
|
|
data_height = total_height / 2;
|
|
src_height = total_height - data_height;
|
|
tui_make_all_invisible ();
|
|
tui_make_invisible (locator);
|
|
make_data_window (&TUI_DATA_WIN, data_height, 0);
|
|
TUI_DATA_WIN->can_highlight = TRUE;
|
|
if (new_layout == SRC_DATA_COMMAND)
|
|
win_type = SRC_WIN;
|
|
else
|
|
win_type = DISASSEM_WIN;
|
|
if (tui_win_list[win_type] == NULL)
|
|
{
|
|
if (win_type == SRC_WIN)
|
|
make_source_window (&tui_win_list[win_type], src_height, data_height - 1);
|
|
else
|
|
make_disasm_window (&tui_win_list[win_type], src_height, data_height - 1);
|
|
locator
|
|
= ((struct tui_gen_win_info *)
|
|
init_and_make_win (locator,
|
|
LOCATOR_WIN,
|
|
2 /* 1 */ ,
|
|
tui_term_width (),
|
|
0,
|
|
total_height - 1,
|
|
DONT_BOX_WINDOW));
|
|
}
|
|
else
|
|
{
|
|
init_gen_win_info (&tui_win_list[win_type]->generic,
|
|
tui_win_list[win_type]->generic.type,
|
|
src_height,
|
|
tui_win_list[win_type]->generic.width,
|
|
tui_win_list[win_type]->detail.source_info.execution_info->width,
|
|
data_height - 1);
|
|
init_gen_win_info (tui_win_list[win_type]->detail.source_info.execution_info,
|
|
EXEC_INFO_WIN,
|
|
src_height,
|
|
3,
|
|
0,
|
|
data_height - 1);
|
|
tui_make_visible (&tui_win_list[win_type]->generic);
|
|
tui_make_visible (tui_win_list[win_type]->detail.source_info.execution_info);
|
|
init_gen_win_info (locator,
|
|
LOCATOR_WIN,
|
|
2 /* 1 */ ,
|
|
tui_term_width (),
|
|
0,
|
|
total_height - 1);
|
|
}
|
|
tui_win_list[win_type]->detail.source_info.has_locator = TRUE;
|
|
tui_make_visible (locator);
|
|
tui_show_locator_content ();
|
|
tui_add_to_source_windows (tui_win_list[win_type]);
|
|
tui_set_current_layout_to (new_layout);
|
|
}
|
|
|
|
/* init_gen_win_info().
|
|
*/
|
|
static void
|
|
init_gen_win_info (struct tui_gen_win_info *win_info,
|
|
enum tui_win_type type,
|
|
int height, int width,
|
|
int origin_x, int origin_y)
|
|
{
|
|
int h = height;
|
|
|
|
win_info->type = type;
|
|
win_info->width = width;
|
|
win_info->height = h;
|
|
if (h > 1)
|
|
{
|
|
win_info->viewport_height = h - 1;
|
|
if (win_info->type != CMD_WIN)
|
|
win_info->viewport_height--;
|
|
}
|
|
else
|
|
win_info->viewport_height = 1;
|
|
win_info->origin.x = origin_x;
|
|
win_info->origin.y = origin_y;
|
|
|
|
return;
|
|
} /* init_gen_win_info */
|
|
|
|
/* init_and_make_win().
|
|
*/
|
|
static void *
|
|
init_and_make_win (void *opaque_win_info,
|
|
enum tui_win_type win_type,
|
|
int height, int width,
|
|
int origin_x, int origin_y,
|
|
int box_it)
|
|
{
|
|
struct tui_gen_win_info *generic;
|
|
|
|
if (opaque_win_info == NULL)
|
|
{
|
|
if (tui_win_is_auxillary (win_type))
|
|
opaque_win_info = (void *) tui_alloc_generic_win_info ();
|
|
else
|
|
opaque_win_info = (void *) tui_alloc_win_info (win_type);
|
|
}
|
|
if (tui_win_is_auxillary (win_type))
|
|
generic = (struct tui_gen_win_info *) opaque_win_info;
|
|
else
|
|
generic = &((struct tui_win_info *) opaque_win_info)->generic;
|
|
|
|
if (opaque_win_info != NULL)
|
|
{
|
|
init_gen_win_info (generic, win_type, height, width, origin_x, origin_y);
|
|
if (!tui_win_is_auxillary (win_type))
|
|
{
|
|
if (generic->type == CMD_WIN)
|
|
((struct tui_win_info *) opaque_win_info)->can_highlight = FALSE;
|
|
else
|
|
((struct tui_win_info *) opaque_win_info)->can_highlight = TRUE;
|
|
}
|
|
tui_make_window (generic, box_it);
|
|
}
|
|
return opaque_win_info;
|
|
}
|
|
|
|
|
|
static void
|
|
make_source_or_disasm_window (struct tui_win_info **win_info_ptr,
|
|
enum tui_win_type type,
|
|
int height, int origin_y)
|
|
{
|
|
struct tui_gen_win_info *execution_info = NULL;
|
|
|
|
/* Create the exeuction info window. */
|
|
if (type == SRC_WIN)
|
|
execution_info = tui_source_exec_info_win_ptr ();
|
|
else
|
|
execution_info = tui_disassem_exec_info_win_ptr ();
|
|
execution_info
|
|
= ((struct tui_gen_win_info *)
|
|
init_and_make_win (execution_info,
|
|
EXEC_INFO_WIN,
|
|
height,
|
|
3,
|
|
0,
|
|
origin_y,
|
|
DONT_BOX_WINDOW));
|
|
|
|
/* Now create the source window. */
|
|
*win_info_ptr
|
|
= ((struct tui_win_info *)
|
|
init_and_make_win (*win_info_ptr,
|
|
type,
|
|
height,
|
|
tui_term_width () - execution_info->width,
|
|
execution_info->width,
|
|
origin_y,
|
|
BOX_WINDOW));
|
|
|
|
(*win_info_ptr)->detail.source_info.execution_info = execution_info;
|
|
}
|
|
|
|
|
|
/* Show the Source/Command or the Disassem layout. */
|
|
static void
|
|
show_source_or_disasm_and_command (enum tui_layout_type layout_type)
|
|
{
|
|
if (tui_current_layout () != layout_type)
|
|
{
|
|
struct tui_win_info **win_info_ptr;
|
|
int src_height, cmd_height;
|
|
struct tui_gen_win_info *locator = tui_locator_win_info_ptr ();
|
|
|
|
if (TUI_CMD_WIN != NULL)
|
|
cmd_height = TUI_CMD_WIN->generic.height;
|
|
else
|
|
cmd_height = tui_term_height () / 3;
|
|
src_height = tui_term_height () - cmd_height;
|
|
|
|
if (layout_type == SRC_COMMAND)
|
|
win_info_ptr = &TUI_SRC_WIN;
|
|
else
|
|
win_info_ptr = &TUI_DISASM_WIN;
|
|
|
|
if ((*win_info_ptr) == NULL)
|
|
{
|
|
if (layout_type == SRC_COMMAND)
|
|
make_source_window (win_info_ptr, src_height - 1, 0);
|
|
else
|
|
make_disasm_window (win_info_ptr, src_height - 1, 0);
|
|
locator
|
|
= ((struct tui_gen_win_info *)
|
|
init_and_make_win (locator,
|
|
LOCATOR_WIN,
|
|
2 /* 1 */ ,
|
|
tui_term_width (),
|
|
0,
|
|
src_height - 1,
|
|
DONT_BOX_WINDOW));
|
|
}
|
|
else
|
|
{
|
|
init_gen_win_info (locator,
|
|
LOCATOR_WIN,
|
|
2 /* 1 */ ,
|
|
tui_term_width (),
|
|
0,
|
|
src_height - 1);
|
|
(*win_info_ptr)->detail.source_info.has_locator = TRUE;
|
|
init_gen_win_info (&(*win_info_ptr)->generic,
|
|
(*win_info_ptr)->generic.type,
|
|
src_height - 1,
|
|
(*win_info_ptr)->generic.width,
|
|
(*win_info_ptr)->detail.source_info.execution_info->width,
|
|
0);
|
|
init_gen_win_info ((*win_info_ptr)->detail.source_info.execution_info,
|
|
EXEC_INFO_WIN,
|
|
src_height - 1,
|
|
3,
|
|
0,
|
|
0);
|
|
(*win_info_ptr)->can_highlight = TRUE;
|
|
tui_make_visible (&(*win_info_ptr)->generic);
|
|
tui_make_visible ((*win_info_ptr)->detail.source_info.execution_info);
|
|
}
|
|
if ((*win_info_ptr) != NULL)
|
|
{
|
|
(*win_info_ptr)->detail.source_info.has_locator = TRUE;
|
|
tui_make_visible (locator);
|
|
tui_show_locator_content ();
|
|
tui_show_source_content (*win_info_ptr);
|
|
|
|
if (TUI_CMD_WIN == NULL)
|
|
{
|
|
make_command_window (&TUI_CMD_WIN, cmd_height, src_height);
|
|
tui_refresh_win (&TUI_CMD_WIN->generic);
|
|
}
|
|
else
|
|
{
|
|
init_gen_win_info (&TUI_CMD_WIN->generic,
|
|
TUI_CMD_WIN->generic.type,
|
|
TUI_CMD_WIN->generic.height,
|
|
TUI_CMD_WIN->generic.width,
|
|
TUI_CMD_WIN->generic.origin.x,
|
|
TUI_CMD_WIN->generic.origin.y);
|
|
TUI_CMD_WIN->can_highlight = FALSE;
|
|
tui_make_visible (&TUI_CMD_WIN->generic);
|
|
}
|
|
}
|
|
tui_set_current_layout_to (layout_type);
|
|
}
|
|
}
|