mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-25 11:04:18 +08:00
d7e747318f
This patch starts from the desire to eliminate make_cleanup_ui_file_delete, but then goes beyond. It makes ui_file & friends a real C++ class hierarchy, and switches temporary ui_file-like objects to stack-based allocation. - mem_fileopen -> string_file mem_fileopen is replaced with a new string_file class that is treated as a value class created on the stack. This alone eliminates most make_cleanup_ui_file_delete calls, and, simplifies code a whole lot (diffstat shows around 1k loc dropped.) string_file's internal buffer is a std::string, thus the "string" in the name. This simplifies the implementation much, compared to mem_fileopen, which managed growing its internal buffer manually. - ui_file_as_string, ui_file_strdup, ui_file_obsavestring all gone The new string_file class has a string() method that provides direct writable access to the internal std::string buffer. This replaced ui_file_as_string, which forced a copy of the same data the stream had inside. With direct access via a writable reference, we can instead move the string out of the string_stream, avoiding deep string copying. Related, ui_file_xstrdup calls are replaced with xstrdup'ping the stream's string, and ui_file_obsavestring is replaced by obstack_copy0. With all those out of the way, getting rid of the weird ui_file_put mechanism was possible. - New ui_file::printf, ui_file::puts, etc. methods These simplify / clarify client code. I considered splitting client-code changes, like these, e.g.: - stb = mem_fileopen (); - fprintf_unfiltered (stb, "%s%s%s", - _("The valid values are:\n"), - regdesc, - _("The default is \"std\".")); + string_file stb; + stb.printf ("%s%s%s", + _("The valid values are:\n"), + regdesc, + _("The default is \"std\".")); In two steps, with the first step leaving fprintf_unfiltered (etc.) calls in place, and only afterwards do a pass to change all those to call stb.printf etc.. I didn't do that split, because (when I tried), it turned out to be pointless make-work: the first pass would have to touch the fprintf_unfiltered line anyway, to replace "stb" with "&stb". - gdb_fopen replaced with stack-based objects This avoids the need for cleanups or unique_ptr's. I.e., this: struct ui_file *file = gdb_fopen (filename, "w"); if (filename == NULL) perror_with_name (filename); cleanups = make_cleanup_ui_file_delete (file); // use file. do_cleanups (cleanups); is replaced with this: stdio_file file; if (!file.open (filename, "w")) perror_with_name (filename); // use file. - odd contorsions in null_file_write / null_file_fputs around when to call to_fputs / to_write eliminated. - Global null_stream object A few places that were allocating a ui_file in order to print to "nowhere" are adjusted to instead refer to a new 'null_stream' global stream. - TUI's tui_sfileopen eliminated. TUI's ui_file much simplified The TUI's ui_file was serving a dual purpose. It supported being used as string buffer, and supported being backed by a stdio FILE. The string buffer part is gone, replaced by using of string_file. The 'FILE *' support is now much simplified, by making the TUI's ui_file inherit from stdio_file. gdb/ChangeLog: 2017-02-02 Pedro Alves <palves@redhat.com> * ada-lang.c (type_as_string): Use string_file. * ada-valprint.c (ada_print_floating): Use string_file. * ada-varobj.c (ada_varobj_scalar_image) (ada_varobj_get_value_image): Use string_file. * aix-thread.c (aix_thread_extra_thread_info): Use string_file. * arm-tdep.c (_initialize_arm_tdep): Use string_printf. * breakpoint.c (update_inserted_breakpoint_locations) (insert_breakpoint_locations, reattach_breakpoints) (print_breakpoint_location, print_one_detail_ranged_breakpoint) (print_it_watchpoint): Use string_file. (save_breakpoints): Use stdio_file. * c-exp.y (oper): Use string_file. * cli/cli-logging.c (set_logging_redirect): Use ui_file_up and tee_file. (pop_output_files): Use delete. (handle_redirections): Use stdio_file and tee_file. * cli/cli-setshow.c (do_show_command): Use string_file. * compile/compile-c-support.c (c_compute_program): Use string_file. * compile/compile-c-symbols.c (generate_vla_size): Take a 'string_file &' instead of a 'ui_file *'. (generate_c_for_for_one_variable): Take a 'string_file &' instead of a 'ui_file *'. Use string_file. (generate_c_for_variable_locations): Take a 'string_file &' instead of a 'ui_file *'. * compile/compile-internal.h (generate_c_for_for_one_variable): Take a 'string_file &' instead of a 'ui_file *'. * compile/compile-loc2c.c (push, pushf, unary, binary) (print_label, pushf_register_address, pushf_register) (do_compile_dwarf_expr_to_c): Take a 'string_file &' instead of a 'ui_file *'. Adjust. * compile/compile.c (compile_to_object): Use string_file. * compile/compile.h (compile_dwarf_expr_to_c) (compile_dwarf_bounds_to_c): Take a 'string_file &' instead of a 'ui_file *'. * cp-support.c (inspect_type): Use string_file and obstack_copy0. (replace_typedefs_qualified_name): Use string_file and obstack_copy0. * disasm.c (gdb_pretty_print_insn): Use string_file. (gdb_disassembly): Adjust reference the null_stream global. (do_ui_file_delete): Delete. (gdb_insn_length): Use null_stream. * dummy-frame.c (maintenance_print_dummy_frames): Use stdio_file. * dwarf2loc.c (dwarf2_compile_property_to_c) (locexpr_generate_c_location, loclist_generate_c_location): Take a 'string_file &' instead of a 'ui_file *'. * dwarf2loc.h (dwarf2_compile_property_to_c): Likewise. * dwarf2read.c (do_ui_file_peek_last): Delete. (dwarf2_compute_name): Use string_file. * event-top.c (gdb_setup_readline): Use stdio_file. * gdbarch.sh (verify_gdbarch): Use string_file. * gdbtypes.c (safe_parse_type): Use null_stream. * guile/scm-breakpoint.c (gdbscm_breakpoint_commands): Use string_file. * guile/scm-disasm.c (gdbscm_print_insn_from_port): Take a 'string_file *' instead of a 'ui_file *'. (gdbscm_arch_disassemble): Use string_file. * guile/scm-frame.c (frscm_print_frame_smob): Use string_file. * guile/scm-ports.c (class ioscm_file_port): Now a class that inherits from ui_file. (ioscm_file_port_delete, ioscm_file_port_rewind) (ioscm_file_port_put): Delete. (ioscm_file_port_write): Rename to ... (ioscm_file_port::write): ... this. Remove file_port_magic checks. (ioscm_file_port_new): Delete. (ioscm_with_output_to_port_worker): Use ioscm_file_port and ui_file_up. * guile/scm-type.c (tyscm_type_name): Use string_file. * guile/scm-value.c (vlscm_print_value_smob, gdbscm_value_print): Use string_file. * infcmd.c (print_return_value_1): Use string_file. * infrun.c (print_target_wait_results): Use string_file. * language.c (add_language): Use string_file. * location.c (explicit_to_string_internal): Use string_file. * main.c (captured_main_1): Use null_file. * maint.c (maintenance_print_architecture): Use stdio_file. * mi/mi-cmd-stack.c (list_arg_or_local): Use string_file. * mi/mi-common.h (struct mi_interp) <out, err, log, targ, event_channel>: Change type to mi_console_file pointer. * mi/mi-console.c (mi_console_file_fputs, mi_console_file_flush) (mi_console_file_delete): Delete. (struct mi_console_file): Delete. (mi_console_file_magic): Delete. (mi_console_file_new): Delete. (mi_console_file::mi_console_file): New. (mi_console_file_delete): Delete. (mi_console_file_fputs): Delete. (mi_console_file::write): New. (mi_console_raw_packet): Delete. (mi_console_file::flush): New. (mi_console_file_flush): Delete. (mi_console_set_raw): Rename to ... (mi_console_file::set_raw): ... this. * mi/mi-console.h (class mi_console_file): New class. (mi_console_file_new, mi_console_set_raw): Delete. * mi/mi-interp.c (mi_interpreter_init): Use mi_console_file. (mi_set_logging): Use delete and tee_file. Adjust. * mi/mi-main.c (output_register): Use string_file. (mi_cmd_data_evaluate_expression): Use string_file. (mi_cmd_data_read_memory): Use string_file. (mi_cmd_execute, print_variable_or_computed): Use string_file. * mi/mi-out.c (mi_ui_out::main_stream): New. (mi_ui_out::rewind): Use main_stream and string_file. (mi_ui_out::put): Use main_stream and string_file. (mi_ui_out::mi_ui_out): Remove 'stream' parameter. Allocate a 'string_file' instead. (mi_out_new): Don't allocate a mem_fileopen stream here. * mi/mi-out.h (mi_ui_out::mi_ui_out): Remove 'stream' parameter. (mi_ui_out::main_stream): Declare method. * printcmd.c (eval_command): Use string_file. * psymtab.c (maintenance_print_psymbols): Use stdio_file. * python/py-arch.c (archpy_disassemble): Use string_file. * python/py-breakpoint.c (bppy_get_commands): Use string_file. * python/py-frame.c (frapy_str): Use string_file. * python/py-framefilter.c (py_print_type, py_print_single_arg): Use string_file. * python/py-type.c (typy_str): Use string_file. * python/py-unwind.c (unwind_infopy_str): Use string_file. * python/py-value.c (valpy_str): Use string_file. * record-btrace.c (btrace_insn_history): Use string_file. * regcache.c (regcache_print): Use stdio_file. * reggroups.c (maintenance_print_reggroups): Use stdio_file. * remote.c (escape_buffer): Use string_file. * rust-lang.c (rust_get_disr_info): Use string_file. * serial.c (serial_open_ops_1): Use stdio_file. (do_serial_close): Use delete. * stack.c (print_frame_arg): Use string_file. (print_frame_args): Remove local mem_fileopen stream, not used. (print_frame): Use string_file. * symmisc.c (maintenance_print_symbols): Use stdio_file. * symtab.h (struct symbol_computed_ops) <generate_c_location>: Take a 'string_file *' instead of a 'ui_file *'. * top.c (new_ui): Use stdio_file and stderr_file. (free_ui): Use delete. (execute_command_to_string): Use string_file. (quit_confirm): Use string_file. * tracepoint.c (collection_list::append_exp): Use string_file. * tui/tui-disasm.c (tui_disassemble): Use string_file. * tui/tui-file.c: Don't include "ui-file.h". (enum streamtype, struct tui_stream): Delete. (tui_file_new, tui_file_delete, tui_fileopen, tui_sfileopen) (tui_file_isatty, tui_file_rewind, tui_file_put): Delete. (tui_file::tui_file): New method. (tui_file_fputs): Delete. (tui_file_get_strbuf): Delete. (tui_file::puts): New method. (tui_file_adjust_strbuf): Delete. (tui_file_flush): Delete. (tui_file::flush): New method. * tui/tui-file.h: Tweak intro comment. Include ui-file.h. (tui_fileopen, tui_sfileopen, tui_file_get_strbuf) (tui_file_adjust_strbuf): Delete declarations. (class tui_file): New class. * tui/tui-io.c (tui_initialize_io): Use tui_file. * tui/tui-regs.c (tui_restore_gdbout): Use delete. (tui_register_format): Use string_stream. * tui/tui-stack.c (tui_make_status_line): Use string_file. (tui_get_function_from_frame): Use string_file. * typeprint.c (type_to_string): Use string_file. * ui-file.c (struct ui_file, ui_file_magic, ui_file_new): Delete. (null_stream): New global. (ui_file_delete): Delete. (ui_file::ui_file): New. (null_file_isatty): Delete. (ui_file::~ui_file): New. (null_file_rewind): Delete. (ui_file::printf): New. (null_file_put): Delete. (null_file_flush): Delete. (ui_file::putstr): New. (null_file_write): Delete. (ui_file::putstrn): New. (null_file_read): Delete. (ui_file::putc): New. (null_file_fputs): Delete. (null_file_write_async_safe): Delete. (ui_file::vprintf): New. (null_file_delete): Delete. (null_file::write): New. (null_file_fseek): Delete. (null_file::puts): New. (ui_file_data): Delete. (null_file::write_async_safe): New. (gdb_flush, ui_file_isatty): Adjust. (ui_file_put, ui_file_rewind): Delete. (ui_file_write): Adjust. (ui_file_write_for_put): Delete. (ui_file_write_async_safe, ui_file_read): Adjust. (ui_file_fseek): Delete. (fputs_unfiltered): Adjust. (set_ui_file_flush, set_ui_file_isatty, set_ui_file_rewind) (set_ui_file_put, set_ui_file_write, set_ui_file_write_async_safe) (set_ui_file_read, set_ui_file_fputs, set_ui_file_fseek) (set_ui_file_data): Delete. (string_file::~string_file, string_file::write) (struct accumulated_ui_file, do_ui_file_xstrdup, ui_file_xstrdup) (do_ui_file_as_string, ui_file_as_string): Delete. (do_ui_file_obsavestring, ui_file_obsavestring): Delete. (struct mem_file): Delete. (mem_file_new): Delete. (stdio_file::stdio_file): New. (mem_file_delete): Delete. (stdio_file::stdio_file): New. (mem_fileopen): Delete. (stdio_file::~stdio_file): New. (mem_file_rewind): Delete. (stdio_file::set_stream): New. (mem_file_put): Delete. (stdio_file::open): New. (mem_file_write): Delete. (stdio_file_magic, struct stdio_file): Delete. (stdio_file_new, stdio_file_delete, stdio_file_flush): Delete. (stdio_file::flush): New. (stdio_file_read): Rename to ... (stdio_file::read): ... this. Adjust. (stdio_file_write): Rename to ... (stdio_file::write): ... this. Adjust. (stdio_file_write_async_safe): Rename to ... (stdio_file::write_async_safe) ... this. Adjust. (stdio_file_fputs): Rename to ... (stdio_file::puts) ... this. Adjust. (stdio_file_isatty): Delete. (stdio_file_fseek): Delete. (stdio_file::isatty): New. (stderr_file_write): Rename to ... (stderr_file::write) ... this. Adjust. (stderr_file_fputs): Rename to ... (stderr_file::puts) ... this. Adjust. (stderr_fileopen, stdio_fileopen, gdb_fopen): Delete. (stderr_file::stderr_file): New. (tee_file_magic): Delete. (struct tee_file): Delete. (tee_file::tee_file): New. (tee_file_new): Delete. (tee_file::~tee_file): New. (tee_file_delete): Delete. (tee_file_flush): Rename to ... (tee_file::flush): ... this. Adjust. (tee_file_write): Rename to ... (tee_file::write): ... this. Adjust. (tee_file::write_async_safe): New. (tee_file_fputs): Rename to ... (tee_file::puts): ... this. Adjust. (tee_file_isatty): Rename to ... (tee_file::isatty): ... this. Adjust. * ui-file.h (struct obstack, struct ui_file): Don't forward-declare. (ui_file_new, ui_file_flush_ftype, set_ui_file_flush) (ui_file_write_ftype) (set_ui_file_write, ui_file_fputs_ftype, set_ui_file_fputs) (ui_file_write_async_safe_ftype, set_ui_file_write_async_safe) (ui_file_read_ftype, set_ui_file_read, ui_file_isatty_ftype) (set_ui_file_isatty, ui_file_rewind_ftype, set_ui_file_rewind) (ui_file_put_method_ftype, ui_file_put_ftype, set_ui_file_put) (ui_file_delete_ftype, set_ui_file_data, ui_file_fseek_ftype) (set_ui_file_fseek): Delete. (ui_file_data, ui_file_delete, ui_file_rewind) (struct ui_file): New. (ui_file_up): New. (class null_file): New. (null_stream): Declare. (ui_file_write_for_put, ui_file_put): Delete. (ui_file_xstrdup, ui_file_as_string, ui_file_obsavestring): Delete. (ui_file_fseek, mem_fileopen, stdio_fileopen, stderr_fileopen) (gdb_fopen, tee_file_new): Delete. (struct string_file): New. (struct stdio_file): New. (stdio_file_up): New. (struct stderr_file): New. (class tee_file): New. * ui-out.c (ui_out::field_stream): Take a 'string_file &' instead of a 'ui_file *'. Adjust. * ui-out.h (class ui_out) <field_stream>: Likewise. * utils.c (do_ui_file_delete, make_cleanup_ui_file_delete) (null_stream): Delete. (error_stream): Take a 'string_file &' instead of a 'ui_file *'. Adjust. * utils.h (struct ui_file): Delete forward declaration.. (make_cleanup_ui_file_delete, null_stream): Delete declarations. (error_stream): Take a 'string_file &' instead of a 'ui_file *'. * varobj.c (varobj_value_get_print_value): Use string_file. * xtensa-tdep.c (xtensa_verify_config): Use string_file. * gdbarch.c: Regenerate.
1152 lines
33 KiB
C
1152 lines
33 KiB
C
/* Support for GDB maintenance commands.
|
||
|
||
Copyright (C) 1992-2017 Free Software Foundation, Inc.
|
||
|
||
Written by Fred Fish at Cygnus Support.
|
||
|
||
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 <ctype.h>
|
||
#include <signal.h>
|
||
#include "command.h"
|
||
#include "gdbcmd.h"
|
||
#include "symtab.h"
|
||
#include "block.h"
|
||
#include "gdbtypes.h"
|
||
#include "demangle.h"
|
||
#include "gdbcore.h"
|
||
#include "expression.h" /* For language.h */
|
||
#include "language.h"
|
||
#include "symfile.h"
|
||
#include "objfiles.h"
|
||
#include "value.h"
|
||
#include "top.h"
|
||
#include "maint.h"
|
||
#include "selftest.h"
|
||
|
||
#include "cli/cli-decode.h"
|
||
#include "cli/cli-utils.h"
|
||
#include "cli/cli-setshow.h"
|
||
|
||
extern void _initialize_maint_cmds (void);
|
||
|
||
static void maintenance_command (char *, int);
|
||
|
||
static void maintenance_internal_error (char *args, int from_tty);
|
||
|
||
static void maintenance_demangle (char *, int);
|
||
|
||
static void maintenance_time_display (char *, int);
|
||
|
||
static void maintenance_space_display (char *, int);
|
||
|
||
static void maintenance_info_command (char *, int);
|
||
|
||
static void maintenance_info_sections (char *, int);
|
||
|
||
static void maintenance_print_command (char *, int);
|
||
|
||
static void maintenance_do_deprecate (char *, int);
|
||
|
||
/* Set this to the maximum number of seconds to wait instead of waiting forever
|
||
in target_wait(). If this timer times out, then it generates an error and
|
||
the command is aborted. This replaces most of the need for timeouts in the
|
||
GDB test suite, and makes it possible to distinguish between a hung target
|
||
and one with slow communications. */
|
||
|
||
int watchdog = 0;
|
||
static void
|
||
show_watchdog (struct ui_file *file, int from_tty,
|
||
struct cmd_list_element *c, const char *value)
|
||
{
|
||
fprintf_filtered (file, _("Watchdog timer is %s.\n"), value);
|
||
}
|
||
|
||
/* Access the maintenance subcommands. */
|
||
|
||
static void
|
||
maintenance_command (char *args, int from_tty)
|
||
{
|
||
printf_unfiltered (_("\"maintenance\" must be followed by "
|
||
"the name of a maintenance command.\n"));
|
||
help_list (maintenancelist, "maintenance ", all_commands, gdb_stdout);
|
||
}
|
||
|
||
#ifndef _WIN32
|
||
static void
|
||
maintenance_dump_me (char *args, int from_tty)
|
||
{
|
||
if (query (_("Should GDB dump core? ")))
|
||
{
|
||
#ifdef __DJGPP__
|
||
/* SIGQUIT by default is ignored, so use SIGABRT instead. */
|
||
signal (SIGABRT, SIG_DFL);
|
||
kill (getpid (), SIGABRT);
|
||
#else
|
||
signal (SIGQUIT, SIG_DFL);
|
||
kill (getpid (), SIGQUIT);
|
||
#endif
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/* Stimulate the internal error mechanism that GDB uses when an
|
||
internal problem is detected. Allows testing of the mechanism.
|
||
Also useful when the user wants to drop a core file but not exit
|
||
GDB. */
|
||
|
||
static void
|
||
maintenance_internal_error (char *args, int from_tty)
|
||
{
|
||
internal_error (__FILE__, __LINE__, "%s", (args == NULL ? "" : args));
|
||
}
|
||
|
||
/* Stimulate the internal error mechanism that GDB uses when an
|
||
internal problem is detected. Allows testing of the mechanism.
|
||
Also useful when the user wants to drop a core file but not exit
|
||
GDB. */
|
||
|
||
static void
|
||
maintenance_internal_warning (char *args, int from_tty)
|
||
{
|
||
internal_warning (__FILE__, __LINE__, "%s", (args == NULL ? "" : args));
|
||
}
|
||
|
||
/* Stimulate the internal error mechanism that GDB uses when an
|
||
demangler problem is detected. Allows testing of the mechanism. */
|
||
|
||
static void
|
||
maintenance_demangler_warning (char *args, int from_tty)
|
||
{
|
||
demangler_warning (__FILE__, __LINE__, "%s", (args == NULL ? "" : args));
|
||
}
|
||
|
||
/* Old command to demangle a string. The command has been moved to "demangle".
|
||
It is kept for now because otherwise "mt demangle" gets interpreted as
|
||
"mt demangler-warning" which artificially creates an internal gdb error. */
|
||
|
||
static void
|
||
maintenance_demangle (char *args, int from_tty)
|
||
{
|
||
printf_filtered (_("This command has been moved to \"demangle\".\n"));
|
||
}
|
||
|
||
static void
|
||
maintenance_time_display (char *args, int from_tty)
|
||
{
|
||
if (args == NULL || *args == '\0')
|
||
printf_unfiltered (_("\"maintenance time\" takes a numeric argument.\n"));
|
||
else
|
||
set_per_command_time (strtol (args, NULL, 10));
|
||
}
|
||
|
||
static void
|
||
maintenance_space_display (char *args, int from_tty)
|
||
{
|
||
if (args == NULL || *args == '\0')
|
||
printf_unfiltered ("\"maintenance space\" takes a numeric argument.\n");
|
||
else
|
||
set_per_command_space (strtol (args, NULL, 10));
|
||
}
|
||
|
||
/* The "maintenance info" command is defined as a prefix, with
|
||
allow_unknown 0. Therefore, its own definition is called only for
|
||
"maintenance info" with no args. */
|
||
|
||
static void
|
||
maintenance_info_command (char *arg, int from_tty)
|
||
{
|
||
printf_unfiltered (_("\"maintenance info\" must be followed "
|
||
"by the name of an info command.\n"));
|
||
help_list (maintenanceinfolist, "maintenance info ", all_commands,
|
||
gdb_stdout);
|
||
}
|
||
|
||
/* Mini tokenizing lexer for 'maint info sections' command. */
|
||
|
||
static int
|
||
match_substring (const char *string, const char *substr)
|
||
{
|
||
int substr_len = strlen(substr);
|
||
const char *tok;
|
||
|
||
while ((tok = strstr (string, substr)) != NULL)
|
||
{
|
||
/* Got a partial match. Is it a whole word? */
|
||
if (tok == string
|
||
|| tok[-1] == ' '
|
||
|| tok[-1] == '\t')
|
||
{
|
||
/* Token is delimited at the front... */
|
||
if (tok[substr_len] == ' '
|
||
|| tok[substr_len] == '\t'
|
||
|| tok[substr_len] == '\0')
|
||
{
|
||
/* Token is delimited at the rear. Got a whole-word match. */
|
||
return 1;
|
||
}
|
||
}
|
||
/* Token didn't match as a whole word. Advance and try again. */
|
||
string = tok + 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static int
|
||
match_bfd_flags (const char *string, flagword flags)
|
||
{
|
||
if (flags & SEC_ALLOC)
|
||
if (match_substring (string, "ALLOC"))
|
||
return 1;
|
||
if (flags & SEC_LOAD)
|
||
if (match_substring (string, "LOAD"))
|
||
return 1;
|
||
if (flags & SEC_RELOC)
|
||
if (match_substring (string, "RELOC"))
|
||
return 1;
|
||
if (flags & SEC_READONLY)
|
||
if (match_substring (string, "READONLY"))
|
||
return 1;
|
||
if (flags & SEC_CODE)
|
||
if (match_substring (string, "CODE"))
|
||
return 1;
|
||
if (flags & SEC_DATA)
|
||
if (match_substring (string, "DATA"))
|
||
return 1;
|
||
if (flags & SEC_ROM)
|
||
if (match_substring (string, "ROM"))
|
||
return 1;
|
||
if (flags & SEC_CONSTRUCTOR)
|
||
if (match_substring (string, "CONSTRUCTOR"))
|
||
return 1;
|
||
if (flags & SEC_HAS_CONTENTS)
|
||
if (match_substring (string, "HAS_CONTENTS"))
|
||
return 1;
|
||
if (flags & SEC_NEVER_LOAD)
|
||
if (match_substring (string, "NEVER_LOAD"))
|
||
return 1;
|
||
if (flags & SEC_COFF_SHARED_LIBRARY)
|
||
if (match_substring (string, "COFF_SHARED_LIBRARY"))
|
||
return 1;
|
||
if (flags & SEC_IS_COMMON)
|
||
if (match_substring (string, "IS_COMMON"))
|
||
return 1;
|
||
|
||
return 0;
|
||
}
|
||
|
||
static void
|
||
print_bfd_flags (flagword flags)
|
||
{
|
||
if (flags & SEC_ALLOC)
|
||
printf_filtered (" ALLOC");
|
||
if (flags & SEC_LOAD)
|
||
printf_filtered (" LOAD");
|
||
if (flags & SEC_RELOC)
|
||
printf_filtered (" RELOC");
|
||
if (flags & SEC_READONLY)
|
||
printf_filtered (" READONLY");
|
||
if (flags & SEC_CODE)
|
||
printf_filtered (" CODE");
|
||
if (flags & SEC_DATA)
|
||
printf_filtered (" DATA");
|
||
if (flags & SEC_ROM)
|
||
printf_filtered (" ROM");
|
||
if (flags & SEC_CONSTRUCTOR)
|
||
printf_filtered (" CONSTRUCTOR");
|
||
if (flags & SEC_HAS_CONTENTS)
|
||
printf_filtered (" HAS_CONTENTS");
|
||
if (flags & SEC_NEVER_LOAD)
|
||
printf_filtered (" NEVER_LOAD");
|
||
if (flags & SEC_COFF_SHARED_LIBRARY)
|
||
printf_filtered (" COFF_SHARED_LIBRARY");
|
||
if (flags & SEC_IS_COMMON)
|
||
printf_filtered (" IS_COMMON");
|
||
}
|
||
|
||
static void
|
||
maint_print_section_info (const char *name, flagword flags,
|
||
CORE_ADDR addr, CORE_ADDR endaddr,
|
||
unsigned long filepos, int addr_size)
|
||
{
|
||
printf_filtered (" %s", hex_string_custom (addr, addr_size));
|
||
printf_filtered ("->%s", hex_string_custom (endaddr, addr_size));
|
||
printf_filtered (" at %s",
|
||
hex_string_custom ((unsigned long) filepos, 8));
|
||
printf_filtered (": %s", name);
|
||
print_bfd_flags (flags);
|
||
printf_filtered ("\n");
|
||
}
|
||
|
||
static void
|
||
print_bfd_section_info (bfd *abfd,
|
||
asection *asect,
|
||
void *datum)
|
||
{
|
||
flagword flags = bfd_get_section_flags (abfd, asect);
|
||
const char *name = bfd_section_name (abfd, asect);
|
||
const char *arg = (const char *) datum;
|
||
|
||
if (arg == NULL || *arg == '\0'
|
||
|| match_substring (arg, name)
|
||
|| match_bfd_flags (arg, flags))
|
||
{
|
||
struct gdbarch *gdbarch = gdbarch_from_bfd (abfd);
|
||
int addr_size = gdbarch_addr_bit (gdbarch) / 8;
|
||
CORE_ADDR addr, endaddr;
|
||
|
||
addr = bfd_section_vma (abfd, asect);
|
||
endaddr = addr + bfd_section_size (abfd, asect);
|
||
printf_filtered (" [%d] ", gdb_bfd_section_index (abfd, asect));
|
||
maint_print_section_info (name, flags, addr, endaddr,
|
||
asect->filepos, addr_size);
|
||
}
|
||
}
|
||
|
||
static void
|
||
print_objfile_section_info (bfd *abfd,
|
||
struct obj_section *asect,
|
||
const char *string)
|
||
{
|
||
flagword flags = bfd_get_section_flags (abfd, asect->the_bfd_section);
|
||
const char *name = bfd_section_name (abfd, asect->the_bfd_section);
|
||
|
||
if (string == NULL || *string == '\0'
|
||
|| match_substring (string, name)
|
||
|| match_bfd_flags (string, flags))
|
||
{
|
||
struct gdbarch *gdbarch = gdbarch_from_bfd (abfd);
|
||
int addr_size = gdbarch_addr_bit (gdbarch) / 8;
|
||
|
||
maint_print_section_info (name, flags,
|
||
obj_section_addr (asect),
|
||
obj_section_endaddr (asect),
|
||
asect->the_bfd_section->filepos,
|
||
addr_size);
|
||
}
|
||
}
|
||
|
||
static void
|
||
maintenance_info_sections (char *arg, int from_tty)
|
||
{
|
||
if (exec_bfd)
|
||
{
|
||
printf_filtered (_("Exec file:\n"));
|
||
printf_filtered (" `%s', ", bfd_get_filename (exec_bfd));
|
||
wrap_here (" ");
|
||
printf_filtered (_("file type %s.\n"), bfd_get_target (exec_bfd));
|
||
if (arg && *arg && match_substring (arg, "ALLOBJ"))
|
||
{
|
||
struct objfile *ofile;
|
||
struct obj_section *osect;
|
||
|
||
/* Only this function cares about the 'ALLOBJ' argument;
|
||
if 'ALLOBJ' is the only argument, discard it rather than
|
||
passing it down to print_objfile_section_info (which
|
||
wouldn't know how to handle it). */
|
||
if (strcmp (arg, "ALLOBJ") == 0)
|
||
arg = NULL;
|
||
|
||
ALL_OBJFILES (ofile)
|
||
{
|
||
printf_filtered (_(" Object file: %s\n"),
|
||
bfd_get_filename (ofile->obfd));
|
||
ALL_OBJFILE_OSECTIONS (ofile, osect)
|
||
{
|
||
print_objfile_section_info (ofile->obfd, osect, arg);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
bfd_map_over_sections (exec_bfd, print_bfd_section_info, arg);
|
||
}
|
||
|
||
if (core_bfd)
|
||
{
|
||
printf_filtered (_("Core file:\n"));
|
||
printf_filtered (" `%s', ", bfd_get_filename (core_bfd));
|
||
wrap_here (" ");
|
||
printf_filtered (_("file type %s.\n"), bfd_get_target (core_bfd));
|
||
bfd_map_over_sections (core_bfd, print_bfd_section_info, arg);
|
||
}
|
||
}
|
||
|
||
static void
|
||
maintenance_print_statistics (char *args, int from_tty)
|
||
{
|
||
print_objfile_statistics ();
|
||
print_symbol_bcache_statistics ();
|
||
}
|
||
|
||
static void
|
||
maintenance_print_architecture (char *args, int from_tty)
|
||
{
|
||
struct gdbarch *gdbarch = get_current_arch ();
|
||
|
||
if (args == NULL)
|
||
gdbarch_dump (gdbarch, gdb_stdout);
|
||
else
|
||
{
|
||
stdio_file file;
|
||
|
||
if (!file.open (args, "w"))
|
||
perror_with_name (_("maintenance print architecture"));
|
||
gdbarch_dump (gdbarch, &file);
|
||
}
|
||
}
|
||
|
||
/* The "maintenance print" command is defined as a prefix, with
|
||
allow_unknown 0. Therefore, its own definition is called only for
|
||
"maintenance print" with no args. */
|
||
|
||
static void
|
||
maintenance_print_command (char *arg, int from_tty)
|
||
{
|
||
printf_unfiltered (_("\"maintenance print\" must be followed "
|
||
"by the name of a print command.\n"));
|
||
help_list (maintenanceprintlist, "maintenance print ", all_commands,
|
||
gdb_stdout);
|
||
}
|
||
|
||
/* The "maintenance translate-address" command converts a section and address
|
||
to a symbol. This can be called in two ways:
|
||
maintenance translate-address <secname> <addr>
|
||
or maintenance translate-address <addr>. */
|
||
|
||
static void
|
||
maintenance_translate_address (char *arg, int from_tty)
|
||
{
|
||
CORE_ADDR address;
|
||
struct obj_section *sect;
|
||
char *p;
|
||
struct bound_minimal_symbol sym;
|
||
struct objfile *objfile;
|
||
|
||
if (arg == NULL || *arg == 0)
|
||
error (_("requires argument (address or section + address)"));
|
||
|
||
sect = NULL;
|
||
p = arg;
|
||
|
||
if (!isdigit (*p))
|
||
{ /* See if we have a valid section name. */
|
||
while (*p && !isspace (*p)) /* Find end of section name. */
|
||
p++;
|
||
if (*p == '\000') /* End of command? */
|
||
error (_("Need to specify <section-name> and <address>"));
|
||
*p++ = '\000';
|
||
p = skip_spaces (p);
|
||
|
||
ALL_OBJSECTIONS (objfile, sect)
|
||
{
|
||
if (strcmp (sect->the_bfd_section->name, arg) == 0)
|
||
break;
|
||
}
|
||
|
||
if (!objfile)
|
||
error (_("Unknown section %s."), arg);
|
||
}
|
||
|
||
address = parse_and_eval_address (p);
|
||
|
||
if (sect)
|
||
sym = lookup_minimal_symbol_by_pc_section (address, sect);
|
||
else
|
||
sym = lookup_minimal_symbol_by_pc (address);
|
||
|
||
if (sym.minsym)
|
||
{
|
||
const char *symbol_name = MSYMBOL_PRINT_NAME (sym.minsym);
|
||
const char *symbol_offset
|
||
= pulongest (address - BMSYMBOL_VALUE_ADDRESS (sym));
|
||
|
||
sect = MSYMBOL_OBJ_SECTION(sym.objfile, sym.minsym);
|
||
if (sect != NULL)
|
||
{
|
||
const char *section_name;
|
||
const char *obj_name;
|
||
|
||
gdb_assert (sect->the_bfd_section && sect->the_bfd_section->name);
|
||
section_name = sect->the_bfd_section->name;
|
||
|
||
gdb_assert (sect->objfile && objfile_name (sect->objfile));
|
||
obj_name = objfile_name (sect->objfile);
|
||
|
||
if (MULTI_OBJFILE_P ())
|
||
printf_filtered (_("%s + %s in section %s of %s\n"),
|
||
symbol_name, symbol_offset,
|
||
section_name, obj_name);
|
||
else
|
||
printf_filtered (_("%s + %s in section %s\n"),
|
||
symbol_name, symbol_offset, section_name);
|
||
}
|
||
else
|
||
printf_filtered (_("%s + %s\n"), symbol_name, symbol_offset);
|
||
}
|
||
else if (sect)
|
||
printf_filtered (_("no symbol at %s:%s\n"),
|
||
sect->the_bfd_section->name, hex_string (address));
|
||
else
|
||
printf_filtered (_("no symbol at %s\n"), hex_string (address));
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
/* When a command is deprecated the user will be warned the first time
|
||
the command is used. If possible, a replacement will be
|
||
offered. */
|
||
|
||
static void
|
||
maintenance_deprecate (char *args, int from_tty)
|
||
{
|
||
if (args == NULL || *args == '\0')
|
||
{
|
||
printf_unfiltered (_("\"maintenance deprecate\" takes an argument,\n\
|
||
the command you want to deprecate, and optionally the replacement command\n\
|
||
enclosed in quotes.\n"));
|
||
}
|
||
|
||
maintenance_do_deprecate (args, 1);
|
||
|
||
}
|
||
|
||
|
||
static void
|
||
maintenance_undeprecate (char *args, int from_tty)
|
||
{
|
||
if (args == NULL || *args == '\0')
|
||
{
|
||
printf_unfiltered (_("\"maintenance undeprecate\" takes an argument, \n\
|
||
the command you want to undeprecate.\n"));
|
||
}
|
||
|
||
maintenance_do_deprecate (args, 0);
|
||
|
||
}
|
||
|
||
/* You really shouldn't be using this. It is just for the testsuite.
|
||
Rather, you should use deprecate_cmd() when the command is created
|
||
in _initialize_blah().
|
||
|
||
This function deprecates a command and optionally assigns it a
|
||
replacement. */
|
||
|
||
static void
|
||
maintenance_do_deprecate (char *text, int deprecate)
|
||
{
|
||
struct cmd_list_element *alias = NULL;
|
||
struct cmd_list_element *prefix_cmd = NULL;
|
||
struct cmd_list_element *cmd = NULL;
|
||
|
||
char *start_ptr = NULL;
|
||
char *end_ptr = NULL;
|
||
int len;
|
||
char *replacement = NULL;
|
||
|
||
if (text == NULL)
|
||
return;
|
||
|
||
if (!lookup_cmd_composition (text, &alias, &prefix_cmd, &cmd))
|
||
{
|
||
printf_filtered (_("Can't find command '%s' to deprecate.\n"), text);
|
||
return;
|
||
}
|
||
|
||
if (deprecate)
|
||
{
|
||
/* Look for a replacement command. */
|
||
start_ptr = strchr (text, '\"');
|
||
if (start_ptr != NULL)
|
||
{
|
||
start_ptr++;
|
||
end_ptr = strrchr (start_ptr, '\"');
|
||
if (end_ptr != NULL)
|
||
{
|
||
len = end_ptr - start_ptr;
|
||
start_ptr[len] = '\0';
|
||
replacement = xstrdup (start_ptr);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!start_ptr || !end_ptr)
|
||
replacement = NULL;
|
||
|
||
|
||
/* If they used an alias, we only want to deprecate the alias.
|
||
|
||
Note the MALLOCED_REPLACEMENT test. If the command's replacement
|
||
string was allocated at compile time we don't want to free the
|
||
memory. */
|
||
if (alias)
|
||
{
|
||
if (alias->malloced_replacement)
|
||
xfree ((char *) alias->replacement);
|
||
|
||
if (deprecate)
|
||
{
|
||
alias->deprecated_warn_user = 1;
|
||
alias->cmd_deprecated = 1;
|
||
}
|
||
else
|
||
{
|
||
alias->deprecated_warn_user = 0;
|
||
alias->cmd_deprecated = 0;
|
||
}
|
||
alias->replacement = replacement;
|
||
alias->malloced_replacement = 1;
|
||
return;
|
||
}
|
||
else if (cmd)
|
||
{
|
||
if (cmd->malloced_replacement)
|
||
xfree ((char *) cmd->replacement);
|
||
|
||
if (deprecate)
|
||
{
|
||
cmd->deprecated_warn_user = 1;
|
||
cmd->cmd_deprecated = 1;
|
||
}
|
||
else
|
||
{
|
||
cmd->deprecated_warn_user = 0;
|
||
cmd->cmd_deprecated = 0;
|
||
}
|
||
cmd->replacement = replacement;
|
||
cmd->malloced_replacement = 1;
|
||
return;
|
||
}
|
||
xfree (replacement);
|
||
}
|
||
|
||
/* Maintenance set/show framework. */
|
||
|
||
struct cmd_list_element *maintenance_set_cmdlist;
|
||
struct cmd_list_element *maintenance_show_cmdlist;
|
||
|
||
static void
|
||
maintenance_set_cmd (char *args, int from_tty)
|
||
{
|
||
printf_unfiltered (_("\"maintenance set\" must be followed "
|
||
"by the name of a set command.\n"));
|
||
help_list (maintenance_set_cmdlist, "maintenance set ", all_commands,
|
||
gdb_stdout);
|
||
}
|
||
|
||
static void
|
||
maintenance_show_cmd (char *args, int from_tty)
|
||
{
|
||
cmd_show_list (maintenance_show_cmdlist, from_tty, "");
|
||
}
|
||
|
||
/* Profiling support. */
|
||
|
||
static int maintenance_profile_p;
|
||
static void
|
||
show_maintenance_profile_p (struct ui_file *file, int from_tty,
|
||
struct cmd_list_element *c, const char *value)
|
||
{
|
||
fprintf_filtered (file, _("Internal profiling is %s.\n"), value);
|
||
}
|
||
|
||
#ifdef HAVE__ETEXT
|
||
extern char _etext;
|
||
#define TEXTEND &_etext
|
||
#elif defined (HAVE_ETEXT)
|
||
extern char etext;
|
||
#define TEXTEND &etext
|
||
#endif
|
||
|
||
#if defined (HAVE_MONSTARTUP) && defined (HAVE__MCLEANUP) && defined (TEXTEND)
|
||
|
||
static int profiling_state;
|
||
|
||
EXTERN_C void _mcleanup (void);
|
||
|
||
static void
|
||
mcleanup_wrapper (void)
|
||
{
|
||
if (profiling_state)
|
||
_mcleanup ();
|
||
}
|
||
|
||
EXTERN_C void monstartup (unsigned long, unsigned long);
|
||
extern int main ();
|
||
|
||
static void
|
||
maintenance_set_profile_cmd (char *args, int from_tty,
|
||
struct cmd_list_element *c)
|
||
{
|
||
if (maintenance_profile_p == profiling_state)
|
||
return;
|
||
|
||
profiling_state = maintenance_profile_p;
|
||
|
||
if (maintenance_profile_p)
|
||
{
|
||
static int profiling_initialized;
|
||
|
||
if (!profiling_initialized)
|
||
{
|
||
atexit (mcleanup_wrapper);
|
||
profiling_initialized = 1;
|
||
}
|
||
|
||
/* "main" is now always the first function in the text segment, so use
|
||
its address for monstartup. */
|
||
monstartup ((unsigned long) &main, (unsigned long) TEXTEND);
|
||
}
|
||
else
|
||
{
|
||
extern void _mcleanup (void);
|
||
|
||
_mcleanup ();
|
||
}
|
||
}
|
||
#else
|
||
static void
|
||
maintenance_set_profile_cmd (char *args, int from_tty,
|
||
struct cmd_list_element *c)
|
||
{
|
||
error (_("Profiling support is not available on this system."));
|
||
}
|
||
#endif
|
||
|
||
/* If nonzero, display time usage both at startup and for each command. */
|
||
|
||
static int per_command_time;
|
||
|
||
/* If nonzero, display space usage both at startup and for each command. */
|
||
|
||
static int per_command_space;
|
||
|
||
/* If nonzero, display basic symtab stats for each command. */
|
||
|
||
static int per_command_symtab;
|
||
|
||
/* mt per-command commands. */
|
||
|
||
static struct cmd_list_element *per_command_setlist;
|
||
static struct cmd_list_element *per_command_showlist;
|
||
|
||
/* Set whether to display time statistics to NEW_VALUE
|
||
(non-zero means true). */
|
||
|
||
void
|
||
set_per_command_time (int new_value)
|
||
{
|
||
per_command_time = new_value;
|
||
}
|
||
|
||
/* Set whether to display space statistics to NEW_VALUE
|
||
(non-zero means true). */
|
||
|
||
void
|
||
set_per_command_space (int new_value)
|
||
{
|
||
per_command_space = new_value;
|
||
}
|
||
|
||
/* Count the number of symtabs and blocks. */
|
||
|
||
static void
|
||
count_symtabs_and_blocks (int *nr_symtabs_ptr, int *nr_compunit_symtabs_ptr,
|
||
int *nr_blocks_ptr)
|
||
{
|
||
struct objfile *o;
|
||
struct compunit_symtab *cu;
|
||
struct symtab *s;
|
||
int nr_symtabs = 0;
|
||
int nr_compunit_symtabs = 0;
|
||
int nr_blocks = 0;
|
||
|
||
/* When collecting statistics during startup, this is called before
|
||
pretty much anything in gdb has been initialized, and thus
|
||
current_program_space may be NULL. */
|
||
if (current_program_space != NULL)
|
||
{
|
||
ALL_COMPUNITS (o, cu)
|
||
{
|
||
++nr_compunit_symtabs;
|
||
nr_blocks += BLOCKVECTOR_NBLOCKS (COMPUNIT_BLOCKVECTOR (cu));
|
||
ALL_COMPUNIT_FILETABS (cu, s)
|
||
++nr_symtabs;
|
||
}
|
||
}
|
||
|
||
*nr_symtabs_ptr = nr_symtabs;
|
||
*nr_compunit_symtabs_ptr = nr_compunit_symtabs;
|
||
*nr_blocks_ptr = nr_blocks;
|
||
}
|
||
|
||
/* As indicated by display_time and display_space, report GDB's
|
||
elapsed time and space usage from the base time and space recorded
|
||
in this object. */
|
||
|
||
scoped_command_stats::~scoped_command_stats ()
|
||
{
|
||
/* Early exit if we're not reporting any stats. It can be expensive to
|
||
compute the pre-command values so don't collect them at all if we're
|
||
not reporting stats. Alas this doesn't work in the startup case because
|
||
we don't know yet whether we will be reporting the stats. For the
|
||
startup case collect the data anyway (it should be cheap at this point),
|
||
and leave it to the reporter to decide whether to print them. */
|
||
if (m_msg_type
|
||
&& !per_command_time
|
||
&& !per_command_space
|
||
&& !per_command_symtab)
|
||
return;
|
||
|
||
if (m_time_enabled && per_command_time)
|
||
{
|
||
using namespace std::chrono;
|
||
|
||
run_time_clock::duration cmd_time
|
||
= run_time_clock::now () - m_start_cpu_time;
|
||
|
||
steady_clock::duration wall_time
|
||
= steady_clock::now () - m_start_wall_time;
|
||
/* Subtract time spend in prompt_for_continue from walltime. */
|
||
wall_time -= get_prompt_for_continue_wait_time ();
|
||
|
||
printf_unfiltered (!m_msg_type
|
||
? _("Startup time: %.6f (cpu), %.6f (wall)\n")
|
||
: _("Command execution time: %.6f (cpu), %.6f (wall)\n"),
|
||
duration<double> (cmd_time).count (),
|
||
duration<double> (wall_time).count ());
|
||
}
|
||
|
||
if (m_space_enabled && per_command_space)
|
||
{
|
||
#ifdef HAVE_SBRK
|
||
char *lim = (char *) sbrk (0);
|
||
|
||
long space_now = lim - lim_at_start;
|
||
long space_diff = space_now - m_start_space;
|
||
|
||
printf_unfiltered (!m_msg_type
|
||
? _("Space used: %ld (%s%ld during startup)\n")
|
||
: _("Space used: %ld (%s%ld for this command)\n"),
|
||
space_now,
|
||
(space_diff >= 0 ? "+" : ""),
|
||
space_diff);
|
||
#endif
|
||
}
|
||
|
||
if (m_symtab_enabled && per_command_symtab)
|
||
{
|
||
int nr_symtabs, nr_compunit_symtabs, nr_blocks;
|
||
|
||
count_symtabs_and_blocks (&nr_symtabs, &nr_compunit_symtabs, &nr_blocks);
|
||
printf_unfiltered (_("#symtabs: %d (+%d),"
|
||
" #compunits: %d (+%d),"
|
||
" #blocks: %d (+%d)\n"),
|
||
nr_symtabs,
|
||
nr_symtabs - m_start_nr_symtabs,
|
||
nr_compunit_symtabs,
|
||
(nr_compunit_symtabs
|
||
- m_start_nr_compunit_symtabs),
|
||
nr_blocks,
|
||
nr_blocks - m_start_nr_blocks);
|
||
}
|
||
}
|
||
|
||
scoped_command_stats::scoped_command_stats (bool msg_type)
|
||
: m_msg_type (msg_type)
|
||
{
|
||
if (!m_msg_type || per_command_space)
|
||
{
|
||
#ifdef HAVE_SBRK
|
||
char *lim = (char *) sbrk (0);
|
||
m_start_space = lim - lim_at_start;
|
||
m_space_enabled = 1;
|
||
#endif
|
||
}
|
||
else
|
||
m_space_enabled = 0;
|
||
|
||
if (msg_type == 0 || per_command_time)
|
||
{
|
||
using namespace std::chrono;
|
||
|
||
m_start_cpu_time = run_time_clock::now ();
|
||
m_start_wall_time = steady_clock::now ();
|
||
m_time_enabled = 1;
|
||
}
|
||
else
|
||
m_time_enabled = 0;
|
||
|
||
if (msg_type == 0 || per_command_symtab)
|
||
{
|
||
int nr_symtabs, nr_compunit_symtabs, nr_blocks;
|
||
|
||
count_symtabs_and_blocks (&nr_symtabs, &nr_compunit_symtabs, &nr_blocks);
|
||
m_start_nr_symtabs = nr_symtabs;
|
||
m_start_nr_compunit_symtabs = nr_compunit_symtabs;
|
||
m_start_nr_blocks = nr_blocks;
|
||
m_symtab_enabled = 1;
|
||
}
|
||
else
|
||
m_symtab_enabled = 0;
|
||
|
||
/* Initialize timer to keep track of how long we waited for the user. */
|
||
reset_prompt_for_continue_wait_time ();
|
||
}
|
||
|
||
/* Handle unknown "mt set per-command" arguments.
|
||
In this case have "mt set per-command on|off" affect every setting. */
|
||
|
||
static void
|
||
set_per_command_cmd (char *args, int from_tty)
|
||
{
|
||
struct cmd_list_element *list;
|
||
int val;
|
||
|
||
val = parse_cli_boolean_value (args);
|
||
if (val < 0)
|
||
error (_("Bad value for 'mt set per-command no'."));
|
||
|
||
for (list = per_command_setlist; list != NULL; list = list->next)
|
||
if (list->var_type == var_boolean)
|
||
{
|
||
gdb_assert (list->type == set_cmd);
|
||
do_set_command (args, from_tty, list);
|
||
}
|
||
}
|
||
|
||
/* Command "show per-command" displays summary of all the current
|
||
"show per-command " settings. */
|
||
|
||
static void
|
||
show_per_command_cmd (char *args, int from_tty)
|
||
{
|
||
cmd_show_list (per_command_showlist, from_tty, "");
|
||
}
|
||
|
||
|
||
/* The "maintenance selftest" command. */
|
||
|
||
static void
|
||
maintenance_selftest (char *args, int from_tty)
|
||
{
|
||
run_self_tests ();
|
||
}
|
||
|
||
|
||
void
|
||
_initialize_maint_cmds (void)
|
||
{
|
||
struct cmd_list_element *cmd;
|
||
|
||
add_prefix_cmd ("maintenance", class_maintenance, maintenance_command, _("\
|
||
Commands for use by GDB maintainers.\n\
|
||
Includes commands to dump specific internal GDB structures in\n\
|
||
a human readable form, to cause GDB to deliberately dump core, etc."),
|
||
&maintenancelist, "maintenance ", 0,
|
||
&cmdlist);
|
||
|
||
add_com_alias ("mt", "maintenance", class_maintenance, 1);
|
||
|
||
add_prefix_cmd ("info", class_maintenance, maintenance_info_command, _("\
|
||
Commands for showing internal info about the program being debugged."),
|
||
&maintenanceinfolist, "maintenance info ", 0,
|
||
&maintenancelist);
|
||
add_alias_cmd ("i", "info", class_maintenance, 1, &maintenancelist);
|
||
|
||
add_cmd ("sections", class_maintenance, maintenance_info_sections, _("\
|
||
List the BFD sections of the exec and core files. \n\
|
||
Arguments may be any combination of:\n\
|
||
[one or more section names]\n\
|
||
ALLOC LOAD RELOC READONLY CODE DATA ROM CONSTRUCTOR\n\
|
||
HAS_CONTENTS NEVER_LOAD COFF_SHARED_LIBRARY IS_COMMON\n\
|
||
Sections matching any argument will be listed (no argument\n\
|
||
implies all sections). In addition, the special argument\n\
|
||
ALLOBJ\n\
|
||
lists all sections from all object files, including shared libraries."),
|
||
&maintenanceinfolist);
|
||
|
||
add_prefix_cmd ("print", class_maintenance, maintenance_print_command,
|
||
_("Maintenance command for printing GDB internal state."),
|
||
&maintenanceprintlist, "maintenance print ", 0,
|
||
&maintenancelist);
|
||
|
||
add_prefix_cmd ("set", class_maintenance, maintenance_set_cmd, _("\
|
||
Set GDB internal variables used by the GDB maintainer.\n\
|
||
Configure variables internal to GDB that aid in GDB's maintenance"),
|
||
&maintenance_set_cmdlist, "maintenance set ",
|
||
0/*allow-unknown*/,
|
||
&maintenancelist);
|
||
|
||
add_prefix_cmd ("show", class_maintenance, maintenance_show_cmd, _("\
|
||
Show GDB internal variables used by the GDB maintainer.\n\
|
||
Configure variables internal to GDB that aid in GDB's maintenance"),
|
||
&maintenance_show_cmdlist, "maintenance show ",
|
||
0/*allow-unknown*/,
|
||
&maintenancelist);
|
||
|
||
#ifndef _WIN32
|
||
add_cmd ("dump-me", class_maintenance, maintenance_dump_me, _("\
|
||
Get fatal error; make debugger dump its core.\n\
|
||
GDB sets its handling of SIGQUIT back to SIG_DFL and then sends\n\
|
||
itself a SIGQUIT signal."),
|
||
&maintenancelist);
|
||
#endif
|
||
|
||
add_cmd ("internal-error", class_maintenance,
|
||
maintenance_internal_error, _("\
|
||
Give GDB an internal error.\n\
|
||
Cause GDB to behave as if an internal error was detected."),
|
||
&maintenancelist);
|
||
|
||
add_cmd ("internal-warning", class_maintenance,
|
||
maintenance_internal_warning, _("\
|
||
Give GDB an internal warning.\n\
|
||
Cause GDB to behave as if an internal warning was reported."),
|
||
&maintenancelist);
|
||
|
||
add_cmd ("demangler-warning", class_maintenance,
|
||
maintenance_demangler_warning, _("\
|
||
Give GDB a demangler warning.\n\
|
||
Cause GDB to behave as if a demangler warning was reported."),
|
||
&maintenancelist);
|
||
|
||
cmd = add_cmd ("demangle", class_maintenance, maintenance_demangle, _("\
|
||
This command has been moved to \"demangle\"."),
|
||
&maintenancelist);
|
||
deprecate_cmd (cmd, "demangle");
|
||
|
||
add_prefix_cmd ("per-command", class_maintenance, set_per_command_cmd, _("\
|
||
Per-command statistics settings."),
|
||
&per_command_setlist, "set per-command ",
|
||
1/*allow-unknown*/, &maintenance_set_cmdlist);
|
||
|
||
add_prefix_cmd ("per-command", class_maintenance, show_per_command_cmd, _("\
|
||
Show per-command statistics settings."),
|
||
&per_command_showlist, "show per-command ",
|
||
0/*allow-unknown*/, &maintenance_show_cmdlist);
|
||
|
||
add_setshow_boolean_cmd ("time", class_maintenance,
|
||
&per_command_time, _("\
|
||
Set whether to display per-command execution time."), _("\
|
||
Show whether to display per-command execution time."),
|
||
_("\
|
||
If enabled, the execution time for each command will be\n\
|
||
displayed following the command's output."),
|
||
NULL, NULL,
|
||
&per_command_setlist, &per_command_showlist);
|
||
|
||
add_setshow_boolean_cmd ("space", class_maintenance,
|
||
&per_command_space, _("\
|
||
Set whether to display per-command space usage."), _("\
|
||
Show whether to display per-command space usage."),
|
||
_("\
|
||
If enabled, the space usage for each command will be\n\
|
||
displayed following the command's output."),
|
||
NULL, NULL,
|
||
&per_command_setlist, &per_command_showlist);
|
||
|
||
add_setshow_boolean_cmd ("symtab", class_maintenance,
|
||
&per_command_symtab, _("\
|
||
Set whether to display per-command symtab statistics."), _("\
|
||
Show whether to display per-command symtab statistics."),
|
||
_("\
|
||
If enabled, the basic symtab statistics for each command will be\n\
|
||
displayed following the command's output."),
|
||
NULL, NULL,
|
||
&per_command_setlist, &per_command_showlist);
|
||
|
||
/* This is equivalent to "mt set per-command time on".
|
||
Kept because some people are used to typing "mt time 1". */
|
||
add_cmd ("time", class_maintenance, maintenance_time_display, _("\
|
||
Set the display of time usage.\n\
|
||
If nonzero, will cause the execution time for each command to be\n\
|
||
displayed, following the command's output."),
|
||
&maintenancelist);
|
||
|
||
/* This is equivalent to "mt set per-command space on".
|
||
Kept because some people are used to typing "mt space 1". */
|
||
add_cmd ("space", class_maintenance, maintenance_space_display, _("\
|
||
Set the display of space usage.\n\
|
||
If nonzero, will cause the execution space for each command to be\n\
|
||
displayed, following the command's output."),
|
||
&maintenancelist);
|
||
|
||
add_cmd ("type", class_maintenance, maintenance_print_type, _("\
|
||
Print a type chain for a given symbol.\n\
|
||
For each node in a type chain, print the raw data for each member of\n\
|
||
the type structure, and the interpretation of the data."),
|
||
&maintenanceprintlist);
|
||
|
||
add_cmd ("statistics", class_maintenance, maintenance_print_statistics,
|
||
_("Print statistics about internal gdb state."),
|
||
&maintenanceprintlist);
|
||
|
||
add_cmd ("architecture", class_maintenance,
|
||
maintenance_print_architecture, _("\
|
||
Print the internal architecture configuration.\n\
|
||
Takes an optional file parameter."),
|
||
&maintenanceprintlist);
|
||
|
||
add_cmd ("translate-address", class_maintenance,
|
||
maintenance_translate_address,
|
||
_("Translate a section name and address to a symbol."),
|
||
&maintenancelist);
|
||
|
||
add_cmd ("deprecate", class_maintenance, maintenance_deprecate, _("\
|
||
Deprecate a command. Note that this is just in here so the \n\
|
||
testsuite can check the command deprecator. You probably shouldn't use this,\n\
|
||
rather you should use the C function deprecate_cmd(). If you decide you \n\
|
||
want to use it: maintenance deprecate 'commandname' \"replacement\". The \n\
|
||
replacement is optional."), &maintenancelist);
|
||
|
||
add_cmd ("undeprecate", class_maintenance, maintenance_undeprecate, _("\
|
||
Undeprecate a command. Note that this is just in here so the \n\
|
||
testsuite can check the command deprecator. You probably shouldn't use this,\n\
|
||
If you decide you want to use it: maintenance undeprecate 'commandname'"),
|
||
&maintenancelist);
|
||
|
||
add_cmd ("selftest", class_maintenance, maintenance_selftest, _("\
|
||
Run gdb's unit tests.\n\
|
||
Usage: maintenance selftest\n\
|
||
This will run any unit tests that were built in to gdb.\n\
|
||
gdb will abort if any test fails."),
|
||
&maintenancelist);
|
||
|
||
add_setshow_zinteger_cmd ("watchdog", class_maintenance, &watchdog, _("\
|
||
Set watchdog timer."), _("\
|
||
Show watchdog timer."), _("\
|
||
When non-zero, this timeout is used instead of waiting forever for a target\n\
|
||
to finish a low-level step or continue operation. If the specified amount\n\
|
||
of time passes without a response from the target, an error occurs."),
|
||
NULL,
|
||
show_watchdog,
|
||
&setlist, &showlist);
|
||
|
||
add_setshow_boolean_cmd ("profile", class_maintenance,
|
||
&maintenance_profile_p, _("\
|
||
Set internal profiling."), _("\
|
||
Show internal profiling."), _("\
|
||
When enabled GDB is profiled."),
|
||
maintenance_set_profile_cmd,
|
||
show_maintenance_profile_p,
|
||
&maintenance_set_cmdlist,
|
||
&maintenance_show_cmdlist);
|
||
}
|