diff options
Diffstat (limited to 'gdb')
70 files changed, 1103 insertions, 542 deletions
diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 8f6df5b..6203bcf 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -1912,8 +1912,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ $(patsubst %.c,%.o,$(COMMON_SFILES)) \ $(SUBDIR_CLI_OBS) \ $(SUBDIR_MI_OBS) \ - $(SUBDIR_TARGET_OBS) \ - $(SUBDIR_GCC_COMPILE_OBS) + $(SUBDIR_TARGET_OBS) SUBDIRS = doc @subdirs@ data-directory CLEANDIRS = $(SUBDIRS) @@ -3,6 +3,10 @@ *** Changes since GDB 16 +* Debugger Adapter Protocol changes + + ** GDB now supports the "completions" request. + * "set style" commands now supports numeric format for basic colors from 0 to 255 and #RRGGBB format for TrueColor. @@ -108,6 +112,10 @@ qXfer:threads:read * Support for stabs debugging format and the a.out/dbx object format is deprecated, and will be removed in GDB 18. +* A new configure option was added, allowing support for the compile + subsystem to be disabled at configure time, in the form of + --disable-gdb-compile. + *** Changes in GDB 16 * Support for Nios II targets has been removed as this architecture @@ -442,6 +442,9 @@ more obscure GDB `configure' options are not listed here. Requires a curses library (ncurses and cursesX are also supported). +`--disable-gdb-compile' + Build GDB without support for the 'compile' command. + `--with-curses' Use the curses library instead of the termcap library, for text-mode terminal operations. diff --git a/gdb/arm-pikeos-tdep.c b/gdb/arm-pikeos-tdep.c index 4760755..b2c93bd 100644 --- a/gdb/arm-pikeos-tdep.c +++ b/gdb/arm-pikeos-tdep.c @@ -36,8 +36,6 @@ arm_pikeos_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) static enum gdb_osabi arm_pikeos_osabi_sniffer (bfd *abfd) { - long number_of_symbols; - long i; int pikeos_stack_found = 0; int pikeos_stack_size_found = 0; @@ -50,20 +48,15 @@ arm_pikeos_osabi_sniffer (bfd *abfd) OS ABI sniffers are called before the minimal symtabs are created. So inspect the symbol table using BFD. */ - long storage_needed = bfd_get_symtab_upper_bound (abfd); - if (storage_needed <= 0) - return GDB_OSABI_UNKNOWN; - - gdb::unique_xmalloc_ptr<asymbol *> symbol_table - ((asymbol **) xmalloc (storage_needed)); - number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table.get ()); + gdb::array_view<asymbol *> symbol_table + = gdb_bfd_canonicalize_symtab (abfd, false); - if (number_of_symbols <= 0) + if (symbol_table.empty ()) return GDB_OSABI_UNKNOWN; - for (i = 0; i < number_of_symbols; i++) + for (const asymbol *sym : symbol_table) { - const char *name = bfd_asymbol_name (symbol_table.get ()[i]); + const char *name = bfd_asymbol_name (sym); if (strcmp (name, "_vm_stack") == 0 || strcmp (name, "__p4_stack") == 0) diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 3085ca1..0fb6fd9 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -1535,6 +1535,11 @@ void breakpoint_set_commands (struct breakpoint *b, counted_command_line &&commands) { + /* If the commands have not changed then there's no need to update + anything, and no need to emit a breakpoint modified event. */ + if (commands_equal (b->commands.get (), commands.get ())) + return; + validate_commands_for_breakpoint (b, commands.get ()); b->commands = std::move (commands); @@ -3099,7 +3104,6 @@ insert_bp_location (struct bp_location *bl, || shared_objfile_contains_address_p (bl->pspace, bl->address))) { - /* See also: disable_breakpoints_in_shlibs. */ bl->shlib_disabled = 1; notify_breakpoint_modified (bl->owner); if (!*disabled_breaks) @@ -8079,44 +8083,19 @@ create_and_insert_solib_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR add return b; } -/* See breakpoint.h. */ - -void -disable_breakpoints_in_shlibs (program_space *pspace) -{ - for (bp_location *loc : all_bp_locations ()) - { - /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always non-NULL. */ - struct breakpoint *b = loc->owner; - - /* We apply the check to all breakpoints, including disabled for - those with loc->duplicate set. This is so that when breakpoint - becomes enabled, or the duplicate is removed, gdb will try to - insert all breakpoints. If we don't set shlib_disabled here, - we'll try to insert those breakpoints and fail. */ - if (((b->type == bp_jit_event) - || is_breakpoint (b) - || is_tracepoint (b)) - && loc->pspace == pspace - && !loc->shlib_disabled - && solib_name_from_address (loc->pspace, loc->address) - ) - { - loc->shlib_disabled = 1; - } - } -} - /* Disable any breakpoints and tracepoints that are in SOLIB upon notification of unloaded_shlib. Only apply to enabled breakpoints, disabled ones can just stay disabled. When STILL_IN_USE is true, SOLIB hasn't really been unmapped from - the inferior. In this case, don't disable anything. */ + the inferior. In this case, don't disable anything. + + When SILENT is false notify the user if any breakpoints are disabled, + otherwise, still disable the breakpoints, but don't tell the user. */ static void disable_breakpoints_in_unloaded_shlib (program_space *pspace, const solib &solib, - bool still_in_use) + bool still_in_use, bool silent) { if (still_in_use) return; @@ -8160,7 +8139,7 @@ disable_breakpoints_in_unloaded_shlib (program_space *pspace, const solib &solib bp_modified = true; - if (!disabled_shlib_breaks && user_breakpoint_p (&b)) + if (!disabled_shlib_breaks && !silent && user_breakpoint_p (&b)) { target_terminal::ours_for_output (); warning (_("Temporarily disabling breakpoints " diff --git a/gdb/bsd-uthread.c b/gdb/bsd-uthread.c index 67db0ca..129e7a6 100644 --- a/gdb/bsd-uthread.c +++ b/gdb/bsd-uthread.c @@ -295,7 +295,7 @@ bsd_uthread_solib_loaded (solib &so) static void bsd_uthread_solib_unloaded (program_space *pspace, const solib &so, - bool still_in_use) + bool still_in_use, bool /* silent */) { if (bsd_uthread_solib_name.empty () || still_in_use) return; diff --git a/gdb/c-lang.c b/gdb/c-lang.c index c28493f..5592234 100644 --- a/gdb/c-lang.c +++ b/gdb/c-lang.c @@ -807,22 +807,6 @@ public: } /* See language.h. */ - std::unique_ptr<compile_instance> get_compile_instance () const override - { - return c_get_compile_context (); - } - - /* See language.h. */ - std::string compute_program (compile_instance *inst, - const char *input, - struct gdbarch *gdbarch, - const struct block *expr_block, - CORE_ADDR expr_pc) const override - { - return c_compute_program (inst, input, gdbarch, expr_block, expr_pc); - } - - /* See language.h. */ bool can_print_type_offsets () const override { @@ -943,22 +927,6 @@ public: } /* See language.h. */ - std::unique_ptr<compile_instance> get_compile_instance () const override - { - return cplus_get_compile_context (); - } - - /* See language.h. */ - std::string compute_program (compile_instance *inst, - const char *input, - struct gdbarch *gdbarch, - const struct block *expr_block, - CORE_ADDR expr_pc) const override - { - return cplus_compute_program (inst, input, gdbarch, expr_block, expr_pc); - } - - /* See language.h. */ unsigned int search_name_hash (const char *name) const override { return cp_search_name_hash (name); diff --git a/gdb/c-lang.h b/gdb/c-lang.h index 0e733d8..06b7ad0 100644 --- a/gdb/c-lang.h +++ b/gdb/c-lang.h @@ -25,7 +25,6 @@ struct ui_file; struct language_arch_info; struct type_print_options; struct parser_state; -struct compile_instance; #include "compile/compile.h" #include "value.h" @@ -132,43 +131,6 @@ extern bool c_is_string_type_p (struct type *type); extern int c_textual_element_type (struct type *, char); -/* Create a new instance of the C compiler and return it. This - function never returns NULL, but rather throws an exception on - failure. This is suitable for use as the - language_defn::get_compile_instance method. */ - -extern std::unique_ptr<compile_instance> c_get_compile_context (); - -/* Create a new instance of the C++ compiler and return it. This - function never returns NULL, but rather throws an exception on - failure. This is suitable for use as the - language_defn::get_compile_instance method. */ - -extern std::unique_ptr<compile_instance> cplus_get_compile_context (); - -/* This takes the user-supplied text and returns a new bit of code to - compile. - - This is used as the compute_program language method; see that - for a description of the arguments. */ - -extern std::string c_compute_program (compile_instance *inst, - const char *input, - struct gdbarch *gdbarch, - const struct block *expr_block, - CORE_ADDR expr_pc); - -/* This takes the user-supplied text and returns a new bit of code to compile. - - This is used as the compute_program language method; see that - for a description of the arguments. */ - -extern std::string cplus_compute_program (compile_instance *inst, - const char *input, - struct gdbarch *gdbarch, - const struct block *expr_block, - CORE_ADDR expr_pc); - /* Return the canonical form of the C symbol NAME. If NAME is already canonical, return nullptr. */ diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c index 5decf3b..0337d01 100644 --- a/gdb/cli/cli-script.c +++ b/gdb/cli/cli-script.c @@ -660,9 +660,13 @@ execute_control_command_1 (struct command_line *cmd, int from_tty) } case compile_control: +#if defined(HAVE_COMPILE) eval_compile_command (cmd, NULL, cmd->control_u.compile.scope, cmd->control_u.compile.scope_data); ret = simple_control; +#else + error (_("compile support has not been compiled into gdb")); +#endif break; case define_control: @@ -1621,6 +1625,65 @@ define_prefix_command (const char *comname, int from_tty) c->allow_unknown = c->user_commands.get () != nullptr; } +/* See cli/cli-script.h. */ + +bool +commands_equal (const command_line *a, const command_line *b) +{ + if ((a == nullptr) != (b == nullptr)) + return false; + + while (a != nullptr) + { + /* We are either at the end of both command lists, or there's + another command in both lists. */ + if ((a->next == nullptr) != (b->next == nullptr)) + return false; + + /* There's a command line for both, or neither. */ + if ((a->line == nullptr) != (b->line == nullptr)) + return false; + + /* Check control_type matches. */ + if (a->control_type != b->control_type) + return false; + + if (a->control_type == compile_control) + { + if (a->control_u.compile.scope != b->control_u.compile.scope) + return false; + + /* This is where we "fail safe". The scope_data is a 'void *' + pointer which changes in meaning based on the value of + 'scope'. It is possible that two different 'void *' pointers + could point to the equal scope data, however, we just assume + that if the pointers are different, then the scope_data is + different. This could be improved in the future. */ + if (a->control_u.compile.scope_data + != b->control_u.compile.scope_data) + return false; + } + + /* Check lines are identical. */ + if (a->line != nullptr && strcmp (a->line, b->line) != 0) + return false; + + /* Check body_list_0. */ + if (!commands_equal (a->body_list_0.get (), b->body_list_0.get ())) + return false; + + /* Check body_list_1. */ + if (!commands_equal (a->body_list_1.get (), b->body_list_1.get ())) + return false; + + /* Move to the next element in each chain. */ + a = a->next; + b = b->next; + } + + return true; +} + /* Used to implement source_command. */ diff --git a/gdb/cli/cli-script.h b/gdb/cli/cli-script.h index df7316e..23a1e1f 100644 --- a/gdb/cli/cli-script.h +++ b/gdb/cli/cli-script.h @@ -184,4 +184,14 @@ extern void print_command_trace (const char *cmd, ...) extern void reset_command_nest_depth (void); +/* Return true if A and B are identical. Some commands carry around a + 'void *' compilation context, in this case this function doesn't try to + validate if the context is actually the same or not, and will just + return false indicating the commands have changed. That is, a return + value of true is a guarantee that the commands are equal, a return + value of false means the commands are possibly different (and in most + cases are different). */ + +extern bool commands_equal (const command_line *a, const command_line *b); + #endif /* GDB_CLI_CLI_SCRIPT_H */ diff --git a/gdb/compile/compile-internal.h b/gdb/compile/compile-internal.h index f4cc9ee..789782d 100644 --- a/gdb/compile/compile-internal.h +++ b/gdb/compile/compile-internal.h @@ -80,4 +80,43 @@ private: std::string m_object_file; }; +struct compile_instance; + +/* Create a new instance of the C compiler and return it. This + function never returns NULL, but rather throws an exception on + failure. This is suitable for use as the + language_defn::get_compile_instance method. */ + +extern std::unique_ptr<compile_instance> c_get_compile_context (); + +/* Create a new instance of the C++ compiler and return it. This + function never returns NULL, but rather throws an exception on + failure. This is suitable for use as the + language_defn::get_compile_instance method. */ + +extern std::unique_ptr<compile_instance> cplus_get_compile_context (); + +/* This takes the user-supplied text and returns a new bit of code to + compile. + + This is used as the compute_program language method; see that + for a description of the arguments. */ + +extern std::string c_compute_program (compile_instance *inst, + const char *input, + struct gdbarch *gdbarch, + const struct block *expr_block, + CORE_ADDR expr_pc); + +/* This takes the user-supplied text and returns a new bit of code to compile. + + This is used as the compute_program language method; see that + for a description of the arguments. */ + +extern std::string cplus_compute_program (compile_instance *inst, + const char *input, + struct gdbarch *gdbarch, + const struct block *expr_block, + CORE_ADDR expr_pc); + #endif /* GDB_COMPILE_COMPILE_INTERNAL_H */ diff --git a/gdb/compile/compile-object-load.c b/gdb/compile/compile-object-load.c index ef77ee3..05e5b43 100644 --- a/gdb/compile/compile-object-load.c +++ b/gdb/compile/compile-object-load.c @@ -605,9 +605,7 @@ compile_object_load (const compile_file_names &file_names, CORE_ADDR regs_addr, out_value_addr = 0; struct symbol *func_sym; struct type *func_type; - long storage_needed; - asymbol **symbol_table, **symp; - long number_of_symbols, missing_symbols; + long missing_symbols; struct type *regs_type, *out_value_type = NULL; char **matching; struct objfile *objfile; @@ -635,11 +633,6 @@ compile_object_load (const compile_file_names &file_names, setup_sections_data.setup_one_section (sect); setup_sections_data.setup_one_section (nullptr); - storage_needed = bfd_get_symtab_upper_bound (abfd.get ()); - if (storage_needed < 0) - error (_("Cannot read symbols of compiled module \"%s\": %s"), - filename.get (), bfd_errmsg (bfd_get_error ())); - /* SYMFILE_VERBOSE is not passed even if FROM_TTY, user is not interested in "Reading symbols from ..." message for automatically generated file. */ scoped_objfile_unlinker objfile_holder (symbol_file_add_from_bfd @@ -692,21 +685,12 @@ compile_object_load (const compile_file_names &file_names, "module \"%s\"."), GCC_FE_WRAPPER_FUNCTION, objfile_name (objfile)); - /* The memory may be later needed - by bfd_generic_get_relocated_section_contents - called from default_symfile_relocate. */ - symbol_table = (asymbol **) obstack_alloc (&objfile->objfile_obstack, - storage_needed); - number_of_symbols = bfd_canonicalize_symtab (abfd.get (), symbol_table); - if (number_of_symbols < 0) - error (_("Cannot parse symbols of compiled module \"%s\": %s"), - filename.get (), bfd_errmsg (bfd_get_error ())); + gdb::array_view<asymbol *> symbol_table + = gdb_bfd_canonicalize_symtab (abfd.get ()); missing_symbols = 0; - for (symp = symbol_table; symp < symbol_table + number_of_symbols; symp++) + for (asymbol *sym : symbol_table) { - asymbol *sym = *symp; - if (sym->flags != 0) continue; sym->flags = BSF_GLOBAL; @@ -800,7 +784,7 @@ compile_object_load (const compile_file_names &file_names, if (missing_symbols) error (_("%ld symbols were missing, cannot continue."), missing_symbols); - bfd_map_over_sections (abfd.get (), copy_sections, symbol_table); + bfd_map_over_sections (abfd.get (), copy_sections, symbol_table.data ()); regs_type = get_regs_type (func_sym, objfile); if (regs_type == NULL) diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c index d6bcc1f..01f43ad 100644 --- a/gdb/compile/compile.c +++ b/gdb/compile/compile.c @@ -46,16 +46,17 @@ #include "gdbsupport/scoped_ignore_signal.h" #include "gdbsupport/buildargv.h" +/* Hold "compile" commands. */ + +static struct cmd_list_element *compile_command_list; + +#ifdef HAVE_COMPILE /* Initial filename for temporary files. */ #define TMP_PREFIX "/tmp/gdbobj-" -/* Hold "compile" commands. */ - -static struct cmd_list_element *compile_command_list; - /* Debug flag for "compile" commands. */ bool compile_debug; @@ -527,6 +528,41 @@ print_callback (void *ignore, const char *message) gdb_puts (message, gdb_stderr); } +/* Helper for compile_to_object, to find the compile context + based on the current language. */ +static std::unique_ptr<compile_instance> +get_language_compile_context () +{ + switch (current_language->la_language) + { + case language_c: + return c_get_compile_context (); + case language_cplus: + return cplus_get_compile_context (); + default: + return {}; + } +} + +/* Helper for compile_to_object, to call the correct + compute_program based on the current language. */ +static std::string +compute_program_language (compile_instance *inst, const char *input, + struct gdbarch *gdbarch, + const struct block *block, + CORE_ADDR pc) +{ + switch (current_language->la_language) + { + case language_c: + return c_compute_program (inst, input, gdbarch, block, pc); + case language_cplus: + return cplus_compute_program (inst, input, gdbarch, block, pc); + default: + gdb_assert_not_reached ("Unsupported language"); + } +} + /* Process the compilation request. On success it returns the object and source file names. On an error condition, error () is called. */ @@ -550,7 +586,8 @@ compile_to_object (struct command_line *cmd, const char *cmd_string, /* Set up instance and context for the compiler. */ std::unique_ptr<compile_instance> compiler - = current_language->get_compile_instance (); + = get_language_compile_context (); + if (compiler == nullptr) error (_("No compiler support for language %s."), current_language->name ()); @@ -582,8 +619,8 @@ compile_to_object (struct command_line *cmd, const char *cmd_string, error (_("Neither a simple expression, or a multi-line specified.")); std::string code - = current_language->compute_program (compiler.get (), input, gdbarch, - expr_block, expr_pc); + = compute_program_language (compiler.get (), input, gdbarch, + expr_block, expr_pc); if (compile_debug) gdb_printf (gdb_stdlog, "debug output:\n\n%s", code.c_str ()); @@ -816,6 +853,18 @@ compile_instance::compile (const char *filename, int verbose_level) #undef FORWARD +#else /* HAVE_COMPILE */ + +/* The "compile" prefix command, when support was disabled. */ + +static void +compile_command (const char *args, int from_tty) +{ + error (_("This command is not supported.")); +} + +#endif /* HAVE_COMPILE */ + /* See compile.h. */ cmd_list_element *compile_cmd_element = nullptr; @@ -823,14 +872,25 @@ void _initialize_compile (); void _initialize_compile () { - struct cmd_list_element *c = NULL; - compile_cmd_element = add_prefix_cmd ("compile", class_obscure, - compile_command, _("\ + compile_command, +#ifdef HAVE_COMPILE + _("\ Command to compile source code and inject it into the inferior."), +#else /* HAVE_COMPILE */ + _("\ +Command to compile source code and inject it into the inferior.\n\ +\n\ +Code compilation and injection is not supported in this copy of GDB.\n\ +This command is only a placeholder."), +#endif /* HAVE_COMPILE */ &compile_command_list, 1, &cmdlist); add_com_alias ("expression", compile_cmd_element, class_obscure, 0); +#ifdef HAVE_COMPILE + + struct cmd_list_element *c = NULL; + const auto compile_opts = make_compile_options_def_group (nullptr); static const std::string compile_code_help @@ -937,4 +997,5 @@ It should be absolute filename of the gcc executable.\n\ If empty the default target triplet will be searched in $PATH."), NULL, show_compile_gcc, &setlist, &showlist); +#endif /* HAVE_COMPILE */ } diff --git a/gdb/config.in b/gdb/config.in index db63aea..86ff67d 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -104,6 +104,9 @@ the CoreFoundation framework. */ #undef HAVE_CFPREFERENCESCOPYAPPVALUE +/* Define if compiling support to gdb compile. */ +#undef HAVE_COMPILE + /* Define to 1 if you have the <cursesX.h> header file. */ #undef HAVE_CURSESX_H diff --git a/gdb/configure b/gdb/configure index 3080413..e8a649f 100755 --- a/gdb/configure +++ b/gdb/configure @@ -956,6 +956,7 @@ with_libexpat_type with_python with_python_libdir with_guile +enable_gdb_compile enable_source_highlight with_sysroot with_system_gdbinit @@ -1650,6 +1651,8 @@ Optional Features: --enable-gdbtk enable gdbtk graphical user interface (GUI) --enable-profiling enable profiling of GDB --enable-codesign=CERT sign gdb with 'codesign -s CERT' + --enable-gdb-compile enable support for the compile subsystem, default + 'yes' --enable-source-highlight enable source-highlight for source listings --enable-werror treat compile warnings as errors @@ -11500,7 +11503,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11503 "configure" +#line 11506 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11606,7 +11609,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11609 "configure" +#line 11612 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -28969,6 +28972,38 @@ fi # ---------------------------- # +# Check for compile support. # +# ---------------------------- # + +# Check whether --enable-gdb-compile was given. +if test "${enable_gdb_compile+set}" = set; then : + enableval=$enable_gdb_compile; + case $enableval in + yes | no) + ;; + *) + as_fn_error $? "bad value $enableval for --enable-gdb-compile" "$LINENO" 5 + ;; + esac + +else + enable_gdb_compile=yes +fi + + +if test "${enable_gdb_compile}" == yes; then + +$as_echo "#define HAVE_COMPILE 1" >>confdefs.h + + CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_GCC_COMPILE_OBS)" +else + # Even if compile support is not enabled, we need this file to define + # the "compile" command. + CONFIG_OBS="$CONFIG_OBS compile/compile.o" + CONFIG_SRCS="$CONFIG_SRCS compile/compile.c" +fi + +# ---------------------------- # # Check for source highlight. # # ---------------------------- # diff --git a/gdb/configure.ac b/gdb/configure.ac index eafbf5a..2411b10 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -1222,6 +1222,26 @@ AC_SUBST(GUILE_LIBS) AM_CONDITIONAL(HAVE_GUILE, test "${have_libguile}" != no) # ---------------------------- # +# Check for compile support. # +# ---------------------------- # + +AC_ARG_ENABLE([gdb-compile], + AS_HELP_STRING([--enable-gdb-compile], + [enable support for the compile subsystem, default 'yes']), + [GDB_CHECK_YES_NO_VAL([$enableval], [--enable-gdb-compile])], + [enable_gdb_compile=yes]) + +if test "${enable_gdb_compile}" == yes; then + AC_DEFINE(HAVE_COMPILE, 1, [Define if compiling support to gdb compile.]) + CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_GCC_COMPILE_OBS)" +else + # Even if compile support is not enabled, we need this file to define + # the "compile" command. + CONFIG_OBS="$CONFIG_OBS compile/compile.o" + CONFIG_SRCS="$CONFIG_SRCS compile/compile.c" +fi + +# ---------------------------- # # Check for source highlight. # # ---------------------------- # diff --git a/gdb/contrib/codespell-ignore-words.txt b/gdb/contrib/codespell-ignore-words.txt index a8287f7..2d6e13a 100644 --- a/gdb/contrib/codespell-ignore-words.txt +++ b/gdb/contrib/codespell-ignore-words.txt @@ -1,3 +1,2 @@ configury -invokable -useable +SME diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in index 287dc7f..c08a68d 100644 --- a/gdb/data-directory/Makefile.in +++ b/gdb/data-directory/Makefile.in @@ -97,6 +97,7 @@ PYTHON_FILE_LIST = \ gdb/command/xmethods.py \ gdb/dap/breakpoint.py \ gdb/dap/bt.py \ + gdb/dap/completions.py \ gdb/dap/disassemble.py \ gdb/dap/evaluate.py \ gdb/dap/events.py \ diff --git a/gdb/dicos-tdep.c b/gdb/dicos-tdep.c index 3627426..96b841a 100644 --- a/gdb/dicos-tdep.c +++ b/gdb/dicos-tdep.c @@ -53,9 +53,7 @@ dicos_init_abi (struct gdbarch *gdbarch) int dicos_load_module_p (bfd *abfd, int header_size) { - long storage_needed; int ret = 0; - asymbol **symbol_table = NULL; const char *symname = "Dicos_loadModuleInfo"; asection *section; @@ -75,42 +73,19 @@ dicos_load_module_p (bfd *abfd, int header_size) /* Dicos LMs always have a "Dicos_loadModuleInfo" symbol defined. Look for it. */ - storage_needed = bfd_get_symtab_upper_bound (abfd); - if (storage_needed < 0) - { - warning (_("Can't read elf symbols from %s: %s"), - bfd_get_filename (abfd), - bfd_errmsg (bfd_get_error ())); - return 0; - } + gdb::array_view<asymbol *> symbol_table + = gdb_bfd_canonicalize_symtab (abfd, false); - if (storage_needed > 0) + for (asymbol *sym : symbol_table) { - long i, symcount; - - symbol_table = (asymbol **) xmalloc (storage_needed); - symcount = bfd_canonicalize_symtab (abfd, symbol_table); - - if (symcount < 0) - warning (_("Can't read elf symbols from %s: %s"), - bfd_get_filename (abfd), - bfd_errmsg (bfd_get_error ())); - else + if (sym->name != NULL + && symname[0] == sym->name[0] + && strcmp (symname + 1, sym->name + 1) == 0) { - for (i = 0; i < symcount; i++) - { - asymbol *sym = symbol_table[i]; - if (sym->name != NULL - && symname[0] == sym->name[0] - && strcmp (symname + 1, sym->name + 1) == 0) - { - ret = 1; - break; - } - } + ret = 1; + break; } } - xfree (symbol_table); return ret; } diff --git a/gdb/dwarf2/cooked-index.c b/gdb/dwarf2/cooked-index.c index 724615f..feaf9b5 100644 --- a/gdb/dwarf2/cooked-index.c +++ b/gdb/dwarf2/cooked-index.c @@ -122,11 +122,8 @@ cooked_index_entry::compare (const char *stra, const char *strb, /* When completing, if STRB ends earlier than STRA, consider them as equal. */ - if (mode == COMPLETE || (mode == MATCH && a == munge ('<'))) - { - if (b == '\0') - return 0; - } + if (mode == COMPLETE && b == '\0') + return 0; return a < b ? -1 : 1; } @@ -550,25 +547,28 @@ cooked_index_shard::finalize (const parent_map_map *parent_maps) cooked_index_shard::range cooked_index_shard::find (const std::string &name, bool completing) const { - cooked_index_entry::comparison_mode mode = (completing - ? cooked_index_entry::COMPLETE - : cooked_index_entry::MATCH); - - auto lower = std::lower_bound (m_entries.cbegin (), m_entries.cend (), name, - [=] (const cooked_index_entry *entry, - const std::string &n) + struct comparator { - return cooked_index_entry::compare (entry->canonical, n.c_str (), mode) < 0; - }); + cooked_index_entry::comparison_mode mode; - auto upper = std::upper_bound (m_entries.cbegin (), m_entries.cend (), name, - [=] (const std::string &n, - const cooked_index_entry *entry) - { - return cooked_index_entry::compare (entry->canonical, n.c_str (), mode) > 0; - }); + bool operator() (const cooked_index_entry *entry, + const char *name) const noexcept + { + return cooked_index_entry::compare (entry->canonical, name, mode) < 0; + } + + bool operator() (const char *name, + const cooked_index_entry *entry) const noexcept + { + return cooked_index_entry::compare (entry->canonical, name, mode) > 0; + } + }; - return range (lower, upper); + return std::make_from_tuple<range> + (std::equal_range (m_entries.cbegin (), m_entries.cend (), name.c_str (), + comparator { (completing + ? cooked_index_entry::COMPLETE + : cooked_index_entry::MATCH) })); } /* See cooked-index.h. */ diff --git a/gdb/dwarf2/cooked-indexer.c b/gdb/dwarf2/cooked-indexer.c index 3b80cd6..789fdb5 100644 --- a/gdb/dwarf2/cooked-indexer.c +++ b/gdb/dwarf2/cooked-indexer.c @@ -109,7 +109,7 @@ cooked_indexer::ensure_cu_exists (cutu_reader *reader, cutu_reader *result = m_index_storage->get_reader (per_cu); if (result == nullptr) { - cutu_reader new_reader (per_cu, per_objfile, nullptr, nullptr, false, + cutu_reader new_reader (*per_cu, *per_objfile, nullptr, nullptr, false, language_minimal, &m_index_storage->get_abbrev_table_cache ()); diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c index 7c12c0d..8f66694 100644 --- a/gdb/dwarf2/loc.c +++ b/gdb/dwarf2/loc.c @@ -1784,6 +1784,7 @@ dwarf2_compile_property_to_c (string_file *stream, CORE_ADDR pc, struct symbol *sym) { +#if defined (HAVE_COMPILE) const dwarf2_property_baton *baton = prop->baton (); const gdb_byte *data; size_t size; @@ -1810,6 +1811,9 @@ dwarf2_compile_property_to_c (string_file *stream, gdbarch, registers_used, per_cu->addr_size (), data, data + size, per_cu, per_objfile); +#else + gdb_assert_not_reached ("Compile support was disabled"); +#endif } /* Compute the correct symbol_needs_kind value for the location @@ -3852,6 +3856,7 @@ locexpr_generate_c_location (struct symbol *sym, string_file *stream, std::vector<bool> ®isters_used, CORE_ADDR pc, const char *result_name) { +#if defined (HAVE_COMPILE) struct dwarf2_locexpr_baton *dlbaton = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (sym); unsigned int addr_size = dlbaton->per_cu->addr_size (); @@ -3863,6 +3868,9 @@ locexpr_generate_c_location (struct symbol *sym, string_file *stream, sym, pc, gdbarch, registers_used, addr_size, dlbaton->data, dlbaton->data + dlbaton->size, dlbaton->per_cu, dlbaton->per_objfile); +#else + gdb_assert_not_reached ("Compile support was disabled"); +#endif } /* The set of location functions used with the DWARF-2 expression @@ -4088,6 +4096,7 @@ loclist_generate_c_location (struct symbol *sym, string_file *stream, std::vector<bool> ®isters_used, CORE_ADDR pc, const char *result_name) { +#if defined (HAVE_COMPILE) struct dwarf2_loclist_baton *dlbaton = (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (sym); unsigned int addr_size = dlbaton->per_cu->addr_size (); @@ -4103,6 +4112,9 @@ loclist_generate_c_location (struct symbol *sym, string_file *stream, data, data + size, dlbaton->per_cu, dlbaton->per_objfile); +#else + gdb_assert_not_reached ("Compile support was disabled"); +#endif } /* The set of location functions used with the DWARF-2 expression diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 8875e97..3d7b6dd 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -1791,7 +1791,7 @@ dw2_get_file_names (dwarf2_per_cu *this_cu, dwarf2_per_objfile *per_objfile) if (this_cu->files_read) return this_cu->file_names; - cutu_reader reader (this_cu, per_objfile, nullptr, + cutu_reader reader (*this_cu, *per_objfile, nullptr, per_objfile->get_cu (this_cu), true, language_minimal, nullptr); if (!reader.is_dummy ()) @@ -2710,8 +2710,7 @@ cutu_reader::init_cu_die_reader (dwarf2_cu *cu, dwarf2_section_info *section, void cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit, die_info *stub_comp_unit_die, - const char *stub_comp_dir, - abbrev_table_up *result_dwo_abbrev_table) + const char *stub_comp_dir) { dwarf2_per_objfile *per_objfile = cu->per_objfile; dwarf2_per_cu *per_cu = cu->per_cu; @@ -2829,10 +2828,18 @@ cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit, } dwo_abbrev_section->read (objfile); - *result_dwo_abbrev_table + m_dwo_abbrev_table = abbrev_table::read (dwo_abbrev_section, cu->header.abbrev_sect_off); this->init_cu_die_reader (cu, section, dwo_unit->dwo_file, - result_dwo_abbrev_table->get ()); + m_dwo_abbrev_table.get ()); + + /* Skip dummy compilation units. */ + if (m_info_ptr >= begin_info_ptr + dwo_unit->length + || peek_abbrev_code (abfd, m_info_ptr) == 0) + { + m_dummy_p = true; + return; + } /* Read in the die, filling in the attributes from the stub. This has the benefit of simplifying the rest of the code - all the @@ -2841,11 +2848,6 @@ cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit, m_top_level_die = this->read_toplevel_die (gdb::make_array_view (attributes, next_attr_idx)); - - /* Skip dummy compilation units. */ - if (m_info_ptr >= begin_info_ptr + dwo_unit->length - || peek_abbrev_code (abfd, m_info_ptr) == 0) - m_dummy_p = true; } /* Return the signature of the compile unit, if found. In DWARF 4 and before, @@ -2864,8 +2866,12 @@ lookup_dwo_id (struct dwarf2_cu *cu, struct die_info* comp_unit_die) } /* Subroutine of cutu_reader to simplify it. - Look up the DWO unit specified by COMP_UNIT_DIE of THIS_CU. - Returns NULL if the specified DWO unit cannot be found. */ + Look up the DWO unit specified by COMP_UNIT_DIE of CU. + + DWO_NAME is the name (DW_AT_dwo_name) of the DWO unit already read from + COMP_UNIT_DIE. + + Returns nullptr if the specified DWO unit cannot be found. */ static struct dwo_unit * lookup_dwo_unit (dwarf2_cu *cu, die_info *comp_unit_die, const char *dwo_name) @@ -2883,8 +2889,6 @@ lookup_dwo_unit (dwarf2_cu *cu, die_info *comp_unit_die, const char *dwo_name) gdb_assert (cu != NULL); - /* Yeah, we look dwo_name up again, but it simplifies the code. */ - dwo_name = dwarf2_dwo_name (comp_unit_die, cu); comp_dir = dwarf2_string_attr (comp_unit_die, DW_AT_comp_dir, cu); if (per_cu->is_debug_types) @@ -2946,8 +2950,7 @@ cutu_reader::init_tu_and_read_dwo_dies (dwarf2_per_cu *this_cu, could share abbrev tables. */ read_cutu_die_from_dwo (cu, sig_type->dwo_unit, NULL /* stub_comp_unit_die */, - sig_type->dwo_unit->dwo_file->comp_dir, - &m_dwo_abbrev_table); + sig_type->dwo_unit->dwo_file->comp_dir); prepare_one_comp_unit (cu, pretend_language); } @@ -2961,16 +2964,16 @@ cutu_reader::init_tu_and_read_dwo_dies (dwarf2_per_cu *this_cu, If EXISTING_CU is non-NULL, then use it. Otherwise, a new CU is allocated. */ -cutu_reader::cutu_reader (dwarf2_per_cu *this_cu, - dwarf2_per_objfile *per_objfile, +cutu_reader::cutu_reader (dwarf2_per_cu &this_cu, + dwarf2_per_objfile &per_objfile, const struct abbrev_table *abbrev_table, dwarf2_cu *existing_cu, bool skip_partial, enum language pretend_language, const abbrev_table_cache *cache) { - struct objfile *objfile = per_objfile->objfile; - struct dwarf2_section_info *section = this_cu->section; + struct objfile *objfile = per_objfile.objfile; + struct dwarf2_section_info *section = this_cu.section; bfd *abfd = section->get_bfd_owner (); const gdb_byte *begin_info_ptr; struct signatured_type *sig_type = NULL; @@ -2982,17 +2985,17 @@ cutu_reader::cutu_reader (dwarf2_per_cu *this_cu, if (dwarf_die_debug) gdb_printf (gdb_stdlog, "Reading %s unit at offset %s\n", - this_cu->is_debug_types ? "type" : "comp", - sect_offset_str (this_cu->sect_off)); + this_cu.is_debug_types ? "type" : "comp", + sect_offset_str (this_cu.sect_off)); /* If we're reading a TU directly from a DWO file, including a virtual DWO file (instead of going through the stub), short-circuit all of this. */ - if (this_cu->reading_dwo_directly) + if (this_cu.reading_dwo_directly) { /* Narrow down the scope of possibilities to have to understand. */ - gdb_assert (this_cu->is_debug_types); + gdb_assert (this_cu.is_debug_types); gdb_assert (abbrev_table == NULL); - init_tu_and_read_dwo_dies (this_cu, per_objfile, existing_cu, + init_tu_and_read_dwo_dies (&this_cu, &per_objfile, existing_cu, pretend_language); return; } @@ -3001,9 +3004,9 @@ cutu_reader::cutu_reader (dwarf2_per_cu *this_cu, section->read (objfile); begin_info_ptr = m_info_ptr - = section->buffer + to_underlying (this_cu->sect_off); + = section->buffer + to_underlying (this_cu.sect_off); - abbrev_section = get_abbrev_section_for_cu (this_cu); + abbrev_section = get_abbrev_section_for_cu (&this_cu); dwarf2_cu *cu; @@ -3028,8 +3031,8 @@ cutu_reader::cutu_reader (dwarf2_per_cu *this_cu, is irrelevant, and (2) the get_cu method is not thread-safe. */ gdb_assert (cache != nullptr - || per_objfile->get_cu (this_cu) == nullptr); - m_new_cu = std::make_unique<dwarf2_cu> (this_cu, per_objfile); + || per_objfile.get_cu (&this_cu) == nullptr); + m_new_cu = std::make_unique<dwarf2_cu> (&this_cu, &per_objfile); cu = m_new_cu.get (); } @@ -3041,43 +3044,43 @@ cutu_reader::cutu_reader (dwarf2_per_cu *this_cu, } else { - if (this_cu->is_debug_types) + if (this_cu.is_debug_types) { m_info_ptr - = read_and_check_comp_unit_head (per_objfile, &cu->header, section, + = read_and_check_comp_unit_head (&per_objfile, &cu->header, section, abbrev_section, m_info_ptr, rcuh_kind::TYPE); /* Since per_cu is the first member of struct signatured_type, we can go from a pointer to one to a pointer to the other. */ - sig_type = (struct signatured_type *) this_cu; + sig_type = (struct signatured_type *) &this_cu; gdb_assert (sig_type->signature == cu->header.signature); gdb_assert (sig_type->type_offset_in_tu == cu->header.type_cu_offset_in_tu); - gdb_assert (this_cu->sect_off == cu->header.sect_off); + gdb_assert (this_cu.sect_off == cu->header.sect_off); /* LENGTH has not been set yet for type units if we're using .gdb_index. */ - this_cu->set_length (cu->header.get_length_with_initial ()); + this_cu.set_length (cu->header.get_length_with_initial ()); /* Establish the type offset that can be used to lookup the type. */ sig_type->type_offset_in_section = - this_cu->sect_off + to_underlying (sig_type->type_offset_in_tu); + this_cu.sect_off + to_underlying (sig_type->type_offset_in_tu); } else { m_info_ptr - = read_and_check_comp_unit_head (per_objfile, &cu->header, section, + = read_and_check_comp_unit_head (&per_objfile, &cu->header, section, abbrev_section, m_info_ptr, rcuh_kind::COMPILE); - gdb_assert (this_cu->sect_off == cu->header.sect_off); - this_cu->set_length (cu->header.get_length_with_initial ()); + gdb_assert (this_cu.sect_off == cu->header.sect_off); + this_cu.set_length (cu->header.get_length_with_initial ()); } } /* Skip dummy compilation units. */ - if (m_info_ptr >= begin_info_ptr + this_cu->length () + if (m_info_ptr >= begin_info_ptr + this_cu.length () || peek_abbrev_code (abfd, m_info_ptr) == 0) m_dummy_p = true; else @@ -3129,14 +3132,13 @@ cutu_reader::cutu_reader (dwarf2_per_cu *this_cu, { complaint (_("compilation unit with DW_AT_GNU_dwo_name" " has children (offset %s) [in module %s]"), - sect_offset_str (this_cu->sect_off), + sect_offset_str (this_cu.sect_off), bfd_get_filename (abfd)); } dwo_unit = lookup_dwo_unit (cu, m_top_level_die, dwo_name); if (dwo_unit != NULL) - read_cutu_die_from_dwo (cu, dwo_unit, m_top_level_die, nullptr, - &m_dwo_abbrev_table); + read_cutu_die_from_dwo (cu, dwo_unit, m_top_level_die, nullptr); else { /* Yikes, we couldn't find the rest of the DIE, we only have @@ -3165,65 +3167,57 @@ cutu_reader::release_cu () return std::move (m_new_cu); } -/* Read CU/TU THIS_CU but do not follow DW_AT_GNU_dwo_name (DW_AT_dwo_name) - if present. DWO_FILE, if non-NULL, is the DWO file to read (the caller is - assumed to have already done the lookup to find the DWO file). - - The caller is required to fill in THIS_CU->section, THIS_CU->offset, and - THIS_CU->is_debug_types, but nothing else. +/* This constructor exists for the special case of reading many units in a row + from a given known DWO file. - We fill in THIS_CU->length. + THIS_CU is a special dwarf2_per_cu to represent where to read the unit from, + in the DWO file. The caller is required to fill THIS_CU::SECTION, + THIS_CU::SECT_OFF, and THIS_CU::IS_DEBUG_TYPES. This constructor will fill + in the length. THIS_CU::SECTION must point to a section from the DWO file, + which is normally not the case for regular dwarf2_per_cu uses. - THIS_CU->cu is always freed when done. - This is done in order to not leave THIS_CU->cu in a state where we have - to care whether it refers to the "main" CU or the DWO CU. + PARENT_CU is the CU created when reading the skeleton unit, and is used to + provide a default value for str_offsets_base and addr_base. */ - When parent_cu is passed, it is used to provide a default value for - str_offsets_base and addr_base from the parent. */ - -cutu_reader::cutu_reader (dwarf2_per_cu *this_cu, - dwarf2_per_objfile *per_objfile, - enum language pretend_language, - struct dwarf2_cu *parent_cu, - struct dwo_file *dwo_file) +cutu_reader::cutu_reader (dwarf2_per_cu &this_cu, + dwarf2_per_objfile &per_objfile, + language pretend_language, dwarf2_cu &parent_cu, + dwo_file &dwo_file) { - struct objfile *objfile = per_objfile->objfile; - struct dwarf2_section_info *section = this_cu->section; + struct objfile *objfile = per_objfile.objfile; + struct dwarf2_section_info *section = this_cu.section; bfd *abfd = section->get_bfd_owner (); - gdb_assert (parent_cu != nullptr); - gdb_assert (dwo_file != nullptr); - if (dwarf_die_debug) gdb_printf (gdb_stdlog, "Reading %s unit at offset %s\n", - this_cu->is_debug_types ? "type" : "comp", - sect_offset_str (this_cu->sect_off)); + this_cu.is_debug_types ? "type" : "comp", + sect_offset_str (this_cu.sect_off)); - gdb_assert (per_objfile->get_cu (this_cu) == nullptr); + gdb_assert (per_objfile.get_cu (&this_cu) == nullptr); - dwarf2_section_info *abbrev_section = &dwo_file->sections.abbrev; + dwarf2_section_info *abbrev_section = &dwo_file.sections.abbrev; /* This is cheap if the section is already read in. */ section->read (objfile); - m_new_cu = std::make_unique<dwarf2_cu> (this_cu, per_objfile); + m_new_cu = std::make_unique<dwarf2_cu> (&this_cu, &per_objfile); - m_info_ptr = section->buffer + to_underlying (this_cu->sect_off); + m_info_ptr = section->buffer + to_underlying (this_cu.sect_off); const gdb_byte *begin_info_ptr = m_info_ptr; m_info_ptr - = read_and_check_comp_unit_head (per_objfile, &m_new_cu->header, section, + = read_and_check_comp_unit_head (&per_objfile, &m_new_cu->header, section, abbrev_section, m_info_ptr, - (this_cu->is_debug_types + (this_cu.is_debug_types ? rcuh_kind::TYPE : rcuh_kind::COMPILE)); - m_new_cu->str_offsets_base = parent_cu->str_offsets_base; - m_new_cu->addr_base = parent_cu->addr_base; + m_new_cu->str_offsets_base = parent_cu.str_offsets_base; + m_new_cu->addr_base = parent_cu.addr_base; - this_cu->set_length (m_new_cu->header.get_length_with_initial ()); + this_cu.set_length (m_new_cu->header.get_length_with_initial ()); /* Skip dummy compilation units. */ - if (m_info_ptr >= begin_info_ptr + this_cu->length () + if (m_info_ptr >= begin_info_ptr + this_cu.length () || peek_abbrev_code (abfd, m_info_ptr) == 0) m_dummy_p = true; else @@ -3233,7 +3227,7 @@ cutu_reader::cutu_reader (dwarf2_per_cu *this_cu, = abbrev_table::read (abbrev_section, m_new_cu->header.abbrev_sect_off); - this->init_cu_die_reader (m_new_cu.get (), section, dwo_file, + this->init_cu_die_reader (m_new_cu.get (), section, &dwo_file, m_abbrev_table_holder.get ()); m_top_level_die = this->read_toplevel_die (); } @@ -3300,7 +3294,7 @@ process_psymtab_comp_unit (dwarf2_per_cu *this_cu, cutu_reader *reader = storage->get_reader (this_cu); if (reader == nullptr) { - cutu_reader new_reader (this_cu, per_objfile, nullptr, nullptr, false, + cutu_reader new_reader (*this_cu, *per_objfile, nullptr, nullptr, false, language_minimal, &storage->get_abbrev_table_cache ()); @@ -3447,7 +3441,7 @@ build_type_psymtabs (dwarf2_per_objfile *per_objfile, ++tu_stats->nr_uniq_abbrev_tables; } - cutu_reader reader (tu.sig_type, per_objfile, + cutu_reader reader (*tu.sig_type, *per_objfile, abbrev_table.get (), nullptr, false, language_minimal); if (!reader.is_dummy ()) @@ -3501,7 +3495,7 @@ process_skeletonless_type_unit (dwo_unit *dwo_unit, fill_in_sig_entry_from_dwo_entry (per_objfile, *sig_type_it, dwo_unit); /* This does the job that build_type_psymtabs would have done. */ - cutu_reader reader (*sig_type_it, per_objfile, nullptr, nullptr, false, + cutu_reader reader (**sig_type_it, *per_objfile, nullptr, nullptr, false, language_minimal); if (!reader.is_dummy ()) build_type_psymtabs_reader (&reader, storage); @@ -4223,7 +4217,7 @@ load_full_comp_unit (dwarf2_per_cu *this_cu, dwarf2_per_objfile *per_objfile, gdb_assert (! this_cu->is_debug_types); gdb_assert (per_objfile->get_cu (this_cu) == nullptr); - cutu_reader reader (this_cu, per_objfile, nullptr, nullptr, skip_partial, + cutu_reader reader (*this_cu, *per_objfile, nullptr, nullptr, skip_partial, pretend_language); if (reader.is_dummy ()) return; @@ -6358,8 +6352,8 @@ create_cus_hash_table (dwarf2_cu *cu, dwo_file &dwo_file) /* The length of the CU gets set by the cutu_reader just below. */ dwarf2_per_cu per_cu (per_bfd, §ion, sect_off, 0 /* length */, false /* is_dwz */); - cutu_reader reader (&per_cu, per_objfile, language_minimal, - cu, &dwo_file); + cutu_reader reader (per_cu, *per_objfile, language_minimal, + *cu, dwo_file); info_ptr += per_cu.length (); @@ -15323,7 +15317,7 @@ dwarf2_read_addr_index (dwarf2_per_cu *per_cu, dwarf2_per_objfile *per_objfile, } else { - cutu_reader reader (per_cu, per_objfile, nullptr, nullptr, false, + cutu_reader reader (*per_cu, *per_objfile, nullptr, nullptr, false, language_minimal); addr_base = reader.cu ()->addr_base; addr_size = reader.cu ()->header.addr_size; @@ -18823,7 +18817,7 @@ read_signatured_type (signatured_type *sig_type, gdb_assert (sig_type->is_debug_types); gdb_assert (per_objfile->get_cu (sig_type) == nullptr); - cutu_reader reader (sig_type, per_objfile, nullptr, nullptr, false, + cutu_reader reader (*sig_type, *per_objfile, nullptr, nullptr, false, language_minimal); if (!reader.is_dummy ()) @@ -19336,7 +19330,7 @@ dwarf2_per_cu::ensure_lang (dwarf2_per_objfile *per_objfile) /* Constructing this object will set the language as a side effect. */ - cutu_reader reader (this, per_objfile, nullptr, per_objfile->get_cu (this), + cutu_reader reader (*this, *per_objfile, nullptr, per_objfile->get_cu (this), true, language_minimal, nullptr); } diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index ba2dd07..7f56dac 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -921,19 +921,19 @@ class cutu_reader { public: - cutu_reader (dwarf2_per_cu *this_cu, - dwarf2_per_objfile *per_objfile, + cutu_reader (dwarf2_per_cu &this_cu, + dwarf2_per_objfile &per_objfile, const struct abbrev_table *abbrev_table, dwarf2_cu *existing_cu, bool skip_partial, enum language pretend_language, const abbrev_table_cache *cache = nullptr); - cutu_reader (dwarf2_per_cu *this_cu, - dwarf2_per_objfile *per_objfile, + cutu_reader (dwarf2_per_cu &this_cu, + dwarf2_per_objfile &per_objfile, enum language pretend_language, - struct dwarf2_cu *parent_cu, - struct dwo_file *dwo_file); + struct dwarf2_cu &parent_cu, + struct dwo_file &dwo_file); DISABLE_COPY_AND_ASSIGN (cutu_reader); @@ -1003,8 +1003,7 @@ private: void read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit, die_info *stub_comp_unit_die, - const char *stub_comp_dir, - abbrev_table_up *result_dwo_abbrev_table); + const char *stub_comp_dir); void prepare_one_comp_unit (struct dwarf2_cu *cu, enum language pretend_language); diff --git a/gdb/elfread.c b/gdb/elfread.c index 5be3118..3756fa3 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -1062,8 +1062,8 @@ elf_read_minimal_symbols (struct objfile *objfile, int symfile_flags, const struct elfinfo *ei) { bfd *synth_abfd, *abfd = objfile->obfd.get (); - long symcount = 0, dynsymcount = 0, synthcount, storage_needed; - asymbol **symbol_table = NULL, **dyn_symbol_table = NULL; + long dynsymcount = 0, synthcount; + asymbol **dyn_symbol_table = NULL; asymbol *synthsyms; symtab_create_debug_printf ("reading minimal symbols of objfile %s", @@ -1087,32 +1087,16 @@ elf_read_minimal_symbols (struct objfile *objfile, int symfile_flags, /* Process the normal ELF symbol table first. */ - storage_needed = bfd_get_symtab_upper_bound (objfile->obfd.get ()); - if (storage_needed < 0) - error (_("Can't read symbols from %s: %s"), - bfd_get_filename (objfile->obfd.get ()), - bfd_errmsg (bfd_get_error ())); + gdb::array_view<asymbol *> symbol_table + = gdb_bfd_canonicalize_symtab (objfile->obfd.get ()); - if (storage_needed > 0) - { - /* Memory gets permanently referenced from ABFD after - bfd_canonicalize_symtab so it must not get freed before ABFD gets. */ - - symbol_table = (asymbol **) bfd_alloc (abfd, storage_needed); - symcount = bfd_canonicalize_symtab (objfile->obfd.get (), symbol_table); - - if (symcount < 0) - error (_("Can't read symbols from %s: %s"), - bfd_get_filename (objfile->obfd.get ()), - bfd_errmsg (bfd_get_error ())); - - elf_symtab_read (reader, objfile, ST_REGULAR, symcount, symbol_table, - false); - } + elf_symtab_read (reader, objfile, ST_REGULAR, symbol_table.size (), + symbol_table.data (), false); /* Add the dynamic symbols. */ - storage_needed = bfd_get_dynamic_symtab_upper_bound (objfile->obfd.get ()); + long storage_needed + = bfd_get_dynamic_symtab_upper_bound (objfile->obfd.get ()); if (storage_needed > 0) { @@ -1157,7 +1141,8 @@ elf_read_minimal_symbols (struct objfile *objfile, int symfile_flags, /* Add synthetic symbols - for instance, names for any PLT entries. */ - synthcount = bfd_get_synthetic_symtab (synth_abfd, symcount, symbol_table, + synthcount = bfd_get_synthetic_symtab (synth_abfd, symbol_table.size (), + symbol_table.data (), dynsymcount, dyn_symbol_table, &synthsyms); if (synthcount > 0) diff --git a/gdb/frame.c b/gdb/frame.c index 2fb06a0..88560b8 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -2325,7 +2325,22 @@ get_prev_frame_always_1 (const frame_info_ptr &this_frame) until we have unwound all the way down to the previous non-inline frame. */ if (get_frame_type (this_frame) == INLINE_FRAME) - return get_prev_frame_maybe_check_cycle (this_frame); + { + frame_info_ptr fi = get_prev_frame_maybe_check_cycle (this_frame); + + /* If this_frame is the current frame, then compute and stash its frame + id so that the cycle check in get_prev_frame_maybe_check_cycle works + correctly in the case where inline frame 0 has been duplicated. + + The this_id.p check is required to avoid recursion as computing the + frame id results in a call to inline_frame_this_id which calls back + into get_prev_frame_always. */ + if (this_frame->level == 0 + && this_frame->this_id.p != frame_id_status::COMPUTING) + get_frame_id (this_frame); + + return fi; + } /* If this_frame is the current frame, then compute and stash its frame id prior to fetching and computing the frame id of the diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c index 8380c53..1a57b3c 100644 --- a/gdb/gdb_bfd.c +++ b/gdb/gdb_bfd.c @@ -143,6 +143,13 @@ struct gdb_bfd_data /* Table of all the bfds this bfd has included. */ std::vector<gdb_bfd_ref_ptr> included_bfds; + /* This is used by gdb_bfd_canonicalize_symtab to hold the symbols + returned by canonicalization. */ + std::optional<gdb::def_vector<asymbol *>> symbol_table; + /* If an error occurred while canonicalizing the symtab, this holds + the error message. */ + std::string symbol_error; + /* The registry. */ registry<bfd> registry_fields; @@ -1177,6 +1184,54 @@ gdb_bfd_errmsg (bfd_error_type error_tag, char **matching) return ret; } +/* See gdb_bfd.h. */ + +gdb::array_view<asymbol *> +gdb_bfd_canonicalize_symtab (bfd *abfd, bool should_throw) +{ + struct gdb_bfd_data *gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd); + + if (!gdata->symbol_table.has_value ()) + { + /* Ensure it exists. */ + gdb::def_vector<asymbol *> &symbol_table + = gdata->symbol_table.emplace (); + + long storage_needed = bfd_get_symtab_upper_bound (abfd); + if (storage_needed < 0) + gdata->symbol_error = bfd_errmsg (bfd_get_error ()); + else if (storage_needed > 0) + { + symbol_table.resize (storage_needed / sizeof (asymbol *)); + long number_of_symbols + = bfd_canonicalize_symtab (abfd, symbol_table.data ()); + if (number_of_symbols < 0) + { + symbol_table.clear (); + gdata->symbol_error = bfd_errmsg (bfd_get_error ()); + } + } + } + + if (!gdata->symbol_error.empty ()) + { + if (should_throw) + error (_("Cannot parse symbols of \"%s\": %s"), + bfd_get_filename (abfd), gdata->symbol_error.c_str ()); + return {}; + } + + gdb::def_vector<asymbol *> &symbol_table = *gdata->symbol_table; + if (symbol_table.empty ()) + return {}; + + /* bfd_canonicalize_symtab adds a trailing NULL, but don't include + this in the array view. */ + gdb_assert (symbol_table.back () == nullptr); + return gdb::make_array_view (symbol_table.data (), + symbol_table.size () - 1); +} + /* Implement the 'maint info bfd' command. */ static void diff --git a/gdb/gdb_bfd.h b/gdb/gdb_bfd.h index d35f2d6..7830bf3 100644 --- a/gdb/gdb_bfd.h +++ b/gdb/gdb_bfd.h @@ -274,4 +274,16 @@ extern std::string gdb_bfd_errmsg (bfd_error_type error_tag, char **matching); extern void gdb_bfd_init (); +/* A wrapper for bfd_canonicalize_symtab that caches the result. This + is important to avoid excess memory use on repeated calls. See + PR gdb/32758. bfd_canonicalize_symtab should not be called directly + by other code in gdb. + + When SHOULD_THROW is true (the default), this will throw an + exception if symbols could not be read. When SHOULD_THROW is + false, an empty view is returned instead. */ + +extern gdb::array_view<asymbol *> gdb_bfd_canonicalize_symtab + (bfd *abfd, bool should_throw = true); + #endif /* GDB_GDB_BFD_H */ diff --git a/gdb/gdbarch-selftests.c b/gdb/gdbarch-selftests.c index 27b17d17..8f42557 100644 --- a/gdb/gdbarch-selftests.c +++ b/gdb/gdbarch-selftests.c @@ -127,6 +127,9 @@ register_to_value_test (struct gdbarch *gdbarch) static void register_name_test (struct gdbarch *gdbarch) { + if (selftest_skip_warning_arch (gdbarch)) + return; + scoped_mock_context<test_target_ops> mockctx (gdbarch); /* Track the number of times each register name appears. */ diff --git a/gdb/gstack-1.in b/gdb/gstack-1.in index 5e41329..25339d9 100755 --- a/gdb/gstack-1.in +++ b/gdb/gstack-1.in @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright (C) 2024 Free Software Foundation, Inc. +# Copyright (C) 2024-2025 Free Software Foundation, Inc. # 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 @@ -22,8 +22,8 @@ GDB=${GDB:-$(command -v gdb)} GDBARGS=${GDBARGS:-} AWK=${AWK:-} -PKGVERSION=@PKGVERSION@ -VERSION=@VERSION@ +PKGVERSION="@PKGVERSION@" +VERSION="@VERSION@" # Find an appropriate awk interpreter if one was not specified # via the environment. @@ -132,7 +132,7 @@ EOF ) # Run GDB and remove some unwanted noise. -"$GDB" --quiet -nx --readnever $GDBARGS <<EOF | +"$GDB" --quiet -nx $GDBARGS <<EOF | set width 0 set height 0 set pagination no diff --git a/gdb/language.c b/gdb/language.c index a8548a2..4208c23 100644 --- a/gdb/language.c +++ b/gdb/language.c @@ -677,14 +677,6 @@ language_defn::is_string_type_p (struct type *type) const return c_is_string_type_p (type); } -/* See language.h. */ - -std::unique_ptr<compile_instance> -language_defn::get_compile_instance () const -{ - return {}; -} - /* The default implementation of the get_symbol_name_matcher_inner method from the language_defn class. Matches with strncmp_iw. */ diff --git a/gdb/language.h b/gdb/language.h index e6bfa3c..5e9599d 100644 --- a/gdb/language.h +++ b/gdb/language.h @@ -36,7 +36,6 @@ struct value_print_options; struct type_print_options; struct lang_varobj_ops; struct parser_state; -class compile_instance; struct completion_match_for_lcd; class innermost_block_tracker; @@ -390,37 +389,6 @@ struct language_defn symbol_name_matcher_ftype *get_symbol_name_matcher (const lookup_name_info &lookup_name) const; - /* If this language allows compilation from the gdb command line, - then this method will return an instance of struct gcc_context - appropriate to the language. If compilation for this language is - generally supported, but something goes wrong then an exception - is thrown. If compilation is not supported for this language - then this method returns NULL. */ - - virtual std::unique_ptr<compile_instance> get_compile_instance () const; - - /* This method must be overridden if 'get_compile_instance' is - overridden. - - This takes the user-supplied text and returns a new bit of code - to compile. - - INST is the compiler instance being used. - INPUT is the user's input text. - GDBARCH is the architecture to use. - EXPR_BLOCK is the block in which the expression is being - parsed. - EXPR_PC is the PC at which the expression is being parsed. */ - - virtual std::string compute_program (compile_instance *inst, - const char *input, - struct gdbarch *gdbarch, - const struct block *expr_block, - CORE_ADDR expr_pc) const - { - gdb_assert_not_reached ("language_defn::compute_program"); - } - /* Hash the given symbol search name. */ virtual unsigned int search_name_hash (const char *name) const; diff --git a/gdb/maint-test-options.c b/gdb/maint-test-options.c index 9d76817..da9765e 100644 --- a/gdb/maint-test-options.c +++ b/gdb/maint-test-options.c @@ -137,6 +137,7 @@ struct test_options_opts int pint_unl_opt = 0; std::string string_opt; std::string filename_opt; + ui_file_style::color color_opt { ui_file_style::MAGENTA }; test_options_opts () = default; @@ -149,7 +150,7 @@ struct test_options_opts gdb_printf (file, _("-flag %d -xx1 %d -xx2 %d -bool %d " "-enum %s -uint-unl %s -pint-unl %s -string '%s' " - "-filename '%s' -- %s\n"), + "-filename '%s' -color %s -- %s\n"), flag_opt, xx1_opt, xx2_opt, @@ -163,6 +164,7 @@ struct test_options_opts : plongest (pint_unl_opt)), string_opt.c_str (), filename_opt.c_str (), + color_opt.to_string ().c_str (), args); } }; @@ -245,6 +247,14 @@ static const gdb::option::option_def test_options_option_defs[] = { nullptr, /* show_cmd_cb */ N_("A filename option."), }, + + /* A color option. */ + gdb::option::color_option_def<test_options_opts> { + "color", + [] (test_options_opts *opts) { return &opts->color_opt; }, + nullptr, /* show_cmd_cb */ + N_("A color option."), + }, }; /* Create an option_def_group for the test_options_opts options, with diff --git a/gdb/observable.h b/gdb/observable.h index deea1ff..c50891e 100644 --- a/gdb/observable.h +++ b/gdb/observable.h @@ -102,10 +102,14 @@ extern observable<inferior */* parent_inf */, inferior */* child_inf */, extern observable<solib &/* solib */> solib_loaded; /* The shared library SOLIB has been unloaded from program space PSPACE. + The SILENT argument indicates that GDB doesn't wish to notify the CLI + about any non-error consequences of unloading the solib, e.g. when + breakpoints are disabled. + Note when gdb calls this observer, the library's symbols have not been unloaded yet, and thus are still available. */ extern observable<program_space *, const solib &/* solib */, - bool /* still_in_use */> solib_unloaded; + bool /* still_in_use */, bool /* silent */> solib_unloaded; /* The symbol file specified by OBJFILE has been loaded. */ extern observable<struct objfile */* objfile */> new_objfile; diff --git a/gdb/python/lib/gdb/dap/__init__.py b/gdb/python/lib/gdb/dap/__init__.py index 145aeb6..08ca33f 100644 --- a/gdb/python/lib/gdb/dap/__init__.py +++ b/gdb/python/lib/gdb/dap/__init__.py @@ -26,6 +26,7 @@ from . import startup # server object. "F401" is the flake8 "imported but unused" code. from . import breakpoint # noqa: F401 from . import bt # noqa: F401 +from . import completions # noqa: F401 from . import disassemble # noqa: F401 from . import evaluate # noqa: F401 from . import launch # noqa: F401 diff --git a/gdb/python/lib/gdb/dap/completions.py b/gdb/python/lib/gdb/dap/completions.py new file mode 100644 index 0000000..85acc43 --- /dev/null +++ b/gdb/python/lib/gdb/dap/completions.py @@ -0,0 +1,60 @@ +# Copyright 2025 Free Software Foundation, Inc. + +# 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/>. + +from typing import Optional + +from .frames import select_frame +from .server import capability, import_column, import_line, request +from .startup import exec_mi_and_log + + +@request("completions") +@capability("supportsCompletionsRequest") +@capability("completionTriggerCharacters", [" ", "."]) +def completions( + *, + frameId: Optional[int] = None, + text: str, + column: int, + line: Optional[int] = None, + **extra, +): + if frameId is not None: + select_frame(frameId) + + column = import_column(column) + if line is None: + line = 1 + else: + line = import_line(line) + text = text.splitlines()[line - 1] + text = text[: column - 1] + mi_result = exec_mi_and_log("-complete", text) + result = [] + completion = None + if "completion" in mi_result: + completion = mi_result["completion"] + result.append({"label": completion, "length": len(completion)}) + # If `-complete' finds one match then `completion' and `matches' + # will contain the same one match. + if ( + completion is not None + and len(mi_result["matches"]) == 1 + and completion == mi_result["matches"][0] + ): + return {"targets": result} + for match in mi_result["matches"]: + result.append({"label": match, "length": len(match)}) + return {"targets": result} diff --git a/gdb/python/lib/gdb/dap/server.py b/gdb/python/lib/gdb/dap/server.py index 8fdf029..7139c79 100644 --- a/gdb/python/lib/gdb/dap/server.py +++ b/gdb/python/lib/gdb/dap/server.py @@ -49,6 +49,7 @@ _server = None # This is set by the initialize request and is used when rewriting # line numbers. _lines_start_at_1 = False +_columns_start_at_1 = False class DeferredRequest: @@ -593,6 +594,8 @@ def initialize(**args): _server.send_event_later("initialized") global _lines_start_at_1 _lines_start_at_1 = client_bool_capability("linesStartAt1", True) + global _columns_start_at_1 + _columns_start_at_1 = client_bool_capability("columnsStartAt1", True) return _capabilities.copy() @@ -698,7 +701,7 @@ def send_gdb_with_response(fn): return val -def export_line(line): +def export_line(line: int) -> int: """Rewrite LINE according to client capability. This applies the linesStartAt1 capability as needed, when sending a line number from gdb to the client.""" @@ -710,7 +713,7 @@ def export_line(line): return line -def import_line(line): +def import_line(line: int) -> int: """Rewrite LINE according to client capability. This applies the linesStartAt1 capability as needed, when the client sends a line number to gdb.""" @@ -720,3 +723,17 @@ def import_line(line): # the client starts at 0. line = line + 1 return line + + +def export_column(column: int) -> int: + """Rewrite COLUMN according to client capability. + This applies the columnsStartAt1 capability as needed, + when sending a column number from gdb to the client.""" + return column if _columns_start_at_1 else column - 1 + + +def import_column(column: int) -> int: + """Rewrite COLUMN according to client capability. + This applies the columnsStartAt1 capability as needed, + when the client sends a column number to gdb.""" + return column if _columns_start_at_1 else column + 1 diff --git a/gdb/regcache.c b/gdb/regcache.c index 5508778..ad72429 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -1911,32 +1911,13 @@ public: {} }; -/* Return true if regcache::cooked_{read,write}_test should be skipped for - GDBARCH. */ - -static bool -selftest_skiparch (struct gdbarch *gdbarch) -{ - const char *name = gdbarch_bfd_arch_info (gdbarch)->printable_name; - - /* Avoid warning: - Running selftest regcache::cooked_{read,write}_test::m68hc11. - warning: No frame soft register found in the symbol table. - Stack backtrace will not work. - We could instead capture the output and then filter out the warning, but - that seems more trouble than it's worth. */ - return (strcmp (name, "m68hc11") == 0 - || strcmp (name, "m68hc12") == 0 - || strcmp (name, "m68hc12:HCS12") == 0); -} - /* Test regcache::cooked_read gets registers from raw registers and memory instead of target to_{fetch,store}_registers. */ static void cooked_read_test (struct gdbarch *gdbarch) { - if (selftest_skiparch (gdbarch)) + if (selftest_skip_warning_arch (gdbarch)) return; scoped_mock_context<target_ops_no_register> mockctx (gdbarch); @@ -2074,7 +2055,7 @@ cooked_read_test (struct gdbarch *gdbarch) static void cooked_write_test (struct gdbarch *gdbarch) { - if (selftest_skiparch (gdbarch)) + if (selftest_skip_warning_arch (gdbarch)) return; /* Create a mock environment. A process_stratum target pushed. */ diff --git a/gdb/selftest-arch.c b/gdb/selftest-arch.c index 17eeba8..79889c0 100644 --- a/gdb/selftest-arch.c +++ b/gdb/selftest-arch.c @@ -108,5 +108,24 @@ reset () registers_changed (); reinit_frame_cache (); } + +/* See selftest-arch.h. */ + +bool +selftest_skip_warning_arch (struct gdbarch *gdbarch) +{ + const char *name = gdbarch_bfd_arch_info (gdbarch)->printable_name; + + /* Avoid warning: + Running selftest <test>::m68hc11. + warning: No frame soft register found in the symbol table. + Stack backtrace will not work. + We could instead capture the output and then filter out the warning, but + that seems more trouble than it's worth. */ + return (strcmp (name, "m68hc11") == 0 + || strcmp (name, "m68hc12") == 0 + || strcmp (name, "m68hc12:HCS12") == 0); +} + } /* namespace selftests */ #endif /* GDB_SELF_TEST */ diff --git a/gdb/selftest-arch.h b/gdb/selftest-arch.h index db11723..c6a85fa 100644 --- a/gdb/selftest-arch.h +++ b/gdb/selftest-arch.h @@ -29,6 +29,11 @@ namespace selftests extern void register_test_foreach_arch (const std::string &name, self_test_foreach_arch_function *function); + +/* Return true if GDBARCH should be skipped in some selftests to avoid + warnings. */ + +extern bool selftest_skip_warning_arch (struct gdbarch *gdbarch); } #endif /* GDB_SELFTEST_ARCH_H */ diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c index 6c7d906..cbd89b1 100644 --- a/gdb/solib-darwin.c +++ b/gdb/solib-darwin.c @@ -146,24 +146,13 @@ struct lm_info_darwin final : public lm_info static CORE_ADDR lookup_symbol_from_bfd (bfd *abfd, const char *symname) { - long storage_needed; - asymbol **symbol_table; - unsigned int number_of_symbols; - unsigned int i; CORE_ADDR symaddr = 0; - storage_needed = bfd_get_symtab_upper_bound (abfd); + gdb::array_view<asymbol *> symbol_table + = gdb_bfd_canonicalize_symtab (abfd, false); - if (storage_needed <= 0) - return 0; - - symbol_table = (asymbol **) xmalloc (storage_needed); - number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); - - for (i = 0; i < number_of_symbols; i++) + for (const asymbol *sym : symbol_table) { - asymbol *sym = symbol_table[i]; - if (strcmp (sym->name, symname) == 0 && (sym->section->flags & (SEC_CODE | SEC_DATA)) != 0) { @@ -172,7 +161,6 @@ lookup_symbol_from_bfd (bfd *abfd, const char *symname) break; } } - xfree (symbol_table); return symaddr; } diff --git a/gdb/solib.c b/gdb/solib.c index 7782c8d..0bbcb02 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -694,14 +694,17 @@ notify_solib_loaded (solib &so) /* Notify interpreters and observers that solib SO has been unloaded. When STILL_IN_USE is true, the objfile backing SO is still in use, this indicates that SO was loaded multiple times, but only mapped - in once (the mapping was reused). */ + in once (the mapping was reused). + + When SILENT is true, don't announce to the user if any breakpoints are + disabled as a result of unloading SO. */ static void notify_solib_unloaded (program_space *pspace, const solib &so, - bool still_in_use) + bool still_in_use, bool silent) { interps_notify_solib_unloaded (so, still_in_use); - gdb::observers::solib_unloaded.notify (pspace, so, still_in_use); + gdb::observers::solib_unloaded.notify (pspace, so, still_in_use, silent); } /* See solib.h. */ @@ -803,7 +806,7 @@ update_solib_list (int from_tty) /* Notify any observer that the shared object has been unloaded before we remove it from GDB's tables. */ notify_solib_unloaded (current_program_space, *gdb_iter, - still_in_use); + still_in_use, false); /* Unless the user loaded it explicitly, free SO's objfile. */ if (gdb_iter->objfile != nullptr @@ -1163,14 +1166,12 @@ clear_solib (program_space *pspace) { const solib_ops *ops = gdbarch_so_ops (current_inferior ()->arch ()); - disable_breakpoints_in_shlibs (pspace); - for (solib &so : pspace->so_list) { bool still_in_use = (so.objfile != nullptr && solib_used (pspace, so)); - notify_solib_unloaded (pspace, so, still_in_use); + notify_solib_unloaded (pspace, so, still_in_use, true); pspace->remove_target_sections (&so); }; @@ -1431,49 +1432,38 @@ CORE_ADDR gdb_bfd_lookup_symbol_from_symtab ( bfd *abfd, gdb::function_view<bool (const asymbol *)> match_sym) { - long storage_needed = bfd_get_symtab_upper_bound (abfd); CORE_ADDR symaddr = 0; + gdb::array_view<asymbol *> symbol_table + = gdb_bfd_canonicalize_symtab (abfd, false); - if (storage_needed > 0) + for (asymbol *sym : symbol_table) { - unsigned int i; - - gdb::def_vector<asymbol *> storage (storage_needed / sizeof (asymbol *)); - asymbol **symbol_table = storage.data (); - unsigned int number_of_symbols - = bfd_canonicalize_symtab (abfd, symbol_table); - - for (i = 0; i < number_of_symbols; i++) + if (match_sym (sym)) { - asymbol *sym = *symbol_table++; - - if (match_sym (sym)) + gdbarch *gdbarch = current_inferior ()->arch (); + symaddr = sym->value; + + /* Some ELF targets fiddle with addresses of symbols they + consider special. They use minimal symbols to do that + and this is needed for correct breakpoint placement, + but we do not have full data here to build a complete + minimal symbol, so just set the address and let the + targets cope with that. */ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && gdbarch_elf_make_msymbol_special_p (gdbarch)) { - gdbarch *gdbarch = current_inferior ()->arch (); - symaddr = sym->value; - - /* Some ELF targets fiddle with addresses of symbols they - consider special. They use minimal symbols to do that - and this is needed for correct breakpoint placement, - but we do not have full data here to build a complete - minimal symbol, so just set the address and let the - targets cope with that. */ - if (bfd_get_flavour (abfd) == bfd_target_elf_flavour - && gdbarch_elf_make_msymbol_special_p (gdbarch)) + struct minimal_symbol msym { - struct minimal_symbol msym - { - }; + }; - msym.set_value_address (symaddr); - gdbarch_elf_make_msymbol_special (gdbarch, sym, &msym); - symaddr = CORE_ADDR (msym.unrelocated_address ()); - } - - /* BFD symbols are section relative. */ - symaddr += sym->section->vma; - break; + msym.set_value_address (symaddr); + gdbarch_elf_make_msymbol_special (gdbarch, sym, &msym); + symaddr = CORE_ADDR (msym.unrelocated_address ()); } + + /* BFD symbols are section relative. */ + symaddr += sym->section->vma; + break; } } diff --git a/gdb/testsuite/gdb.base/filename-completion.exp b/gdb/testsuite/gdb.base/filename-completion.exp index 03ead59..a1dd974 100644 --- a/gdb/testsuite/gdb.base/filename-completion.exp +++ b/gdb/testsuite/gdb.base/filename-completion.exp @@ -381,11 +381,15 @@ proc run_mid_line_completion_tests { root cmd } { proc run_quoting_and_escaping_tests { root } { # Test all the commands which allow quoting of filenames, and # which require whitespace to be escaped in unquoted filenames. - foreach_with_prefix cmd { file exec-file symbol-file add-symbol-file \ - remove-symbol-file \ - "target core" "target exec" "target tfile" \ - "maint print c-tdesc" "compile file" \ - "save gdb-index" "save gdb-index -dwarf-5" } { + set all_cmds { file exec-file symbol-file add-symbol-file \ + remove-symbol-file \ + "target core" "target exec" "target tfile" \ + "maint print c-tdesc" "save gdb-index" + "save gdb-index -dwarf-5" } + if { [allow_compile_tests] } { + lappend all_cmds "compile file" + } + foreach_with_prefix cmd $all_cmds { # Try each test placing the filename as the first argument # then again with a quoted string immediately after the # command. This works because the filename completer will diff --git a/gdb/testsuite/gdb.base/gstack.exp b/gdb/testsuite/gdb.base/gstack.exp index 8df36b1..89be676 100644 --- a/gdb/testsuite/gdb.base/gstack.exp +++ b/gdb/testsuite/gdb.base/gstack.exp @@ -1,4 +1,4 @@ -# Copyright (C) 2024 Free Software Foundation, Inc. +# Copyright (C) 2024-2025 Free Software Foundation, Inc. # 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 @@ -62,8 +62,10 @@ if { ![gdb_assert { ![expr {$res < 0 || $res == ""}] } $test] } { set test "got backtrace" set saw_backtrace false set no_awk false +set location_re ${srcfile}:${decimal} + gdb_expect { - -i "$res" -re "#0 +(0x\[0-9a-f\]+ in )?main \(\).*\r\nGSTACK-END\r\n\$" { + -i "$res" -re "#0 +(0x\[0-9a-f\]+ in )?main \(\).*$location_re.*\r\nGSTACK-END\r\n\$" { set saw_backtrace true pass $test exp_continue diff --git a/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.exp b/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.exp index 45086f6..46561a9 100644 --- a/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.exp +++ b/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.exp @@ -72,77 +72,89 @@ gdb_continue_to_breakpoint "stop at test breakpoint" gdb_test_no_output "source ${pyfile}"\ "import python scripts" -# Check the unbroken stack. -gdb_test_sequence "bt" "backtrace when the unwind is left unbroken" { - "\\r\\n#0 \[^\r\n\]* inline_func \\(\\) at " - "\\r\\n#1 \[^\r\n\]* normal_func \\(\\) at " - "\\r\\n#2 \[^\r\n\]* inline_func \\(\\) at " - "\\r\\n#3 \[^\r\n\]* normal_func \\(\\) at " - "\\r\\n#4 \[^\r\n\]* inline_func \\(\\) at " - "\\r\\n#5 \[^\r\n\]* normal_func \\(\\) at " - "\\r\\n#6 \[^\r\n\]* main \\(\\) at " -} +# Test with and without filters. +foreach bt_cmd { "bt" "bt -no-filters" } { + with_test_prefix "$bt_cmd" { -with_test_prefix "cycle at level 5" { - # Arrange to introduce a stack cycle at frame 5. - gdb_test_no_output "python stop_at_level=5" - gdb_test "maint flush register-cache" \ - "Register cache flushed\\." - gdb_test_lines "bt" "backtrace when the unwind is broken at frame 5" \ - [multi_line \ - "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \ - "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \ - "#2 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \ - "#3 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \ - "#4 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \ - "#5 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \ - "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"] -} + # Check the unbroken stack. + gdb_test_sequence "$bt_cmd" "backtrace when the unwind is left unbroken" { + "\\r\\n#0 \[^\r\n\]* inline_func \\(\\) at " + "\\r\\n#1 \[^\r\n\]* normal_func \\(\\) at " + "\\r\\n#2 \[^\r\n\]* inline_func \\(\\) at " + "\\r\\n#3 \[^\r\n\]* normal_func \\(\\) at " + "\\r\\n#4 \[^\r\n\]* inline_func \\(\\) at " + "\\r\\n#5 \[^\r\n\]* normal_func \\(\\) at " + "\\r\\n#6 \[^\r\n\]* main \\(\\) at " + } -with_test_prefix "cycle at level 3" { - # Arrange to introduce a stack cycle at frame 3. - gdb_test_no_output "python stop_at_level=3" - gdb_test "maint flush register-cache" \ - "Register cache flushed\\." - gdb_test_lines "bt" "backtrace when the unwind is broken at frame 3" \ - [multi_line \ - "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \ - "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \ - "#2 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \ - "#3 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \ - "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"] -} + with_test_prefix "cycle at level 5" { + # Arrange to introduce a stack cycle at frame 5. + gdb_test_no_output "python stop_at_level=5" + gdb_test "maint flush register-cache" \ + "Register cache flushed\\." + gdb_test_lines "$bt_cmd" "backtrace when the unwind is broken at frame 5" \ + [multi_line \ + "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \ + "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \ + "#2 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \ + "#3 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \ + "#4 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \ + "#5 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \ + "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"] + } -with_test_prefix "cycle at level 1" { - # Arrange to introduce a stack cycle at frame 1. - gdb_test_no_output "python stop_at_level=1" - gdb_test "maint flush register-cache" \ - "Register cache flushed\\." - gdb_test_lines "bt" "backtrace when the unwind is broken at frame 1" \ - [multi_line \ - "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \ - "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \ - "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"] -} + with_test_prefix "cycle at level 3" { + # Arrange to introduce a stack cycle at frame 3. + gdb_test_no_output "python stop_at_level=3" + gdb_test "maint flush register-cache" \ + "Register cache flushed\\." + gdb_test_lines "$bt_cmd" "backtrace when the unwind is broken at frame 3" \ + [multi_line \ + "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \ + "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \ + "#2 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \ + "#3 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \ + "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"] + } -# Flush the register cache (which also flushes the frame cache) so we -# get a full backtrace again, then switch on frame debugging and try -# to back trace. At one point this triggered an assertion. -gdb_test "maint flush register-cache" \ - "Register cache flushed\\." "" -gdb_test_no_output "set debug frame 1" -set ok 1 -gdb_test_multiple "bt" "backtrace with debugging on" { - -re "^$gdb_prompt $" { - gdb_assert { $ok } $gdb_test_name - } - -re "Python Exception <class 'gdb.error'>: \[^\r\n\]*\r\n" { - set ok 0 - exp_continue - } - -re "\[^\r\n\]+\r\n" { - exp_continue + with_test_prefix "cycle at level 1" { + # Arrange to introduce a stack cycle at frame 1. + gdb_test_no_output "python stop_at_level=1" + gdb_test "maint flush register-cache" \ + "Register cache flushed\\." + gdb_test_lines "$bt_cmd" "backtrace when the unwind is broken at frame 1" \ + [multi_line \ + "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \ + "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \ + "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"] + } + + # Flush the register cache (which also flushes the frame cache) so we + # get a full backtrace again, then switch on frame debugging and try + # to back trace. At one point this triggered an assertion. + gdb_test "maint flush register-cache" \ + "Register cache flushed\\." "" + gdb_test_no_output "set debug frame 1" + set ok 1 + gdb_test_multiple "$bt_cmd" "backtrace with debugging on" { + -re "^$gdb_prompt $" { + gdb_assert { $ok } $gdb_test_name + } + -re "Python Exception <class 'gdb.error'>: \[^\r\n\]*\r\n" { + set ok 0 + exp_continue + } + -re "\[^\r\n\]+\r\n" { + exp_continue + } + } + gdb_test "p 1 + 2 + 3" " = 6" \ + "ensure GDB is still alive" + + # Prepare for the next iteration of the test loop + gdb_test_no_output "set debug frame 0" + gdb_test_no_output "python stop_at_level=None" + gdb_test "maint flush register-cache" \ + "Register cache flushed\\." "maint flush register-cache at (loop end)" } } -gdb_test "p 1 + 2 + 3" " = 6" \ - "ensure GDB is still alive" diff --git a/gdb/testsuite/gdb.base/options.exp b/gdb/testsuite/gdb.base/options.exp index a1ca39e..8760a91 100644 --- a/gdb/testsuite/gdb.base/options.exp +++ b/gdb/testsuite/gdb.base/options.exp @@ -99,21 +99,21 @@ proc make_cmd {variant} { # operand. proc expect_none {operand} { return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0\ - -string '' -filename '' -- $operand" + -string '' -filename '' -color magenta -- $operand" } # Return a string for the expected result of running "maint # test-options xxx", with -flag set. OPERAND is the expected operand. proc expect_flag {operand} { return "-flag 1 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0\ - -string '' -filename '' -- $operand" + -string '' -filename '' -color magenta -- $operand" } # Return a string for the expected result of running "maint # test-options xxx", with -bool set. OPERAND is the expected operand. proc expect_bool {operand} { return "-flag 0 -xx1 0 -xx2 0 -bool 1 -enum xxx -uint-unl 0 -pint-unl 0\ - -string '' -filename '' -- $operand" + -string '' -filename '' -color magenta -- $operand" } # Return a string for the expected result of running "maint @@ -123,10 +123,10 @@ proc expect_bool {operand} { proc expect_integer {option val operand} { if {$option == "uinteger-unlimited"} { return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl $val\ - -pint-unl 0 -string '' -filename '' -- $operand" + -pint-unl 0 -string '' -filename '' -color magenta -- $operand" } elseif {$option == "pinteger-unlimited"} { return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0\ - -pint-unl $val -string '' -filename '' -- $operand" + -pint-unl $val -string '' -filename '' -color magenta -- $operand" } else { error "unsupported option: $option" } @@ -144,7 +144,7 @@ proc expect_string {str operand} { set str [string range $str 1 end-1] } return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0\ - -string '$str' -filename '' -- $operand" + -string '$str' -filename '' -color magenta -- $operand" } # Return a string for the expected result of running "maint @@ -159,11 +159,12 @@ proc expect_filename {str operand} { set str [string range $str 1 end-1] } return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0\ - -string '' -filename '$str' -- $operand" + -string '' -filename '$str' -color magenta -- $operand" } set all_options { "-bool" + "-color" "-enum" "-filename" "-flag" @@ -628,7 +629,7 @@ proc_with_prefix test-flag {variant} { # Extract twice the same flag, separated by one space. gdb_test "$cmd -xx1 -xx2 -xx1 -xx2 -xx1 -- non flags args" \ "-flag 0 -xx1 1 -xx2 1 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0\ - -string '' -filename '' -- non flags args" + -string '' -filename '' -color magenta -- non flags args" # Extract 2 known flags in front of unknown flags. gdb_test "$cmd -xx1 -xx2 -a -b -c -xx1 --" \ diff --git a/gdb/testsuite/gdb.base/shlib-unload.exp b/gdb/testsuite/gdb.base/shlib-unload.exp index f3e8cce..9d47416 100644 --- a/gdb/testsuite/gdb.base/shlib-unload.exp +++ b/gdb/testsuite/gdb.base/shlib-unload.exp @@ -225,6 +225,75 @@ proc_with_prefix test_dprintf_with_rerun {} { "dprintf is non-pending after restart" } +# Check that we see breakpoint modified events (where appropriate) +# when the 'nosharedlibrary' command is used to unload all shared +# libraries. +# +# Also check that the 'nosharedlibrary' doesn't trigger a warning +# about shared library breakpoints being disabled. +proc_with_prefix test_silent_nosharedlib {} { + if { ![allow_python_tests] } { + unsupported "python support needed" + return + } + + foreach_with_prefix type { breakpoint dprintf } { + clean_restart $::binfile + + if {![runto_main]} { + return + } + + gdb_breakpoint $::srcfile:$::bp_line + gdb_continue_to_breakpoint "stop before dlclose" + + # Setup a dprintf or breakpoint in the shared library. + if { $type eq "breakpoint" } { + gdb_test "break foo" + } else { + gdb_test "dprintf foo,\"In foo\"" + } + + # Record the number of the b/p (or dprintf) we just inserted. + set bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \ + "get b/p number"] + + # Load Python library to track b/p modifications. + gdb_test_no_output "source $::pyfile" "import python scripts" + + # Initialise the b/p modified hash. Currently dprintf style + # breakpoints are not visible from Python, so the modification + # count will remain unchanged in that case. + gdb_test_no_output "python bp_modified_counts\[$bp_num\] = 0" + + # Discard symbols from all loaded shared libraries. + gdb_test_no_output "nosharedlibrary" + + # Check that our b/p is now showing as disabled. + if { $type eq "breakpoint" } { + set re \ + [list "$bp_num\\s+breakpoint\\s+keep\\s+y\\s+<PENDING>\\s+foo"] + set count 1 + } else { + set re \ + [list \ + "$bp_num\\s+dprintf\\s+keep\\s+y\\s+<PENDING>\\s+foo" \ + "\\s+printf \"In foo\""] + set count 0 + } + + gdb_test "info breakpoints $bp_num" \ + [multi_line "^Num\\s+Type\\s+Disp\\s+Enb\\s+Address\\s+What" \ + {*}$re] + + # Check we've seen the expected number of breakpoint modified + # events. Currently dprintf breakpoints are not visible from + # Python, so we will not see an event in that case. + gdb_test "python print(bp_modified_counts\[$bp_num\])" "^$count" + } +} + test_bp_modified_events test_dprintf_after_unload test_dprintf_with_rerun +test_silent_nosharedlib diff --git a/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp index 3e76d38..ddad628 100644 --- a/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp +++ b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp @@ -23,6 +23,8 @@ require allow_cplus_tests require is_c_compiler_gcc +require allow_compile_tests + if {[prepare_for_testing $testfile $testfile $srcfile \ {debug nowarnings c++}]} { return -1 diff --git a/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp index 505a4e1..c7d15ce 100644 --- a/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp +++ b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp @@ -23,6 +23,8 @@ require allow_cplus_tests require is_c_compiler_gcc +require allow_compile_tests + if {[prepare_for_testing $testfile $testfile $srcfile \ {debug nowarnings c++ additional_flags=-std=c++11}]} { return -1 diff --git a/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp b/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp index 1a5f60a..9ef1e83 100644 --- a/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp +++ b/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp @@ -23,6 +23,8 @@ require allow_cplus_tests require is_c_compiler_gcc +require allow_compile_tests + if {[prepare_for_testing $testfile $testfile $srcfile \ {debug nowarnings c++}]} { return -1 diff --git a/gdb/testsuite/gdb.compile/compile-cplus-member.exp b/gdb/testsuite/gdb.compile/compile-cplus-member.exp index 5ffbb30..ac9111c 100644 --- a/gdb/testsuite/gdb.compile/compile-cplus-member.exp +++ b/gdb/testsuite/gdb.compile/compile-cplus-member.exp @@ -23,6 +23,8 @@ require allow_cplus_tests require is_c_compiler_gcc +require allow_compile_tests + if {[prepare_for_testing $testfile $testfile $srcfile \ {debug nowarnings c++}]} { return -1 diff --git a/gdb/testsuite/gdb.compile/compile-cplus-method.exp b/gdb/testsuite/gdb.compile/compile-cplus-method.exp index 0a0e0fa..bcbfbb0 100644 --- a/gdb/testsuite/gdb.compile/compile-cplus-method.exp +++ b/gdb/testsuite/gdb.compile/compile-cplus-method.exp @@ -23,6 +23,8 @@ require allow_cplus_tests require is_c_compiler_gcc +require allow_compile_tests + if {[prepare_for_testing $testfile $testfile $srcfile \ {debug nowarnings c++}]} { return -1 diff --git a/gdb/testsuite/gdb.compile/compile-cplus-namespace.exp b/gdb/testsuite/gdb.compile/compile-cplus-namespace.exp index 3ab8ece..2abc366 100644 --- a/gdb/testsuite/gdb.compile/compile-cplus-namespace.exp +++ b/gdb/testsuite/gdb.compile/compile-cplus-namespace.exp @@ -23,6 +23,8 @@ require allow_cplus_tests require is_c_compiler_gcc +require allow_compile_tests + if {[prepare_for_testing $testfile $testfile $srcfile \ {debug nowarnings c++}]} { return -1 diff --git a/gdb/testsuite/gdb.compile/compile-cplus-nested.exp b/gdb/testsuite/gdb.compile/compile-cplus-nested.exp index 19efd4f..247d270 100644 --- a/gdb/testsuite/gdb.compile/compile-cplus-nested.exp +++ b/gdb/testsuite/gdb.compile/compile-cplus-nested.exp @@ -23,6 +23,8 @@ require allow_cplus_tests require is_c_compiler_gcc +require allow_compile_tests + if {[prepare_for_testing $testfile $testfile $srcfile \ {debug nowarnings c++}]} { return -1 diff --git a/gdb/testsuite/gdb.compile/compile-cplus-print.exp b/gdb/testsuite/gdb.compile/compile-cplus-print.exp index 594f94a..e4413f0 100644 --- a/gdb/testsuite/gdb.compile/compile-cplus-print.exp +++ b/gdb/testsuite/gdb.compile/compile-cplus-print.exp @@ -19,6 +19,8 @@ standard_testfile require is_c_compiler_gcc +require allow_compile_tests + set options {} if [test_compiler_info gcc*] { lappend options additional_flags=-g3 diff --git a/gdb/testsuite/gdb.compile/compile-cplus-virtual.exp b/gdb/testsuite/gdb.compile/compile-cplus-virtual.exp index 8761df5..a770208 100644 --- a/gdb/testsuite/gdb.compile/compile-cplus-virtual.exp +++ b/gdb/testsuite/gdb.compile/compile-cplus-virtual.exp @@ -23,6 +23,8 @@ require allow_cplus_tests require is_c_compiler_gcc +require allow_compile_tests + if {[prepare_for_testing $testfile $testfile $srcfile \ {debug nowarnings c++}]} { return -1 diff --git a/gdb/testsuite/gdb.compile/compile-cplus.exp b/gdb/testsuite/gdb.compile/compile-cplus.exp index 711f299..35ae692 100644 --- a/gdb/testsuite/gdb.compile/compile-cplus.exp +++ b/gdb/testsuite/gdb.compile/compile-cplus.exp @@ -19,6 +19,8 @@ standard_testfile .c compile-shlib.c compile-constvar.S compile-nodebug.c require is_c_compiler_gcc +require allow_compile_tests + set options {} if { [test_compiler_info gcc*] || [test_compiler_info clang*] } { lappend options additional_flags=-g3 diff --git a/gdb/testsuite/gdb.compile/compile-ifunc.exp b/gdb/testsuite/gdb.compile/compile-ifunc.exp index b004bd7..e490890 100644 --- a/gdb/testsuite/gdb.compile/compile-ifunc.exp +++ b/gdb/testsuite/gdb.compile/compile-ifunc.exp @@ -17,6 +17,8 @@ load_lib compile-support.exp require allow_ifunc_tests +require allow_compile_tests + standard_testfile require is_c_compiler_gcc diff --git a/gdb/testsuite/gdb.compile/compile-ops.exp b/gdb/testsuite/gdb.compile/compile-ops.exp index f75e02c..cfbe2b0 100644 --- a/gdb/testsuite/gdb.compile/compile-ops.exp +++ b/gdb/testsuite/gdb.compile/compile-ops.exp @@ -22,6 +22,8 @@ load_lib dwarf.exp # This test can only be run on targets which support DWARF-2 and use gas. require dwarf2_support +require allow_compile_tests + require is_c_compiler_gcc standard_testfile .c -dbg.S diff --git a/gdb/testsuite/gdb.compile/compile-print.exp b/gdb/testsuite/gdb.compile/compile-print.exp index f8f2297..61ce750 100644 --- a/gdb/testsuite/gdb.compile/compile-print.exp +++ b/gdb/testsuite/gdb.compile/compile-print.exp @@ -19,6 +19,8 @@ standard_testfile require is_c_compiler_gcc +require allow_compile_tests + if { [prepare_for_testing "failed to prepare" "$testfile"] } { return -1 } diff --git a/gdb/testsuite/gdb.compile/compile-setjmp.exp b/gdb/testsuite/gdb.compile/compile-setjmp.exp index f387a05..ad8732b 100644 --- a/gdb/testsuite/gdb.compile/compile-setjmp.exp +++ b/gdb/testsuite/gdb.compile/compile-setjmp.exp @@ -19,6 +19,8 @@ standard_testfile .c compile-setjmp-mod.c require is_c_compiler_gcc +require allow_compile_tests + if { [prepare_for_testing "failed to prepare" $testfile] } { return -1 } diff --git a/gdb/testsuite/gdb.compile/compile-tls.exp b/gdb/testsuite/gdb.compile/compile-tls.exp index 2f8dc5a..45e290e 100644 --- a/gdb/testsuite/gdb.compile/compile-tls.exp +++ b/gdb/testsuite/gdb.compile/compile-tls.exp @@ -19,6 +19,8 @@ standard_testfile .c require is_c_compiler_gcc +require allow_compile_tests + if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ executable {debug}] != "" } { return -1 diff --git a/gdb/testsuite/gdb.compile/compile.exp b/gdb/testsuite/gdb.compile/compile.exp index 2c2e321..5128dc62 100644 --- a/gdb/testsuite/gdb.compile/compile.exp +++ b/gdb/testsuite/gdb.compile/compile.exp @@ -15,6 +15,8 @@ load_lib compile-support.exp +require allow_compile_tests + standard_testfile .c compile-shlib.c compile-constvar.S compile-nodebug.c require is_c_compiler_gcc diff --git a/gdb/testsuite/gdb.mi/mi-dprintf-modified-lib.c b/gdb/testsuite/gdb.mi/mi-dprintf-modified-lib.c new file mode 100644 index 0000000..70fc328 --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi-dprintf-modified-lib.c @@ -0,0 +1,22 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2025 Free Software Foundation, Inc. + + 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/>. */ + +int +foo (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.mi/mi-dprintf-modified.c b/gdb/testsuite/gdb.mi/mi-dprintf-modified.c new file mode 100644 index 0000000..7a41adbac --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi-dprintf-modified.c @@ -0,0 +1,55 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2025 Free Software Foundation, Inc. + + 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 <stdlib.h> + +#ifdef __WIN32__ +#include <windows.h> +#define dlopen(name, mode) LoadLibrary (TEXT (name)) +#ifdef _WIN32_WCE +# define dlsym(handle, func) GetProcAddress (handle, TEXT (func)) +#else +# define dlsym(handle, func) GetProcAddress (handle, func) +#endif +#define dlclose(handle) FreeLibrary (handle) +#else +#include <dlfcn.h> +#endif + +#include <assert.h> + +int +main (void) +{ + int res; + void *handle; + int (*func) (void); + int val = 0; + + handle = dlopen (SHLIB_NAME, RTLD_LAZY); /* Break here. */ + assert (handle != NULL); + + func = (int (*)(void)) dlsym (handle, "foo"); + assert (func != NULL); + + val += func (); + + res = dlclose (handle); + assert (res == 0); + + return val; +} diff --git a/gdb/testsuite/gdb.mi/mi-dprintf-modified.exp b/gdb/testsuite/gdb.mi/mi-dprintf-modified.exp new file mode 100644 index 0000000..c3e1bdf --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi-dprintf-modified.exp @@ -0,0 +1,119 @@ +# Copyright 2025 Free Software Foundation, Inc. + +# 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/>. + +# Check that GDB doesn't emit a 'breakpoint-modified' notification for +# dprintf breakpoints when the dprintf commands haven't changed. +# +# GDB use to emit a 'breakpoint-modified' dprintf breakpoints each +# time the dprintf_breakpoint::re_set function was called as this +# would re-cacluate the dprintf command string, even though in most +# cases the calculated string was no different from the previous +# value. +# +# Then GDB got smarter and could recognise that the string had not +# changed, and so would skip the 'breakpoint-modified' notification. +# +# This test stops at a dlopen() call in the inferior and creates a +# dprintf breakpoint. Then we 'next' over the dlopen() which triggers +# a call to the ::re_set() functions. We check that there is no +# 'breakpoint-modified' event emitted for the dprintf breakpoint. + +load_lib mi-support.exp +set MIFLAGS "-i=mi" + +standard_testfile .c -lib.c + +# Build the library. +set libname ${testfile}-lib +set libfile [standard_output_file $libname] +if { [build_executable "build shlib" $libfile $srcfile2 {debug shlib}] == -1} { + return +} + +# Build the executable. +set opts [list debug shlib_load additional_flags=-DSHLIB_NAME=\"${libname}\"] +if { [build_executable "build exec" $binfile $srcfile $opts] == -1} { + return +} + +# The line number of the dlopen() call. +set bp_line [gdb_get_line_number "Break here" $srcfile] + +# Start the inferior. +mi_clean_restart $binfile +mi_runto_main + +# Place a breakpoint at the dlopen() line. +mi_create_breakpoint $srcfile:$bp_line "set breakpoint at dlopen call" \ + -disp keep -func main -file "\[^\r\n\]+/$srcfile" -line $bp_line + +# And run to the breakpoint. +mi_execute_to "exec-continue" "breakpoint-hit" main "" ".*/$srcfile" \ + $bp_line { "" "disp=\"keep\"" } "run to breakpoint" + +# Cleanup breakpoints. +mi_delete_breakpoints + +# Setup a dprintf breakpoint. +mi_gdb_test "-dprintf-insert --function main \"in main\"" \ + "\\^done,bkpt={.*}" "dprintf at main" + +set bpnum [mi_get_valueof "/d" "\$bpnum" "INVALID" \ + "get number for dprintf breakpoint"] + +# Use 'next' to step over loading the shared library. +mi_gdb_test "220-exec-next" ".*" "next over dlopen" + +# Now wait for the 'stopped' notification. While we wait we should +# see a 'library-loaded' notification for the loading of the shared +# library. +# +# In older versions of GDB we would also see a 'breakpoint-modified' +# notification for the dprintf breakpoint, but newer versions of GDB +# are smart enough to not emit this unnecessary notification. +set bp_re [mi_make_breakpoint -number $bpnum \ + -type dprintf -disp keep -enabled y -func main] +set saw_bp_modified false +set saw_lib_load false +set saw_stopped false +gdb_test_multiple "" "wait for 'next' to complete" { + -re "^=library-loaded,id=\[^\r\n\]+\r\n" { + set saw_lib_load true + exp_continue + } + + -re "^=breakpoint-modified,$bp_re\r\n" { + set saw_bp_modified true + exp_continue + } + + -re "^\\*stopped,reason=\"end-stepping-range\",\[^\r\n\]+\r\n" { + set saw_stopped true + exp_continue + } + + -re "^$mi_gdb_prompt$" { + gdb_assert { $saw_lib_load } \ + "$gdb_test_name, library was loaded" + gdb_assert { $saw_stopped } \ + "$gdb_test_name, saw stopped message" + gdb_assert { !$saw_bp_modified } \ + "$gdb_test_name, no breakpoint-modified" + } + + -re "^\[^\r\n\]+\r\n" { + exp_continue + } +} diff --git a/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.c b/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.c index af05b13..e22bf12 100644 --- a/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.c +++ b/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.c @@ -97,6 +97,11 @@ thread_fn (void *arg) return NULL; } +static void +setup_done (void) +{ +} + int main (void) { @@ -104,6 +109,8 @@ main (void) global_var++; + setup_done (); + for (i = 0; i < 4; i++) { struct thread_arg *p; diff --git a/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.exp b/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.exp index 784f17f..42222c0 100644 --- a/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.exp +++ b/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.exp @@ -54,7 +54,7 @@ proc test { non_stop } { clean_restart ${binfile} } - if ![runto_main] { + if ![runto setup_done] { return -1 } @@ -76,7 +76,7 @@ proc test { non_stop } { # Start the second inferior. with_test_prefix "second inferior" { # With stub targets that do reload on run, if we let the new - # inferior share inferior 1's connection, runto_main would + # inferior share inferior 1's connection, runto would # fail because GDB is already connected to something, like # e.g. with --target_board=native-gdbserver: # @@ -86,10 +86,10 @@ proc test { non_stop } { # Already connected to a remote target. Disconnect? (y or n) # # Instead, start the inferior with no connection, and let - # gdb_load/runto_main spawn a new remote connection/gdbserver. + # gdb_load/runto spawn a new remote connection/gdbserver. # # OTOH, with extended-remote, we must let the new inferior - # reuse the current connection, so that runto_main below can + # reuse the current connection, so that runto below can # issue the "run" command, and have the inferior run on the # remote target. If we forced no connection, then "run" would # either fail if "set auto-connect-native-target" is on, like @@ -108,7 +108,7 @@ proc test { non_stop } { gdb_load $binfile - if ![runto_main] { + if ![runto setup_done] { return -1 } } diff --git a/gdb/testsuite/lib/compile-support.exp b/gdb/testsuite/lib/compile-support.exp index aa8aaf3..6d7a4ce 100644 --- a/gdb/testsuite/lib/compile-support.exp +++ b/gdb/testsuite/lib/compile-support.exp @@ -45,6 +45,9 @@ proc _do_check_compile {expr} { # This appears to be a bug in the compiler plugin. set result "apparent compiler plugin bug" } + -re "This command is not supported." { + set result "compiler disabled at configure time" + } -re "\r\n$gdb_prompt $" { } } diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 3349da7..761a4f1 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -2799,6 +2799,12 @@ gdb_caching_proc allow_python_tests {} { return [expr {[string first "--with-python" $output] != -1}] } +# Return a 1 if GDB was configured to support compile commands. +gdb_caching_proc allow_compile_tests {} { + set output [remote_exec host $::GDB "$::INTERNAL_GDBFLAGS -ex \"compile int x = 1\" -batch"] + return [expr {[string first "The program must be running" $output] != -1}] +} + # Return a 1 for configurations that use system readline rather than the # in-repo copy. @@ -5940,6 +5946,23 @@ proc gdb_compile {source dest type options} { } } + # On AIX systems, until GCC 12 (maybe later), stabs was the default + # debug option, but we'd like to have dwarf instead. + # If we're running on one of those systems and debug was requested, + # but no explicit -g<format> option was given, use -gdwarf to force + # that as the debug info for the inferior. + # This list should be exhaustive: + set debug_format "btf|ctf|stabs|vms|coff|xcoff" + # Since additional_flags is a comma separated list, identify if there + # are other (optional) flags in the list. + set other_options "-\[a-zA-Z0-9\]*," + set full_regexp "^additional_flags=\($other_options\)*-g\($debug_format\)" + if { [istarget *-*-aix*] + && [lsearch -exact $options debug] != -1 + && [lsearch -regexp $options $full_regexp] == -1} { + lappend new_options "additional_flags=-gdwarf" + } + set shlib_found 0 set shlib_load 0 foreach opt $options { |