X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fauto-load.c;h=63366dffb22e0dacbfab5e25ea2a8d205b378083;hb=5fed81ff351121887a93b5b57caebb86667cbbd2;hp=0f5973928a2267cebfb8142499354c8ec63576dc;hpb=c765fdb902fd6dbdeaa476b49592a4d9f835d983;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/auto-load.c b/gdb/auto-load.c index 0f5973928a..63366dffb2 100644 --- a/gdb/auto-load.c +++ b/gdb/auto-load.c @@ -1,6 +1,6 @@ /* GDB routines for supporting auto-loaded scripts. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2017 Free Software Foundation, Inc. This file is part of GDB. @@ -18,6 +18,7 @@ along with this program. If not, see . */ #include "defs.h" +#include #include "auto-load.h" #include "progspace.h" #include "gdb_regex.h" @@ -31,7 +32,6 @@ #include "cli/cli-cmds.h" #include "cli/cli-decode.h" #include "cli/cli-setshow.h" -#include "gdb_vecs.h" #include "readline/tilde.h" #include "completer.h" #include "fnmatch.h" @@ -39,6 +39,7 @@ #include "filestuff.h" #include "extension.h" #include "gdb/section-scripts.h" +#include /* The section to look in for auto-loaded scripts (in file formats that support sections). @@ -48,14 +49,15 @@ followed by the path of a python script to load. */ #define AUTO_SECTION_NAME ".debug_gdb_scripts" -static int maybe_add_script (struct auto_load_pspace_info *pspace_info, - int loaded, const char *name, - const char *full_path, - const struct extension_language_defn *language); +static void maybe_print_unsupported_script_warning + (struct auto_load_pspace_info *, struct objfile *objfile, + const struct extension_language_defn *language, + const char *section_name, unsigned offset); -static int unsupported_script_warning_print (struct auto_load_pspace_info *); - -static int script_not_found_warning_print (struct auto_load_pspace_info *); +static void maybe_print_script_not_found_warning + (struct auto_load_pspace_info *, struct objfile *objfile, + const struct extension_language_defn *language, + const char *section_name, unsigned offset); /* Value of the 'set debug auto-load' configuration variable. */ static int debug_auto_load = 0; @@ -216,7 +218,7 @@ auto_load_safe_path_vec_update (void) { char *dir = VEC_index (char_ptr, auto_load_safe_path_vec, ix); char *expanded = tilde_expand (dir); - char *real_path = gdb_realpath (expanded); + gdb::unique_xmalloc_ptr real_path = gdb_realpath (expanded); /* Ensure the current entry is at least tilde_expand-ed. */ VEC_replace (char_ptr, auto_load_safe_path_vec, ix, expanded); @@ -236,16 +238,15 @@ auto_load_safe_path_vec_update (void) xfree (dir); /* If gdb_realpath returns a different content, append it. */ - if (strcmp (real_path, expanded) == 0) - xfree (real_path); - else + if (strcmp (real_path.get (), expanded) != 0) { - VEC_safe_push (char_ptr, auto_load_safe_path_vec, real_path); - if (debug_auto_load) fprintf_unfiltered (gdb_stdlog, _("auto-load: And canonicalized as \"%s\".\n"), - real_path); + real_path.get ()); + + VEC_safe_push (char_ptr, auto_load_safe_path_vec, + real_path.release ()); } } } @@ -300,7 +301,7 @@ show_auto_load_safe_path (struct ui_file *file, int from_tty, variable. */ static void -add_auto_load_safe_path (char *args, int from_tty) +add_auto_load_safe_path (const char *args, int from_tty) { char *s; @@ -317,6 +318,22 @@ Use 'set auto-load safe-path /' for disabling the auto-load safe-path security.\ auto_load_safe_path_vec_update (); } +/* "add-auto-load-scripts-directory" command for the auto_load_dir configuration + variable. */ + +static void +add_auto_load_dir (const char *args, int from_tty) +{ + char *s; + + if (args == NULL || *args == 0) + error (_("Directory argument required.")); + + s = xstrprintf ("%s%c%s", auto_load_dir, DIRNAME_SEPARATOR, args); + xfree (auto_load_dir); + auto_load_dir = s; +} + /* Implementation for filename_is_in_pattern overwriting the caller's FILENAME and PATTERN. */ @@ -390,9 +407,9 @@ filename_is_in_pattern (const char *filename, const char *pattern) { char *filename_copy, *pattern_copy; - filename_copy = alloca (strlen (filename) + 1); + filename_copy = (char *) alloca (strlen (filename) + 1); strcpy (filename_copy, filename); - pattern_copy = alloca (strlen (pattern) + 1); + pattern_copy = (char *) alloca (strlen (pattern) + 1); strcpy (pattern_copy, pattern); return filename_is_in_pattern_1 (filename_copy, pattern_copy); @@ -401,12 +418,11 @@ filename_is_in_pattern (const char *filename, const char *pattern) /* Return 1 if FILENAME belongs to one of directory components of AUTO_LOAD_SAFE_PATH_VEC. Return 0 otherwise. auto_load_safe_path_vec_update is never called. - *FILENAME_REALP may be updated by gdb_realpath of FILENAME - it has to be - freed by the caller. */ + *FILENAME_REALP may be updated by gdb_realpath of FILENAME. */ static int filename_is_in_auto_load_safe_path_vec (const char *filename, - char **filename_realp) + gdb::unique_xmalloc_ptr *filename_realp) { char *pattern; int ix; @@ -421,17 +437,17 @@ filename_is_in_auto_load_safe_path_vec (const char *filename, if (*filename_realp == NULL) { *filename_realp = gdb_realpath (filename); - if (debug_auto_load && strcmp (*filename_realp, filename) != 0) + if (debug_auto_load && strcmp (filename_realp->get (), filename) != 0) fprintf_unfiltered (gdb_stdlog, _("auto-load: Resolved " "file \"%s\" as \"%s\".\n"), - filename, *filename_realp); + filename, filename_realp->get ()); } - if (strcmp (*filename_realp, filename) != 0) + if (strcmp (filename_realp->get (), filename) != 0) for (ix = 0; VEC_iterate (char_ptr, auto_load_safe_path_vec, ix, pattern); ++ix) - if (filename_is_in_pattern (*filename_realp, pattern)) + if (filename_is_in_pattern (filename_realp->get (), pattern)) break; } @@ -458,8 +474,7 @@ filename_is_in_auto_load_safe_path_vec (const char *filename, int file_is_auto_load_safe (const char *filename, const char *debug_fmt, ...) { - char *filename_real = NULL; - struct cleanup *back_to; + gdb::unique_xmalloc_ptr filename_real; static int advice_printed = 0; if (debug_auto_load) @@ -471,34 +486,24 @@ file_is_auto_load_safe (const char *filename, const char *debug_fmt, ...) va_end (debug_args); } - back_to = make_cleanup (free_current_contents, &filename_real); - if (filename_is_in_auto_load_safe_path_vec (filename, &filename_real)) - { - do_cleanups (back_to); - return 1; - } + return 1; auto_load_safe_path_vec_update (); if (filename_is_in_auto_load_safe_path_vec (filename, &filename_real)) - { - do_cleanups (back_to); - return 1; - } + return 1; warning (_("File \"%s\" auto-loading has been declined by your " "`auto-load safe-path' set to \"%s\"."), - filename_real, auto_load_safe_path); + filename_real.get (), auto_load_safe_path); if (!advice_printed) { const char *homedir = getenv ("HOME"); - char *homeinit; if (homedir == NULL) homedir = "$HOME"; - homeinit = xstrprintf ("%s/%s", homedir, gdbinit); - make_cleanup (xfree, homeinit); + std::string homeinit = string_printf ("%s/%s", homedir, gdbinit); printf_filtered (_("\ To enable execution of this file add\n\ @@ -510,11 +515,11 @@ line to your configuration file \"%s\".\n\ For more information about this security protection see the\n\ \"Auto-loading safe path\" section in the GDB manual. E.g., run from the shell:\n\ \tinfo \"(gdb)Auto-loading safe path\"\n"), - filename_real, homeinit, homeinit); + filename_real.get (), + homeinit.c_str (), homeinit.c_str ()); advice_printed = 1; } - do_cleanups (back_to); return 0; } @@ -525,8 +530,10 @@ For more information about this security protection see the\n\ struct auto_load_pspace_info { - /* For each program space we keep track of loaded scripts. */ - struct htab *loaded_scripts; + /* For each program space we keep track of loaded scripts, both when + specified as file names and as scripts to be executed directly. */ + struct htab *loaded_script_files; + struct htab *loaded_script_texts; /* Non-zero if we've issued the warning about an auto-load script not being supported. We only want to issue this warning once. */ @@ -537,7 +544,7 @@ struct auto_load_pspace_info int script_not_found_warning_printed; }; -/* Objects of this type are stored in the loaded script hash table. */ +/* Objects of this type are stored in the loaded_script hash table. */ struct loaded_script { @@ -545,7 +552,7 @@ struct loaded_script const char *name; /* Full path name or NULL if script wasn't found (or was otherwise - inaccessible). */ + inaccessible), or NULL for loaded_script_texts. */ const char *full_path; /* Non-zero if this script has been loaded. */ @@ -560,10 +567,12 @@ 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 = arg; + struct auto_load_pspace_info *info = (struct auto_load_pspace_info *) arg; - if (info->loaded_scripts) - htab_delete (info->loaded_scripts); + if (info->loaded_script_files) + htab_delete (info->loaded_script_files); + if (info->loaded_script_texts) + htab_delete (info->loaded_script_texts); xfree (info); } @@ -575,7 +584,8 @@ get_auto_load_pspace_data (struct program_space *pspace) { struct auto_load_pspace_info *info; - info = program_space_data (pspace, auto_load_pspace_data); + info = ((struct auto_load_pspace_info *) + program_space_data (pspace, auto_load_pspace_data)); if (info == NULL) { info = XCNEW (struct auto_load_pspace_info); @@ -590,7 +600,7 @@ get_auto_load_pspace_data (struct program_space *pspace) static hashval_t hash_loaded_script_entry (const void *data) { - const struct loaded_script *e = data; + const struct loaded_script *e = (const struct loaded_script *) data; return htab_hash_string (e->name) ^ htab_hash_pointer (e->language); } @@ -600,8 +610,8 @@ hash_loaded_script_entry (const void *data) static int eq_loaded_script_entry (const void *a, const void *b) { - const struct loaded_script *ea = a; - const struct loaded_script *eb = b; + const struct loaded_script *ea = (const struct loaded_script *) a; + const struct loaded_script *eb = (const struct loaded_script *) b; return strcmp (ea->name, eb->name) == 0 && ea->language == eb->language; } @@ -616,10 +626,14 @@ init_loaded_scripts_info (struct auto_load_pspace_info *pspace_info) 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->loaded_script_files = htab_create (31, + hash_loaded_script_entry, + eq_loaded_script_entry, + xfree); + pspace_info->loaded_script_texts = htab_create (31, + hash_loaded_script_entry, + eq_loaded_script_entry, + xfree); pspace_info->unsupported_script_warning_printed = FALSE; pspace_info->script_not_found_warning_printed = FALSE; @@ -634,23 +648,24 @@ 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) + if (info->loaded_script_files == NULL) init_loaded_scripts_info (info); return info; } -/* Add script NAME in LANGUAGE to hash table of PSPACE_INFO. LOADED 1 if the - script has been (is going to) be loaded, 0 otherwise (such as if it has not - been found). FULL_PATH is NULL if the script wasn't found. The result is - true if the script was already in the hash table. */ +/* Add script file NAME in LANGUAGE to hash table of PSPACE_INFO. + LOADED 1 if the script has been (is going to) be loaded, 0 otherwise + (such as if it has not been found). + 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 auto_load_pspace_info *pspace_info, int loaded, - const char *name, const char *full_path, - const struct extension_language_defn *language) +maybe_add_script_file (struct auto_load_pspace_info *pspace_info, int loaded, + const char *name, const char *full_path, + const struct extension_language_defn *language) { - struct htab *htab = pspace_info->loaded_scripts; + struct htab *htab = pspace_info->loaded_script_files; struct loaded_script **slot, entry; int in_hash_table; @@ -661,14 +676,15 @@ maybe_add_script (struct auto_load_pspace_info *pspace_info, int loaded, /* If this script is not in the hash table, add it. */ - if (! in_hash_table) + 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)); + *slot = ((struct loaded_script *) + 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; @@ -687,6 +703,45 @@ maybe_add_script (struct auto_load_pspace_info *pspace_info, int loaded, return in_hash_table; } +/* Add script contents NAME in LANGUAGE to hash table of PSPACE_INFO. + LOADED 1 if the script has been (is going to) be loaded, 0 otherwise + (such as if it has not been found). + The result is true if the script was already in the hash table. */ + +static int +maybe_add_script_text (struct auto_load_pspace_info *pspace_info, + int loaded, const char *name, + const struct extension_language_defn *language) +{ + struct htab *htab = pspace_info->loaded_script_texts; + struct loaded_script **slot, entry; + int in_hash_table; + + entry.name = name; + entry.language = language; + 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 = ((struct loaded_script *) + xmalloc (sizeof (**slot) + strlen (name) + 1)); + p = ((char*) *slot) + sizeof (**slot); + strcpy (p, name); + (*slot)->name = p; + (*slot)->full_path = NULL; + (*slot)->loaded = loaded; + (*slot)->language = language; + } + + return in_hash_table; +} + /* Clear the table of loaded section scripts. */ static void @@ -695,11 +750,14 @@ 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) + info = ((struct auto_load_pspace_info *) + program_space_data (pspace, auto_load_pspace_data)); + if (info != NULL && info->loaded_script_files != NULL) { - htab_delete (info->loaded_scripts); - info->loaded_scripts = NULL; + htab_delete (info->loaded_script_files); + htab_delete (info->loaded_script_texts); + info->loaded_script_files = NULL; + info->loaded_script_texts = NULL; info->unsupported_script_warning_printed = FALSE; info->script_not_found_warning_printed = FALSE; } @@ -715,18 +773,17 @@ auto_load_objfile_script_1 (struct objfile *objfile, const char *realname, { char *filename, *debugfile; int len, retval; - FILE *input; struct cleanup *cleanups; const char *suffix = ext_lang_auto_load_suffix (language); len = strlen (realname); - filename = xmalloc (len + strlen (suffix) + 1); + filename = (char *) xmalloc (len + strlen (suffix) + 1); memcpy (filename, realname, len); strcpy (filename + len, suffix); cleanups = make_cleanup (xfree, filename); - input = gdb_fopen_cloexec (filename, "r"); + gdb_file_up input = gdb_fopen_cloexec (filename, "r"); debugfile = filename; if (debug_auto_load) fprintf_unfiltered (gdb_stdlog, _("auto-load: Attempted file \"%s\" %s.\n"), @@ -751,7 +808,7 @@ auto_load_objfile_script_1 (struct objfile *objfile, const char *realname, for (ix = 0; VEC_iterate (char_ptr, vec, ix, dir); ++ix) { - debugfile = xmalloc (strlen (dir) + strlen (filename) + 1); + debugfile = (char *) xmalloc (strlen (dir) + strlen (filename) + 1); strcpy (debugfile, dir); /* FILENAME is absolute, so we don't need a "/" here. */ @@ -774,8 +831,6 @@ auto_load_objfile_script_1 (struct objfile *objfile, const char *realname, int is_safe; struct auto_load_pspace_info *pspace_info; - make_cleanup_fclose (input); - is_safe = file_is_auto_load_safe (debugfile, _("auto-load: Loading %s script \"%s\"" @@ -787,7 +842,8 @@ auto_load_objfile_script_1 (struct objfile *objfile, const char *realname, "info auto-load ${lang}-scripts" can print it. */ pspace_info = get_auto_load_pspace_data_for_loading (current_program_space); - maybe_add_script (pspace_info, is_safe, debugfile, debugfile, language); + maybe_add_script_file (pspace_info, is_safe, debugfile, debugfile, + language); /* To preserve existing behaviour we don't check for whether the script was already in the table, and always load it. @@ -803,7 +859,7 @@ auto_load_objfile_script_1 (struct objfile *objfile, const char *realname, compiled in. And the extension language is required to implement this function. */ gdb_assert (sourcer != NULL); - sourcer (language, objfile, input, debugfile); + sourcer (language, objfile, input.get (), debugfile); } retval = 1; @@ -822,29 +878,187 @@ void auto_load_objfile_script (struct objfile *objfile, const struct extension_language_defn *language) { - char *realname = gdb_realpath (objfile_name (objfile)); - struct cleanup *cleanups = make_cleanup (xfree, realname); + gdb::unique_xmalloc_ptr realname + = gdb_realpath (objfile_name (objfile)); - if (!auto_load_objfile_script_1 (objfile, realname, language)) + if (!auto_load_objfile_script_1 (objfile, realname.get (), language)) { /* For Windows/DOS .exe executables, strip the .exe suffix, so that FOO-gdb.gdb could be used for FOO.exe, and try again. */ - size_t len = strlen (realname); + size_t len = strlen (realname.get ()); const size_t lexe = sizeof (".exe") - 1; - if (len > lexe && strcasecmp (realname + len - lexe, ".exe") == 0) + if (len > lexe && strcasecmp (realname.get () + len - lexe, ".exe") == 0) { len -= lexe; - realname[len] = '\0'; + realname.get ()[len] = '\0'; if (debug_auto_load) fprintf_unfiltered (gdb_stdlog, _("auto-load: Stripped .exe suffix, " "retrying with \"%s\".\n"), - realname); - auto_load_objfile_script_1 (objfile, realname, language); + realname.get ()); + auto_load_objfile_script_1 (objfile, realname.get (), language); + } + } +} + +/* Subroutine of source_section_scripts to simplify it. + Load FILE as a script in extension language LANGUAGE. + The script is from section SECTION_NAME in OBJFILE at offset OFFSET. */ + +static void +source_script_file (struct auto_load_pspace_info *pspace_info, + struct objfile *objfile, + const struct extension_language_defn *language, + const char *section_name, unsigned int offset, + const char *file) +{ + int in_hash_table; + objfile_script_sourcer_func *sourcer; + + /* Skip this script if support is not compiled in. */ + sourcer = ext_lang_objfile_script_sourcer (language); + if (sourcer == NULL) + { + /* We don't throw an error, the program is still debuggable. */ + maybe_print_unsupported_script_warning (pspace_info, objfile, language, + section_name, offset); + /* We *could* still try to open it, but there's no point. */ + maybe_add_script_file (pspace_info, 0, file, NULL, language); + return; + } + + /* Skip this script if auto-loading it has been disabled. */ + if (!ext_lang_auto_load_enabled (language)) + { + /* No message is printed, just skip it. */ + return; + } + + gdb::optional opened = find_and_open_script (file, + 1 /*search_path*/); + + if (opened) + { + if (!file_is_auto_load_safe (opened->full_path.get (), + _("auto-load: Loading %s script " + "\"%s\" from section \"%s\" of " + "objfile \"%s\".\n"), + ext_lang_name (language), + opened->full_path.get (), + section_name, objfile_name (objfile))) + opened.reset (); + } + else + { + /* If one script isn't found it's not uncommon for more to not be + found either. We don't want to print a message for each script, + too much noise. Instead, we print the warning once and tell the + user how to find the list of scripts that weren't loaded. + We don't throw an error, the program is still debuggable. + + IWBN if complaints.c were more general-purpose. */ + + maybe_print_script_not_found_warning (pspace_info, objfile, language, + section_name, offset); + } + + in_hash_table = maybe_add_script_file (pspace_info, bool (opened), file, + (opened + ? opened->full_path.get () + : NULL), + language); + + /* If this file is not currently loaded, load it. */ + if (opened && !in_hash_table) + sourcer (language, objfile, opened->stream.get (), + opened->full_path.get ()); +} + +/* Subroutine of source_section_scripts to simplify it. + Execute SCRIPT as a script in extension language LANG. + The script is from section SECTION_NAME in OBJFILE at offset OFFSET. */ + +static void +execute_script_contents (struct auto_load_pspace_info *pspace_info, + struct objfile *objfile, + const struct extension_language_defn *language, + const char *section_name, unsigned int offset, + const char *script) +{ + objfile_script_executor_func *executor; + const char *newline, *script_text; + char *name; + int is_safe, in_hash_table; + struct cleanup *cleanups; + + cleanups = make_cleanup (null_cleanup, NULL); + + /* The first line of the script is the name of the script. + It must not contain any kind of space character. */ + name = NULL; + newline = strchr (script, '\n'); + if (newline != NULL) + { + char *buf, *p; + + /* Put the name in a buffer and validate it. */ + buf = xstrndup (script, newline - script); + make_cleanup (xfree, buf); + for (p = buf; *p != '\0'; ++p) + { + if (isspace (*p)) + break; } + /* We don't allow nameless scripts, they're not helpful to the user. */ + if (p != buf && *p == '\0') + name = buf; + } + if (name == NULL) + { + /* We don't throw an error, the program is still debuggable. */ + warning (_("\ +Missing/bad script name in entry at offset %u in section %s\n\ +of file %s."), + offset, section_name, objfile_name (objfile)); + do_cleanups (cleanups); + return; + } + script_text = newline + 1; + + /* Skip this script if support is not compiled in. */ + executor = ext_lang_objfile_script_executor (language); + if (executor == NULL) + { + /* We don't throw an error, the program is still debuggable. */ + maybe_print_unsupported_script_warning (pspace_info, objfile, language, + section_name, offset); + maybe_add_script_text (pspace_info, 0, name, language); + do_cleanups (cleanups); + return; } + /* Skip this script if auto-loading it has been disabled. */ + if (!ext_lang_auto_load_enabled (language)) + { + /* No message is printed, just skip it. */ + do_cleanups (cleanups); + return; + } + + is_safe = file_is_auto_load_safe (objfile_name (objfile), + _("auto-load: Loading %s script " + "\"%s\" from section \"%s\" of " + "objfile \"%s\".\n"), + ext_lang_name (language), name, + section_name, objfile_name (objfile)); + + in_hash_table = maybe_add_script_text (pspace_info, is_safe, name, language); + + /* If this file is not currently loaded, load it. */ + if (is_safe && !in_hash_table) + executor (language, objfile, name, script_text); + do_cleanups (cleanups); } @@ -853,12 +1067,12 @@ auto_load_objfile_script (struct objfile *objfile, file names. SECTION_NAME is used in error messages. - Scripts are found per normal "source -s" command processing. - First the script is looked for in $cwd. If not found there the - source search path is used. + Scripts specified as file names are found per normal "source -s" command + processing. First the script is looked for in $cwd. If not found there + the source search path is used. - The section contains a list of path names of script files to load. - Each path is null-terminated. */ + The section contains a list of path names of script files to load or + actual script contents. Each entry is nul-terminated. */ static void source_section_scripts (struct objfile *objfile, const char *section_name, @@ -871,20 +1085,19 @@ source_section_scripts (struct objfile *objfile, const char *section_name, for (p = start; p < end; ++p) { - const char *file; - FILE *stream; - char *full_path; - int opened, in_hash_table; - struct cleanup *back_to; + const char *entry; const struct extension_language_defn *language; - objfile_script_sourcer_func *sourcer; + unsigned int offset = p - start; + int code = *p; - switch (*p) + switch (code) { case SECTION_SCRIPT_ID_PYTHON_FILE: + case SECTION_SCRIPT_ID_PYTHON_TEXT: language = get_ext_lang_defn (EXT_LANG_PYTHON); break; case SECTION_SCRIPT_ID_SCHEME_FILE: + case SECTION_SCRIPT_ID_SCHEME_TEXT: language = get_ext_lang_defn (EXT_LANG_GUILE); break; default: @@ -893,105 +1106,37 @@ source_section_scripts (struct objfile *objfile, const char *section_name, but it's safer to just punt. */ return; } - file = ++p; + entry = ++p; while (p < end && *p != '\0') ++p; if (p == end) { - char *buf = alloca (p - file + 1); - - memcpy (buf, file, p - file); - buf[p - file] = '\0'; - warning (_("Non-null-terminated path in %s: %s"), - section_name, buf); - /* Don't load it. */ + warning (_("Non-nul-terminated entry in %s at offset %u"), + section_name, offset); + /* Don't load/execute it. */ break; } - if (p == file) - { - warning (_("Empty path in %s"), section_name); - continue; - } - /* Until we support more types of records in .debug_gdb_scripts we do - all the processing here. The expectation is to add a new - extension_language_script_ops "method" that handles all the records - for the language. For now we can just use - extension_language_script_ops.objfile_script_sourcer. */ - - /* Skip this script if support is not compiled in. */ - sourcer = ext_lang_objfile_script_sourcer (language); - if (sourcer == NULL) + switch (code) { - /* We don't throw an error, the program is still debuggable. */ - if (!unsupported_script_warning_print (pspace_info)) + case SECTION_SCRIPT_ID_PYTHON_FILE: + case SECTION_SCRIPT_ID_SCHEME_FILE: + if (p == entry) { - warning (_("Unsupported auto-load scripts referenced in" - " %s section\n" - "of file %s.\n" - "Use `info auto-load %s-scripts [REGEXP]'" - " to list them."), - section_name, objfile_name (objfile), - ext_lang_name (language)); + warning (_("Empty entry in %s at offset %u"), + section_name, offset); + continue; } - /* We *could* still try to open it, but there's no point. */ - maybe_add_script (pspace_info, 0, file, NULL, language); - continue; - } - - /* Skip this script if auto-loading it has been disabled. */ - if (!ext_lang_auto_load_enabled (language)) - { - /* No message is printed, just skip it. */ - continue; - } - - opened = find_and_open_script (file, 1 /*search_path*/, - &stream, &full_path); - - back_to = make_cleanup (null_cleanup, NULL); - if (opened) - { - make_cleanup_fclose (stream); - make_cleanup (xfree, full_path); - - if (!file_is_auto_load_safe (full_path, - _("auto-load: Loading %s script " - "\"%s\" from section \"%s\" of " - "objfile \"%s\".\n"), - ext_lang_name (language), full_path, - section_name, objfile_name (objfile))) - opened = 0; - } - else - { - full_path = NULL; - - /* If one script isn't found it's not uncommon for more to not be - found either. We don't want to print a message for each script, - too much noise. Instead, we print the warning once and tell the - user how to find the list of scripts that weren't loaded. - We don't throw an error, the program is still debuggable. - - IWBN if complaints.c were more general-purpose. */ - - 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 %s-scripts [REGEXP]' to list them."), - section_name, objfile_name (objfile), - ext_lang_name (language)); + source_script_file (pspace_info, objfile, language, + section_name, offset, entry); + break; + case SECTION_SCRIPT_ID_PYTHON_TEXT: + case SECTION_SCRIPT_ID_SCHEME_TEXT: + execute_script_contents (pspace_info, objfile, language, + section_name, offset, entry); + break; } - - in_hash_table = maybe_add_script (pspace_info, opened, file, full_path, - language); - - /* If this file is not currently loaded, load it. */ - if (opened && !in_hash_table) - sourcer (language, objfile, stream, full_path); - - do_cleanups (back_to); } } @@ -1005,7 +1150,8 @@ auto_load_section_scripts (struct objfile *objfile, const char *section_name) bfd_byte *data = NULL; scripts_sect = bfd_get_section_by_name (abfd, section_name); - if (scripts_sect == NULL) + if (scripts_sect == NULL + || (bfd_get_section_flags (abfd, scripts_sect) & SEC_HAS_CONTENTS) == 0) return; if (!bfd_get_full_section_contents (abfd, scripts_sect, &data)) @@ -1030,8 +1176,11 @@ load_auto_scripts_for_objfile (struct objfile *objfile) { /* Return immediately if auto-loading has been globally disabled. This is to handle sequencing of operations during gdb startup. - Also return immediately if OBJFILE is not actually a file. */ - if (!global_auto_load || (objfile->flags & OBJF_NOT_FILENAME) != 0) + Also return immediately if OBJFILE was not created from a file + on the local filesystem. */ + if (!global_auto_load + || (objfile->flags & OBJF_NOT_FILENAME) != 0 + || is_target_filename (objfile->original_name)) return; /* Load any extension language scripts for this objfile. @@ -1063,13 +1212,14 @@ auto_load_new_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); - struct collect_matching_scripts_data { - VEC (loaded_script_ptr) **scripts_p; + collect_matching_scripts_data (std::vector *scripts_p_, + const extension_language_defn *language_) + : scripts_p (scripts_p_), language (language_) + {} + std::vector *scripts_p; const struct extension_language_defn *language; }; @@ -1079,11 +1229,12 @@ struct collect_matching_scripts_data static int collect_matching_scripts (void **slot, void *info) { - struct loaded_script *script = *slot; - struct collect_matching_scripts_data *data = info; + struct loaded_script *script = (struct loaded_script *) *slot; + struct collect_matching_scripts_data *data + = (struct collect_matching_scripts_data *) info; if (script->language == data->language && re_exec (script->name)) - VEC_safe_push (loaded_script_ptr, *data->scripts_p, script); + data->scripts_p->push_back (script); return 1; } @@ -1094,35 +1245,29 @@ 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_emit_tuple tuple_emitter (uiout, NULL); - ui_out_field_string (uiout, "loaded", script->loaded ? "Yes" : "No"); - ui_out_field_string (uiout, "script", script->name); - ui_out_text (uiout, "\n"); + uiout->field_string ("loaded", script->loaded ? "Yes" : "No"); + uiout->field_string ("script", script->name); + uiout->text ("\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"); + uiout->text ("\tfull name: "); + uiout->field_string ("full_path", script->full_path); + uiout->text ("\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) +static bool +sort_scripts_by_name (loaded_script *a, loaded_script *b) { - 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); + return FILENAME_CMP (a->name, b->name) < 0; } /* Special internal GDB value of auto_load_info_scripts's PATTERN identify @@ -1130,19 +1275,26 @@ sort_scripts_by_name (const void *ap, const void *bp) "info auto-load" invocation. Extra newline will be printed if needed. */ char auto_load_info_scripts_pattern_nl[] = ""; +/* Subroutine of auto_load_info_scripts to simplify it. + Print SCRIPTS. */ + +static void +print_scripts (const std::vector &scripts) +{ + for (loaded_script *script : scripts) + print_script (script); +} + /* Implementation for "info auto-load gdb-scripts" (and "info auto-load python-scripts"). List scripts in LANGUAGE matching PATTERN. FROM_TTY is the usual GDB boolean for user interactivity. */ void -auto_load_info_scripts (char *pattern, int from_tty, +auto_load_info_scripts (const char *pattern, int from_tty, const struct extension_language_defn *language) { 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 (); @@ -1164,60 +1316,64 @@ auto_load_info_scripts (char *pattern, int from_tty, 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); + std::vector script_files, script_texts; + + if (pspace_info != NULL && pspace_info->loaded_script_files != NULL) + { + collect_matching_scripts_data data (&script_files, language); + + /* Pass a pointer to scripts as VEC_safe_push can realloc space. */ + htab_traverse_noresize (pspace_info->loaded_script_files, + collect_matching_scripts, &data); + + std::sort (script_files.begin (), script_files.end (), + sort_scripts_by_name); + } - if (pspace_info != NULL && pspace_info->loaded_scripts != NULL) + if (pspace_info != NULL && pspace_info->loaded_script_texts != NULL) { - struct collect_matching_scripts_data data = { &scripts, language }; + collect_matching_scripts_data data (&script_texts, language); /* Pass a pointer to scripts as VEC_safe_push can realloc space. */ - htab_traverse_noresize (pspace_info->loaded_scripts, + htab_traverse_noresize (pspace_info->loaded_script_texts, collect_matching_scripts, &data); + + std::sort (script_texts.begin (), script_texts.end (), + sort_scripts_by_name); } - nr_scripts = VEC_length (loaded_script_ptr, scripts); + int nr_scripts = script_files.size () + script_texts.size (); /* Table header shifted right by preceding "gdb-scripts: " would not match its columns. */ if (nr_scripts > 0 && pattern == auto_load_info_scripts_pattern_nl) - ui_out_text (uiout, "\n"); + uiout->text ("\n"); - make_cleanup_ui_out_table_begin_end (uiout, 2, nr_scripts, - "AutoLoadedScriptsTable"); + { + ui_out_emit_table table_emitter (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); + uiout->table_header (7, ui_left, "loaded", "Loaded"); + uiout->table_header (70, ui_left, "script", "Script"); + uiout->table_body (); - 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); + print_scripts (script_files); + print_scripts (script_texts); + } if (nr_scripts == 0) { if (pattern && *pattern) - ui_out_message (uiout, 0, "No auto-load scripts matching %s.\n", - pattern); + uiout->message ("No auto-load scripts matching %s.\n", pattern); else - ui_out_message (uiout, 0, "No auto-load scripts.\n"); + uiout->message ("No auto-load scripts.\n"); } } /* Wrapper for "info auto-load gdb-scripts". */ static void -info_auto_load_gdb_scripts (char *pattern, int from_tty) +info_auto_load_gdb_scripts (const char *pattern, int from_tty) { auto_load_info_scripts (pattern, from_tty, &extension_language_gdb); } @@ -1225,7 +1381,7 @@ info_auto_load_gdb_scripts (char *pattern, int from_tty) /* Implement 'info auto-load local-gdbinit'. */ static void -info_auto_load_local_gdbinit (char *args, int from_tty) +info_auto_load_local_gdbinit (const char *args, int from_tty) { if (auto_load_local_gdbinit_pathname == NULL) printf_filtered (_("Local .gdbinit file was not found.\n")); @@ -1237,38 +1393,54 @@ info_auto_load_local_gdbinit (char *args, int from_tty) auto_load_local_gdbinit_pathname); } -/* Return non-zero if UNSUPPORTED_SCRIPT_WARNING_PRINTED of PSPACE_INFO was - unset before calling this function. Always set - UNSUPPORTED_SCRIPT_WARNING_PRINTED of PSPACE_INFO. */ +/* Print an "unsupported script" warning if it has not already been printed. + The script is in language LANGUAGE at offset OFFSET in section SECTION_NAME + of OBJFILE. */ -static int -unsupported_script_warning_print (struct auto_load_pspace_info *pspace_info) +static void +maybe_print_unsupported_script_warning + (struct auto_load_pspace_info *pspace_info, + struct objfile *objfile, const struct extension_language_defn *language, + const char *section_name, unsigned offset) { - int retval = !pspace_info->unsupported_script_warning_printed; - - pspace_info->unsupported_script_warning_printed = 1; - - return retval; + if (!pspace_info->unsupported_script_warning_printed) + { + warning (_("\ +Unsupported auto-load script at offset %u in section %s\n\ +of file %s.\n\ +Use `info auto-load %s-scripts [REGEXP]' to list them."), + offset, section_name, objfile_name (objfile), + ext_lang_name (language)); + pspace_info->unsupported_script_warning_printed = 1; + } } /* 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. */ -static int -script_not_found_warning_print (struct auto_load_pspace_info *pspace_info) +static void +maybe_print_script_not_found_warning + (struct auto_load_pspace_info *pspace_info, + struct objfile *objfile, const struct extension_language_defn *language, + const char *section_name, unsigned offset) { - int retval = !pspace_info->script_not_found_warning_printed; - - pspace_info->script_not_found_warning_printed = 1; - - return retval; + if (!pspace_info->script_not_found_warning_printed) + { + warning (_("\ +Missing auto-load script at offset %u in section %s\n\ +of file %s.\n\ +Use `info auto-load %s-scripts [REGEXP]' to list them."), + offset, section_name, objfile_name (objfile), + ext_lang_name (language)); + pspace_info->script_not_found_warning_printed = 1; + } } /* The only valid "set auto-load" argument is off|0|no|disable. */ static void -set_auto_load_cmd (char *args, int from_tty) +set_auto_load_cmd (const char *args, int from_tty) { struct cmd_list_element *list; size_t length; @@ -1317,7 +1489,7 @@ automatic loading of Python scripts."), "show auto-load " settings. */ static void -show_auto_load_cmd (char *args, int from_tty) +show_auto_load_cmd (const char *args, int from_tty) { cmd_show_list (*auto_load_show_cmdlist_get (), from_tty, ""); } @@ -1345,32 +1517,25 @@ automatic loading of Python scripts."), newlines at proper places. */ static void -info_auto_load_cmd (char *args, int from_tty) +info_auto_load_cmd (const char *args, int from_tty) { struct cmd_list_element *list; struct cleanup *infolist_chain; struct ui_out *uiout = current_uiout; - infolist_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "infolist"); + ui_out_emit_tuple tuple_emitter (uiout, "infolist"); for (list = *auto_load_info_cmdlist_get (); list != NULL; list = list->next) { - struct cleanup *option_chain - = make_cleanup_ui_out_tuple_begin_end (uiout, "option"); + ui_out_emit_tuple option_emitter (uiout, "option"); gdb_assert (!list->prefixlist); gdb_assert (list->type == not_set_cmd); - ui_out_field_string (uiout, "name", list->name); - ui_out_text (uiout, ": "); + uiout->field_string ("name", list->name); + uiout->text (": "); cmd_func (list, auto_load_info_scripts_pattern_nl, from_tty); - - /* Close the tuple. */ - do_cleanups (option_chain); } - - /* Close the tuple. */ - do_cleanups (infolist_chain); } /* Initialize "info auto-load " commands prefix and return it. */ @@ -1391,8 +1556,6 @@ found and/or loaded."), return &retval; } -void _initialize_auto_load (void); - void _initialize_auto_load (void) { @@ -1526,6 +1689,15 @@ access the current full list setting."), &cmdlist); set_cmd_completer (cmd, filename_completer); + cmd = add_cmd ("add-auto-load-scripts-directory", class_support, + add_auto_load_dir, + _("Add entries to the list of directories from which to load " + "auto-loaded scripts.\n\ +See the commands 'set auto-load scripts-directory' and\n\ +'show auto-load scripts-directory' to access the current full list setting."), + &cmdlist); + set_cmd_completer (cmd, filename_completer); + add_setshow_boolean_cmd ("auto-load", class_maintenance, &debug_auto_load, _("\ Set auto-load verifications debugging."), _("\