From e2207b9a2828674a1deaf98db4ab4d0079b96d34 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Tue, 17 Apr 2012 15:49:16 +0000 Subject: [PATCH] gdb/ auto-load: Move files. * Makefile.in (SFILES): Add auto-load.c. (HFILES_NO_SRCDIR): Add auto-load.h. (COMMON_OBS): Add auto-load.o. (distclean): Change .gdbinit for gdb-gdb.gdb. * auto-load.c: New file, with parts from python/py-auto-load.c. * auto-load.h: New file, with parts from python/python.h. * configure: Regenerate. * configure.ac (AC_OUTPUT): Change .gdbinit for gdb-gdb.gdb. * gdb-gdb.gdb.in: New file, renamed from gdbinit.in. * gdbinit.in: Remove file, rename it to gdb-gdb.gdb.in. * main.c: Include auto-load.h. * python/py-auto-load.c: Move include filenames.h, gdb_regex.h, command.h, observer.h and progspace.h to auto-load.c. Add include auto-load.h. (gdbpy_global_auto_load, struct auto_load_pspace_info) (struct loaded_script, auto_load_pspace_data) (auto_load_pspace_data_cleanup, get_auto_load_pspace_data) (hash_loaded_script_entry, eq_loaded_script_entry) (init_loaded_scripts_info, get_auto_load_pspace_data_for_loading) (maybe_add_script): Move to auto-load.c. (source_section_scripts): Change maybe_add_script parameters passing, use script_not_found_warning_print. (clear_section_scripts, auto_load_objfile_script) (auto_load_new_objfile, loaded_script_ptr) (DEF_VEC_P (loaded_script_ptr), collect_matching_scripts, print_script) (sort_scripts_by_name, info_auto_load_scripts): Move to auto-load.c. (gdbpy_initialize_auto_load): Move auto_load_pspace_data, auto_load_new_objfile and info_auto_load_scripts initizations to auto-load.c. * python/python.h (gdbpy_global_auto_load): Move to auto-load.h. --- gdb/ChangeLog | 34 +++ gdb/Makefile.in | 8 +- gdb/auto-load.c | 472 +++++++++++++++++++++++++++++ gdb/auto-load.h | 36 +++ gdb/configure | 4 +- gdb/configure.ac | 2 +- gdb/{gdbinit.in => gdb-gdb.gdb.in} | 0 gdb/main.c | 1 + gdb/python/py-auto-load.c | 437 +------------------------- gdb/python/python.h | 2 - 10 files changed, 555 insertions(+), 441 deletions(-) create mode 100644 gdb/auto-load.c create mode 100644 gdb/auto-load.h rename gdb/{gdbinit.in => gdb-gdb.gdb.in} (100%) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 6f9608a5f4..0f209dda7b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,37 @@ +2012-04-17 Jan Kratochvil + + auto-load: Move files. + * Makefile.in (SFILES): Add auto-load.c. + (HFILES_NO_SRCDIR): Add auto-load.h. + (COMMON_OBS): Add auto-load.o. + (distclean): Change .gdbinit for gdb-gdb.gdb. + * auto-load.c: New file, with parts from python/py-auto-load.c. + * auto-load.h: New file, with parts from python/python.h. + * configure: Regenerate. + * configure.ac (AC_OUTPUT): Change .gdbinit for gdb-gdb.gdb. + * gdb-gdb.gdb.in: New file, renamed from gdbinit.in. + * gdbinit.in: Remove file, rename it to gdb-gdb.gdb.in. + * main.c: Include auto-load.h. + * python/py-auto-load.c: Move include filenames.h, gdb_regex.h, + command.h, observer.h and progspace.h to auto-load.c. Add include + auto-load.h. + (gdbpy_global_auto_load, struct auto_load_pspace_info) + (struct loaded_script, auto_load_pspace_data) + (auto_load_pspace_data_cleanup, get_auto_load_pspace_data) + (hash_loaded_script_entry, eq_loaded_script_entry) + (init_loaded_scripts_info, get_auto_load_pspace_data_for_loading) + (maybe_add_script): Move to auto-load.c. + (source_section_scripts): Change maybe_add_script parameters passing, + use script_not_found_warning_print. + (clear_section_scripts, auto_load_objfile_script) + (auto_load_new_objfile, loaded_script_ptr) + (DEF_VEC_P (loaded_script_ptr), collect_matching_scripts, print_script) + (sort_scripts_by_name, info_auto_load_scripts): Move to auto-load.c. + (gdbpy_initialize_auto_load): Move auto_load_pspace_data, + auto_load_new_objfile and info_auto_load_scripts initizations to + auto-load.c. + * python/python.h (gdbpy_global_auto_load): Move to auto-load.h. + 2012-04-17 Jan Kratochvil Code cleanup. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index b8b7109985..21fe3a7867 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -683,7 +683,7 @@ TARGET_FLAGS_TO_PASS = \ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ ada-varobj.c \ - addrmap.c \ + addrmap.c auto-load.c \ auxv.c ax-general.c ax-gdb.c \ agent.c \ bcache.c \ @@ -823,7 +823,7 @@ solib-darwin.h solib-ia64-hpux.h solib-spu.h windows-nat.h xcoffread.h \ gnulib/extra/arg-nonnull.h gnulib/extra/c++defs.h gnulib/extra/warn-on-use.h \ gnulib/stddef.in.h gnulib/inttypes.in.h inline-frame.h skip.h \ common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \ -common/linux-osdata.h gdb-dlfcn.h +common/linux-osdata.h gdb-dlfcn.h auto-load.h # Header files that already have srcdir in them, or which are in objdir. @@ -855,7 +855,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ version.o \ annotate.o \ addrmap.o \ - auxv.o \ + auto-load.o auxv.o \ agent.o \ bfd-target.o \ blockframe.o breakpoint.o findvar.o regcache.o \ @@ -1221,7 +1221,7 @@ distclean: clean rm -f gdbserver/config.status gdbserver/config.log rm -f gdbserver/tm.h gdbserver/xm.h gdbserver/nm.h rm -f gdbserver/Makefile gdbserver/config.cache - rm -f nm.h config.status config.h stamp-h .gdbinit jit-reader.h + rm -f nm.h config.status config.h stamp-h gdb-gdb.gdb jit-reader.h rm -f y.output yacc.acts yacc.tmp y.tab.h rm -f config.log config.cache rm -f Makefile diff --git a/gdb/auto-load.c b/gdb/auto-load.c new file mode 100644 index 0000000000..1a8f72f1d3 --- /dev/null +++ b/gdb/auto-load.c @@ -0,0 +1,472 @@ +/* GDB routines for supporting auto-loaded scripts. + + Copyright (C) 2012 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "auto-load.h" +#include "progspace.h" +#include "python/python.h" +#include "gdb_regex.h" +#include "ui-out.h" +#include "filenames.h" +#include "command.h" +#include "observer.h" +#include "objfiles.h" +#include "python/python-internal.h" + +/* Internal-use flag to enable/disable auto-loading. + This is true if we should auto-load python code when an objfile is opened, + false otherwise. + + Both auto_load_scripts && gdbpy_global_auto_load must be true to enable + auto-loading. + + This flag exists to facilitate deferring auto-loading during start-up + until after ./.gdbinit has been read; it may augment the search directories + used to find the scripts. */ +int gdbpy_global_auto_load = 1; + +/* For scripts specified in .debug_gdb_scripts, multiple objfiles may load + the same script. There's no point in loading the script multiple times, + and there can be a lot of objfiles and scripts, so we keep track of scripts + loaded this way. */ + +struct auto_load_pspace_info +{ + /* For each program space we keep track of loaded scripts. */ + struct htab *loaded_scripts; + + /* Non-zero if we've issued the warning about an auto-load script not being + found. We only want to issue this warning once. */ + int script_not_found_warning_printed; +}; + +/* Objects of this type are stored in the loaded script hash table. */ + +struct loaded_script +{ + /* Name as provided by the objfile. */ + const char *name; + /* Full path name or NULL if script wasn't found (or was otherwise + inaccessible). */ + const char *full_path; +}; + +/* Per-program-space data key. */ +static const struct program_space_data *auto_load_pspace_data; + +static void +auto_load_pspace_data_cleanup (struct program_space *pspace, void *arg) +{ + struct auto_load_pspace_info *info; + + info = program_space_data (pspace, auto_load_pspace_data); + if (info != NULL) + { + if (info->loaded_scripts) + htab_delete (info->loaded_scripts); + xfree (info); + } +} + +/* Get the current autoload data. If none is found yet, add it now. This + function always returns a valid object. */ + +static struct auto_load_pspace_info * +get_auto_load_pspace_data (struct program_space *pspace) +{ + struct auto_load_pspace_info *info; + + info = program_space_data (pspace, auto_load_pspace_data); + if (info == NULL) + { + info = XZALLOC (struct auto_load_pspace_info); + set_program_space_data (pspace, auto_load_pspace_data, info); + } + + return info; +} + +/* Hash function for the loaded script hash. */ + +static hashval_t +hash_loaded_script_entry (const void *data) +{ + const struct loaded_script *e = data; + + return htab_hash_string (e->name); +} + +/* Equality function for the loaded script hash. */ + +static int +eq_loaded_script_entry (const void *a, const void *b) +{ + const struct loaded_script *ea = a; + const struct loaded_script *eb = b; + + return strcmp (ea->name, eb->name) == 0; +} + +/* Initialize the table to track loaded scripts. + Each entry is hashed by the full path name. */ + +static void +init_loaded_scripts_info (struct auto_load_pspace_info *pspace_info) +{ + /* Choose 31 as the starting size of the hash table, somewhat arbitrarily. + Space for each entry is obtained with one malloc so we can free them + easily. */ + + pspace_info->loaded_scripts = htab_create (31, + hash_loaded_script_entry, + eq_loaded_script_entry, + xfree); + + pspace_info->script_not_found_warning_printed = FALSE; +} + +/* Wrapper on get_auto_load_pspace_data to also allocate the hash table + for loading scripts. */ + +struct auto_load_pspace_info * +get_auto_load_pspace_data_for_loading (struct program_space *pspace) +{ + struct auto_load_pspace_info *info; + + info = get_auto_load_pspace_data (pspace); + if (info->loaded_scripts == NULL) + init_loaded_scripts_info (info); + + return info; +} + +/* Add script NAME to hash table of PSPACE_INFO. + FULL_PATH is NULL if the script wasn't found. + The result is true if the script was already in the hash table. */ + +int +maybe_add_script (struct auto_load_pspace_info *pspace_info, const char *name, + const char *full_path) +{ + struct htab *htab = pspace_info->loaded_scripts; + struct loaded_script **slot, entry; + int in_hash_table; + + entry.name = name; + entry.full_path = full_path; + slot = (struct loaded_script **) htab_find_slot (htab, &entry, INSERT); + in_hash_table = *slot != NULL; + + /* If this script is not in the hash table, add it. */ + + if (! in_hash_table) + { + char *p; + + /* Allocate all space in one chunk so it's easier to free. */ + *slot = xmalloc (sizeof (**slot) + + strlen (name) + 1 + + (full_path != NULL ? (strlen (full_path) + 1) : 0)); + p = ((char*) *slot) + sizeof (**slot); + strcpy (p, name); + (*slot)->name = p; + if (full_path != NULL) + { + p += strlen (p) + 1; + strcpy (p, full_path); + (*slot)->full_path = p; + } + else + (*slot)->full_path = NULL; + } + + return in_hash_table; +} + +/* Clear the table of loaded section scripts. */ + +static void +clear_section_scripts (void) +{ + struct program_space *pspace = current_program_space; + struct auto_load_pspace_info *info; + + info = program_space_data (pspace, auto_load_pspace_data); + if (info != NULL && info->loaded_scripts != NULL) + { + htab_delete (info->loaded_scripts); + info->loaded_scripts = NULL; + info->script_not_found_warning_printed = FALSE; + } +} + +/* Look for the auto-load script associated with OBJFILE and load it. */ + +void +auto_load_objfile_script (struct objfile *objfile, const char *suffix) +{ + char *realname; + char *filename, *debugfile; + int len; + FILE *input; + struct cleanup *cleanups; + + realname = gdb_realpath (objfile->name); + len = strlen (realname); + filename = xmalloc (len + strlen (suffix) + 1); + memcpy (filename, realname, len); + strcpy (filename + len, suffix); + + cleanups = make_cleanup (xfree, filename); + make_cleanup (xfree, realname); + + input = fopen (filename, "r"); + debugfile = filename; + + if (!input && debug_file_directory) + { + /* Also try the same file in the separate debug info directory. */ + debugfile = xmalloc (strlen (filename) + + strlen (debug_file_directory) + 1); + strcpy (debugfile, debug_file_directory); + /* FILENAME is absolute, so we don't need a "/" here. */ + strcat (debugfile, filename); + + make_cleanup (xfree, debugfile); + input = fopen (debugfile, "r"); + } + + if (!input && gdb_datadir) + { + /* Also try the same file in a subdirectory of gdb's data + directory. */ + debugfile = xmalloc (strlen (gdb_datadir) + strlen (filename) + + strlen ("/auto-load") + 1); + strcpy (debugfile, gdb_datadir); + strcat (debugfile, "/auto-load"); + /* FILENAME is absolute, so we don't need a "/" here. */ + strcat (debugfile, filename); + + make_cleanup (xfree, debugfile); + input = fopen (debugfile, "r"); + } + + if (input) + { + struct auto_load_pspace_info *pspace_info; + + make_cleanup_fclose (input); + + /* Add this script to the hash table too so "info auto-load-scripts" + can print it. */ + pspace_info = + get_auto_load_pspace_data_for_loading (current_program_space); + maybe_add_script (pspace_info, debugfile, debugfile); + + /* To preserve existing behaviour we don't check for whether the + script was already in the table, and always load it. + It's highly unlikely that we'd ever load it twice, + and these scripts are required to be idempotent under multiple + loads anyway. */ + source_python_script_for_objfile (objfile, input, debugfile); + } + + do_cleanups (cleanups); +} + +/* This is a new_objfile observer callback to auto-load scripts. + + Two flavors of auto-loaded scripts are supported. + 1) based on the path to the objfile + 2) from .debug_gdb_scripts section */ + +static void +auto_load_new_objfile (struct objfile *objfile) +{ + if (!objfile) + { + /* OBJFILE is NULL when loading a new "main" symbol-file. */ + clear_section_scripts (); + return; + } + + load_auto_scripts_for_objfile (objfile); +} + +/* Collect scripts to be printed in a vec. */ + +typedef struct loaded_script *loaded_script_ptr; +DEF_VEC_P (loaded_script_ptr); + +/* Traversal function for htab_traverse. + Collect the entry if it matches the regexp. */ + +static int +collect_matching_scripts (void **slot, void *info) +{ + struct loaded_script *script = *slot; + VEC (loaded_script_ptr) **scripts_ptr = info; + + if (re_exec (script->name)) + VEC_safe_push (loaded_script_ptr, *scripts_ptr, script); + + return 1; +} + +/* Print SCRIPT. */ + +static void +print_script (struct loaded_script *script) +{ + struct ui_out *uiout = current_uiout; + struct cleanup *chain; + + chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); + + ui_out_field_string (uiout, "loaded", script->full_path ? "Yes" : "Missing"); + ui_out_field_string (uiout, "script", script->name); + ui_out_text (uiout, "\n"); + + /* If the name isn't the full path, print it too. */ + if (script->full_path != NULL + && strcmp (script->name, script->full_path) != 0) + { + ui_out_text (uiout, "\tfull name: "); + ui_out_field_string (uiout, "full_path", script->full_path); + ui_out_text (uiout, "\n"); + } + + do_cleanups (chain); +} + +/* Helper for info_auto_load_scripts to sort the scripts by name. */ + +static int +sort_scripts_by_name (const void *ap, const void *bp) +{ + const struct loaded_script *a = *(const struct loaded_script **) ap; + const struct loaded_script *b = *(const struct loaded_script **) bp; + + return FILENAME_CMP (a->name, b->name); +} + +/* "info auto-load-scripts" command. */ + +static void +info_auto_load_scripts (char *pattern, int from_tty) +{ + struct ui_out *uiout = current_uiout; + struct auto_load_pspace_info *pspace_info; + struct cleanup *script_chain; + VEC (loaded_script_ptr) *scripts; + int nr_scripts; + + dont_repeat (); + + pspace_info = get_auto_load_pspace_data (current_program_space); + + if (pattern && *pattern) + { + char *re_err = re_comp (pattern); + + if (re_err) + error (_("Invalid regexp: %s"), re_err); + } + else + { + re_comp (""); + } + + /* We need to know the number of rows before we build the table. + Plus we want to sort the scripts by name. + So first traverse the hash table collecting the matching scripts. */ + + scripts = VEC_alloc (loaded_script_ptr, 10); + script_chain = make_cleanup (VEC_cleanup (loaded_script_ptr), &scripts); + + if (pspace_info != NULL && pspace_info->loaded_scripts != NULL) + { + immediate_quit++; + /* Pass a pointer to scripts as VEC_safe_push can realloc space. */ + htab_traverse_noresize (pspace_info->loaded_scripts, + collect_matching_scripts, &scripts); + immediate_quit--; + } + + nr_scripts = VEC_length (loaded_script_ptr, scripts); + make_cleanup_ui_out_table_begin_end (uiout, 2, nr_scripts, + "AutoLoadedScriptsTable"); + + ui_out_table_header (uiout, 7, ui_left, "loaded", "Loaded"); + ui_out_table_header (uiout, 70, ui_left, "script", "Script"); + ui_out_table_body (uiout); + + if (nr_scripts > 0) + { + int i; + loaded_script_ptr script; + + qsort (VEC_address (loaded_script_ptr, scripts), + VEC_length (loaded_script_ptr, scripts), + sizeof (loaded_script_ptr), sort_scripts_by_name); + for (i = 0; VEC_iterate (loaded_script_ptr, scripts, i, script); ++i) + print_script (script); + } + + do_cleanups (script_chain); + + if (nr_scripts == 0) + { + if (pattern && *pattern) + ui_out_message (uiout, 0, "No auto-load scripts matching %s.\n", + pattern); + else + ui_out_message (uiout, 0, "No auto-load scripts.\n"); + } +} + +/* Return non-zero if SCRIPT_NOT_FOUND_WARNING_PRINTED of PSPACE_INFO was unset + before calling this function. Always set SCRIPT_NOT_FOUND_WARNING_PRINTED + of PSPACE_INFO. */ + +int +script_not_found_warning_print (struct auto_load_pspace_info *pspace_info) +{ + int retval = !pspace_info->script_not_found_warning_printed; + + pspace_info->script_not_found_warning_printed = 1; + + return retval; +} + +void _initialize_auto_load (void); + +void +_initialize_auto_load (void) +{ + auto_load_pspace_data + = register_program_space_data_with_cleanup (auto_load_pspace_data_cleanup); + + observer_attach_new_objfile (auto_load_new_objfile); + + add_info ("auto-load-scripts", + info_auto_load_scripts, + _("Print the list of automatically loaded scripts.\n\ +Usage: info auto-load-scripts [REGEXP]")); +} diff --git a/gdb/auto-load.h b/gdb/auto-load.h new file mode 100644 index 0000000000..c026696da8 --- /dev/null +++ b/gdb/auto-load.h @@ -0,0 +1,36 @@ +/* GDB routines for supporting auto-loaded scripts. + + Copyright (C) 2012 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef AUTO_LOAD_H +#define AUTO_LOAD_H 1 + +struct program_space; + +extern int gdbpy_global_auto_load; + +extern struct auto_load_pspace_info * + get_auto_load_pspace_data_for_loading (struct program_space *pspace); +extern int maybe_add_script (struct auto_load_pspace_info *pspace_info, + const char *name, const char *full_path); +extern void auto_load_objfile_script (struct objfile *objfile, + const char *suffix); +extern int + script_not_found_warning_print (struct auto_load_pspace_info *pspace_info); + +#endif /* AUTO_LOAD_H */ diff --git a/gdb/configure b/gdb/configure index 71ae0b29f2..15741b5750 100755 --- a/gdb/configure +++ b/gdb/configure @@ -17649,7 +17649,7 @@ ac_config_links="$ac_config_links $ac_config_links_1" $as_echo "#define GDB_DEFAULT_HOST_CHARSET \"UTF-8\"" >>confdefs.h -ac_config_files="$ac_config_files Makefile .gdbinit:gdbinit.in doc/Makefile gnulib/Makefile data-directory/Makefile" +ac_config_files="$ac_config_files Makefile gdb-gdb.gdb doc/Makefile gnulib/Makefile data-directory/Makefile" ac_config_commands="$ac_config_commands default" @@ -18415,7 +18415,7 @@ do "jit-reader.h") CONFIG_FILES="$CONFIG_FILES jit-reader.h:jit-reader.in" ;; "$ac_config_links_1") CONFIG_LINKS="$CONFIG_LINKS $ac_config_links_1" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - ".gdbinit") CONFIG_FILES="$CONFIG_FILES .gdbinit:gdbinit.in" ;; + "gdb-gdb.gdb") CONFIG_FILES="$CONFIG_FILES gdb-gdb.gdb" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; "gnulib/Makefile") CONFIG_FILES="$CONFIG_FILES gnulib/Makefile" ;; "data-directory/Makefile") CONFIG_FILES="$CONFIG_FILES data-directory/Makefile" ;; diff --git a/gdb/configure.ac b/gdb/configure.ac index 5867782c89..8672ca620a 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -2230,7 +2230,7 @@ dnl At the moment, we just assume it's UTF-8. AC_DEFINE(GDB_DEFAULT_HOST_CHARSET, "UTF-8", [Define to be a string naming the default host character set.]) -AC_OUTPUT(Makefile .gdbinit:gdbinit.in doc/Makefile gnulib/Makefile data-directory/Makefile, +AC_OUTPUT(Makefile gdb-gdb.gdb doc/Makefile gnulib/Makefile data-directory/Makefile, [ case x$CONFIG_HEADERS in xconfig.h:config.in) diff --git a/gdb/gdbinit.in b/gdb/gdb-gdb.gdb.in similarity index 100% rename from gdb/gdbinit.in rename to gdb/gdb-gdb.gdb.in diff --git a/gdb/main.c b/gdb/main.c index e528cd18ad..a22edbf2fa 100644 --- a/gdb/main.c +++ b/gdb/main.c @@ -41,6 +41,7 @@ #include "cli/cli-cmds.h" #include "python/python.h" #include "objfiles.h" +#include "auto-load.h" /* The selected interpreter. This will be used as a set command variable, so it should always be malloc'ed - since diff --git a/gdb/python/py-auto-load.c b/gdb/python/py-auto-load.c index 14e75a7220..a80960b266 100644 --- a/gdb/python/py-auto-load.c +++ b/gdb/python/py-auto-load.c @@ -18,30 +18,14 @@ along with this program. If not, see . */ #include "defs.h" -#include "filenames.h" #include "gdb_string.h" -#include "gdb_regex.h" #include "top.h" #include "exceptions.h" -#include "command.h" #include "gdbcmd.h" -#include "observer.h" -#include "progspace.h" #include "objfiles.h" #include "python.h" #include "cli/cli-cmds.h" - -/* Internal-use flag to enable/disable auto-loading. - This is true if we should auto-load python code when an objfile is opened, - false otherwise. - - Both auto_load_scripts && gdbpy_global_auto_load must be true to enable - auto-loading. - - This flag exists to facilitate deferring auto-loading during start-up - until after ./.gdbinit has been read; it may augment the search directories - used to find the scripts. */ -int gdbpy_global_auto_load = 1; +#include "auto-load.h" #ifdef HAVE_PYTHON @@ -60,32 +44,6 @@ int gdbpy_global_auto_load = 1; The leading byte is to allow upward compatible extensions. */ #define GDBPY_AUTO_SECTION_NAME ".debug_gdb_scripts" -/* For scripts specified in .debug_gdb_scripts, multiple objfiles may load - the same script. There's no point in loading the script multiple times, - and there can be a lot of objfiles and scripts, so we keep track of scripts - loaded this way. */ - -struct auto_load_pspace_info -{ - /* For each program space we keep track of loaded scripts. */ - struct htab *loaded_scripts; - - /* Non-zero if we've issued the warning about an auto-load script not being - found. We only want to issue this warning once. */ - int script_not_found_warning_printed; -}; - -/* Objects of this type are stored in the loaded script hash table. */ - -struct loaded_script -{ - /* Name as provided by the objfile. */ - const char *name; - /* Full path name or NULL if script wasn't found (or was otherwise - inaccessible). */ - const char *full_path; -}; - /* User-settable option to enable/disable auto-loading: set auto-load-scripts on|off This is true if we should auto-load associated scripts when an objfile @@ -97,136 +55,6 @@ struct loaded_script The fact that it lives here is just an implementation detail. */ static int auto_load_scripts = 1; -/* Per-program-space data key. */ -static const struct program_space_data *auto_load_pspace_data; - -static void -auto_load_pspace_data_cleanup (struct program_space *pspace, void *arg) -{ - struct auto_load_pspace_info *info; - - info = program_space_data (pspace, auto_load_pspace_data); - if (info != NULL) - { - if (info->loaded_scripts) - htab_delete (info->loaded_scripts); - xfree (info); - } -} - -/* Get the current autoload data. If none is found yet, add it now. This - function always returns a valid object. */ - -static struct auto_load_pspace_info * -get_auto_load_pspace_data (struct program_space *pspace) -{ - struct auto_load_pspace_info *info; - - info = program_space_data (pspace, auto_load_pspace_data); - if (info == NULL) - { - info = XZALLOC (struct auto_load_pspace_info); - set_program_space_data (pspace, auto_load_pspace_data, info); - } - - return info; -} - -/* Hash function for the loaded script hash. */ - -static hashval_t -hash_loaded_script_entry (const void *data) -{ - const struct loaded_script *e = data; - - return htab_hash_string (e->name); -} - -/* Equality function for the loaded script hash. */ - -static int -eq_loaded_script_entry (const void *a, const void *b) -{ - const struct loaded_script *ea = a; - const struct loaded_script *eb = b; - - return strcmp (ea->name, eb->name) == 0; -} - -/* Initialize the table to track loaded scripts. - Each entry is hashed by the full path name. */ - -static void -init_loaded_scripts_info (struct auto_load_pspace_info *pspace_info) -{ - /* Choose 31 as the starting size of the hash table, somewhat arbitrarily. - Space for each entry is obtained with one malloc so we can free them - easily. */ - - pspace_info->loaded_scripts = htab_create (31, - hash_loaded_script_entry, - eq_loaded_script_entry, - xfree); - - pspace_info->script_not_found_warning_printed = FALSE; -} - -/* Wrapper on get_auto_load_pspace_data to also allocate the hash table - for loading scripts. */ - -static struct auto_load_pspace_info * -get_auto_load_pspace_data_for_loading (struct program_space *pspace) -{ - struct auto_load_pspace_info *info; - - info = get_auto_load_pspace_data (pspace); - if (info->loaded_scripts == NULL) - init_loaded_scripts_info (info); - - return info; -} - -/* Add script NAME to hash table HTAB. - FULL_PATH is NULL if the script wasn't found. - The result is true if the script was already in the hash table. */ - -static int -maybe_add_script (struct htab *htab, const char *name, const char *full_path) -{ - struct loaded_script **slot, entry; - int in_hash_table; - - entry.name = name; - entry.full_path = full_path; - slot = (struct loaded_script **) htab_find_slot (htab, &entry, INSERT); - in_hash_table = *slot != NULL; - - /* If this script is not in the hash table, add it. */ - - if (! in_hash_table) - { - char *p; - - /* Allocate all space in one chunk so it's easier to free. */ - *slot = xmalloc (sizeof (**slot) - + strlen (name) + 1 - + (full_path != NULL ? (strlen (full_path) + 1) : 0)); - p = ((char*) *slot) + sizeof (**slot); - strcpy (p, name); - (*slot)->name = p; - if (full_path != NULL) - { - p += strlen (p) + 1; - strcpy (p, full_path); - (*slot)->full_path = p; - } - else - (*slot)->full_path = NULL; - } - - return in_hash_table; -} - /* Load scripts specified in OBJFILE. START,END delimit a buffer containing a list of nul-terminated file names. @@ -301,20 +129,17 @@ source_section_scripts (struct objfile *objfile, const char *source_name, IWBN if complaints.c were more general-purpose. */ - in_hash_table = maybe_add_script (pspace_info->loaded_scripts, file, + in_hash_table = maybe_add_script (pspace_info, file, opened ? full_path : NULL); if (! opened) { /* We don't throw an error, the program is still debuggable. */ - if (! pspace_info->script_not_found_warning_printed) - { - warning (_("Missing auto-load scripts referenced in section %s\n\ + if (script_not_found_warning_print (pspace_info)) + warning (_("Missing auto-load scripts referenced in section %s\n\ of file %s\n\ Use `info auto-load-scripts [REGEXP]' to list them."), - GDBPY_AUTO_SECTION_NAME, objfile->name); - pspace_info->script_not_found_warning_printed = TRUE; - } + GDBPY_AUTO_SECTION_NAME, objfile->name); } else { @@ -356,116 +181,6 @@ auto_load_section_scripts (struct objfile *objfile, const char *section_name) do_cleanups (cleanups); } -/* Clear the table of loaded section scripts. */ - -static void -clear_section_scripts (void) -{ - struct program_space *pspace = current_program_space; - struct auto_load_pspace_info *info; - - info = program_space_data (pspace, auto_load_pspace_data); - if (info != NULL && info->loaded_scripts != NULL) - { - htab_delete (info->loaded_scripts); - info->loaded_scripts = NULL; - info->script_not_found_warning_printed = FALSE; - } -} - -/* Look for the auto-load script associated with OBJFILE and load it. */ - -static void -auto_load_objfile_script (struct objfile *objfile, const char *suffix) -{ - char *realname; - char *filename, *debugfile; - int len; - FILE *input; - struct cleanup *cleanups; - - realname = gdb_realpath (objfile->name); - len = strlen (realname); - filename = xmalloc (len + strlen (suffix) + 1); - memcpy (filename, realname, len); - strcpy (filename + len, suffix); - - cleanups = make_cleanup (xfree, filename); - make_cleanup (xfree, realname); - - input = fopen (filename, "r"); - debugfile = filename; - - if (!input && debug_file_directory) - { - /* Also try the same file in the separate debug info directory. */ - debugfile = xmalloc (strlen (filename) - + strlen (debug_file_directory) + 1); - strcpy (debugfile, debug_file_directory); - /* FILENAME is absolute, so we don't need a "/" here. */ - strcat (debugfile, filename); - - make_cleanup (xfree, debugfile); - input = fopen (debugfile, "r"); - } - - if (!input && gdb_datadir) - { - /* Also try the same file in a subdirectory of gdb's data - directory. */ - debugfile = xmalloc (strlen (gdb_datadir) + strlen (filename) - + strlen ("/auto-load") + 1); - strcpy (debugfile, gdb_datadir); - strcat (debugfile, "/auto-load"); - /* FILENAME is absolute, so we don't need a "/" here. */ - strcat (debugfile, filename); - - make_cleanup (xfree, debugfile); - input = fopen (debugfile, "r"); - } - - if (input) - { - struct auto_load_pspace_info *pspace_info; - - make_cleanup_fclose (input); - - /* Add this script to the hash table too so "info auto-load-scripts" - can print it. */ - pspace_info = - get_auto_load_pspace_data_for_loading (current_program_space); - maybe_add_script (pspace_info->loaded_scripts, debugfile, debugfile); - - /* To preserve existing behaviour we don't check for whether the - script was already in the table, and always load it. - It's highly unlikely that we'd ever load it twice, - and these scripts are required to be idempotent under multiple - loads anyway. */ - source_python_script_for_objfile (objfile, input, debugfile); - } - - do_cleanups (cleanups); -} - -/* This is a new_objfile observer callback to auto-load scripts. - - Two flavors of auto-loaded scripts are supported. - 1) based on the path to the objfile - 2) from .debug_gdb_scripts section */ - -static void -auto_load_new_objfile (struct objfile *objfile) -{ - if (!objfile) - { - /* OBJFILE is NULL when loading a new "main" symbol-file. */ - clear_section_scripts (); - return; - } - - load_auto_scripts_for_objfile (objfile); -} - /* Load any auto-loaded scripts for OBJFILE. */ void @@ -478,146 +193,9 @@ load_auto_scripts_for_objfile (struct objfile *objfile) } } -/* Collect scripts to be printed in a vec. */ - -typedef struct loaded_script *loaded_script_ptr; -DEF_VEC_P (loaded_script_ptr); - -/* Traversal function for htab_traverse. - Collect the entry if it matches the regexp. */ - -static int -collect_matching_scripts (void **slot, void *info) -{ - struct loaded_script *script = *slot; - VEC (loaded_script_ptr) **scripts_ptr = info; - - if (re_exec (script->name)) - VEC_safe_push (loaded_script_ptr, *scripts_ptr, script); - - return 1; -} - -/* Print SCRIPT. */ - -static void -print_script (struct loaded_script *script) -{ - struct ui_out *uiout = current_uiout; - struct cleanup *chain; - - chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); - - ui_out_field_string (uiout, "loaded", script->full_path ? "Yes" : "Missing"); - ui_out_field_string (uiout, "script", script->name); - ui_out_text (uiout, "\n"); - - /* If the name isn't the full path, print it too. */ - if (script->full_path != NULL - && strcmp (script->name, script->full_path) != 0) - { - ui_out_text (uiout, "\tfull name: "); - ui_out_field_string (uiout, "full_path", script->full_path); - ui_out_text (uiout, "\n"); - } - - do_cleanups (chain); -} - -/* Helper for info_auto_load_scripts to sort the scripts by name. */ - -static int -sort_scripts_by_name (const void *ap, const void *bp) -{ - const struct loaded_script *a = *(const struct loaded_script **) ap; - const struct loaded_script *b = *(const struct loaded_script **) bp; - - return FILENAME_CMP (a->name, b->name); -} - -/* "info auto-load-scripts" command. */ - -static void -info_auto_load_scripts (char *pattern, int from_tty) -{ - struct ui_out *uiout = current_uiout; - struct auto_load_pspace_info *pspace_info; - struct cleanup *script_chain; - VEC (loaded_script_ptr) *scripts; - int nr_scripts; - - dont_repeat (); - - pspace_info = get_auto_load_pspace_data (current_program_space); - - if (pattern && *pattern) - { - char *re_err = re_comp (pattern); - - if (re_err) - error (_("Invalid regexp: %s"), re_err); - } - else - { - re_comp (""); - } - - /* We need to know the number of rows before we build the table. - Plus we want to sort the scripts by name. - So first traverse the hash table collecting the matching scripts. */ - - scripts = VEC_alloc (loaded_script_ptr, 10); - script_chain = make_cleanup (VEC_cleanup (loaded_script_ptr), &scripts); - - if (pspace_info != NULL && pspace_info->loaded_scripts != NULL) - { - immediate_quit++; - /* Pass a pointer to scripts as VEC_safe_push can realloc space. */ - htab_traverse_noresize (pspace_info->loaded_scripts, - collect_matching_scripts, &scripts); - immediate_quit--; - } - - nr_scripts = VEC_length (loaded_script_ptr, scripts); - make_cleanup_ui_out_table_begin_end (uiout, 2, nr_scripts, - "AutoLoadedScriptsTable"); - - ui_out_table_header (uiout, 7, ui_left, "loaded", "Loaded"); - ui_out_table_header (uiout, 70, ui_left, "script", "Script"); - ui_out_table_body (uiout); - - if (nr_scripts > 0) - { - int i; - loaded_script_ptr script; - - qsort (VEC_address (loaded_script_ptr, scripts), - VEC_length (loaded_script_ptr, scripts), - sizeof (loaded_script_ptr), sort_scripts_by_name); - for (i = 0; VEC_iterate (loaded_script_ptr, scripts, i, script); ++i) - print_script (script); - } - - do_cleanups (script_chain); - - if (nr_scripts == 0) - { - if (pattern && *pattern) - ui_out_message (uiout, 0, "No auto-load scripts matching %s.\n", - pattern); - else - ui_out_message (uiout, 0, "No auto-load scripts.\n"); - } -} - void gdbpy_initialize_auto_load (void) { - auto_load_pspace_data - = register_program_space_data_with_cleanup (auto_load_pspace_data_cleanup); - - observer_attach_new_objfile (auto_load_new_objfile); - add_setshow_boolean_cmd ("auto-load-scripts", class_support, &auto_load_scripts, _("\ Set the debugger's behaviour regarding auto-loaded scripts."), _("\ @@ -627,11 +205,6 @@ an executable or shared library."), NULL, NULL, &setlist, &showlist); - - add_info ("auto-load-scripts", - info_auto_load_scripts, - _("Print the list of automatically loaded scripts.\n\ -Usage: info auto-load-scripts [REGEXP]")); } #else /* ! HAVE_PYTHON */ diff --git a/gdb/python/python.h b/gdb/python/python.h index 597ed2ec99..08eb29e82c 100644 --- a/gdb/python/python.h +++ b/gdb/python/python.h @@ -24,8 +24,6 @@ struct breakpoint_object; -extern int gdbpy_global_auto_load; - extern void finish_python_initialization (void); void eval_python_from_control_command (struct command_line *); -- 2.34.1