* [PATCH] Add support for embedding scripts in .debug_gdb_scripts. @ 2015-01-15 17:32 Doug Evans 2015-01-15 18:11 ` Eli Zaretskii 2015-01-31 23:31 ` Doug Evans 0 siblings, 2 replies; 19+ messages in thread From: Doug Evans @ 2015-01-15 17:32 UTC (permalink / raw) To: binutils, gdb-patches Hi. This is a feature I've been planning to add for awhile. There's note of it in the current gdb/section-scripts.h. It extends .debug_gdb_scripts to allow including the script in the section, whereas the current support just allows including a file to be loaded. One use-case I have for this is supporting static linking where there is no shared-library.so to attach a -gdb.py file to. Regression tested on amd64-linux. 2015-01-15 Doug Evans <xdje42@gmail.com> Add support for inlining scripts into .debug_gdb_scripts. include/ * gdb/section-scripts.h: Remove "future extension" comment. (SECTION_SCRIPT_ID_PYTHON_TEXT): New macro. (SECTION_SCRIPT_ID_SCHEME_TEXT): New macro. gdb/ * NEWS: Mention inlined scripts in .debug_gdb_scripts section. * auto-load.c: #include ctype.h. (struct auto_load_pspace_info): Replace member loaded_scripts with new members loaded_script_files, loaded_script_texts. (auto_load_pspace_data_cleanup): Update. (init_loaded_scripts_info): Update. (get_auto_load_pspace_data_for_loading): Update. (maybe_add_script_file): Renamed from maybe_add_script. All callers updated. (maybe_add_script_text): New function. (clear_section_scripts): Update. (source_script_file, execute_script_contents): New functions. (source_section_scripts): Add support for SECTION_SCRIPT_ID_PYTHON_TEXT, SECTION_SCRIPT_ID_GUILE_TEXT. (print_scripts): New function. (auto_load_info_scripts): Also print inlined scripts. (maybe_print_unsupported_script_warning): Renamed from unsupported_script_warning_print. All callers updated. (maybe_print_script_not_found_warning): Renamed from script_not_found_warning_print. All callers updated. * extension-priv.h (struct extension_language_script_ops): New member objfile_script_executor. * extension.c (ext_lang_objfile_script_executor): New function. * extension.h (objfile_script_executor_func): New typedef. (ext_lang_objfile_script_executor): Declare. * guile/guile-internal.h (gdbscm_execute_objfile_script): Declare. * guile/guile.c (guile_extension_script_ops): Update. * guile/scm-objfile.c (gdbscm_execute_objfile_script): New function. * python/python.c (python_extension_script_ops): Update. (gdbpy_execute_objfile_script): New function. doc/ * gdb.texinfo (dotdebug_gdb_scripts section): Update docs to distinguish script files vs inlined scripts. * python.texi (Python Auto-loading): Ditto. testsuite/ * gdb.guile/scm-section-script.c: Add duplicate inlined section script entries. Duplicate file section script entries. * gdb.guile/scm-section-script.exp: Add tests for duplicate entries, inlined entries. Add test for safe-path rejection. * gdb.python/py-section-script.c: Add duplicate inlined section script entries. Duplicate file section script entries. * gdb.python/py-section-script.exp: Add tests for duplicate entries, inlined entries. Add test for safe-path rejection. diff --git a/include/gdb/section-scripts.h b/include/gdb/section-scripts.h index c4b7a1c..effce62 100644 --- a/include/gdb/section-scripts.h +++ b/include/gdb/section-scripts.h @@ -28,8 +28,6 @@ Other unused values needn't specify different scripting languages, but we have no need for anything else at the moment. - Future extension: Include the contents of the script in the section. - These values are defined as macros so that they can be used in embedded asms and assembler source files. */ @@ -47,4 +45,18 @@ file. */ #define SECTION_SCRIPT_ID_SCHEME_FILE 3 +/* The record is a nul-terminated string. + The first line is the name of the script. + Subsequent lines are interpreted as a python script. */ +#define SECTION_SCRIPT_ID_PYTHON_TEXT 4 + +/* Native GDB scripts are not currently supported in .debug_gdb_scripts, + but we reserve a value for it. */ +/*#define SECTION_SCRIPT_ID_GDB_TEXT 5*/ + +/* The record is a nul-terminated string. + The first line is the name of the script. + Subsequent lines are interpreted as a guile(scheme) script. */ +#define SECTION_SCRIPT_ID_SCHEME_TEXT 6 + #endif /* GDB_SECTION_SCRIPTS_H */ diff --git a/gdb/NEWS b/gdb/NEWS index 2d2c941..baf1868 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -3,6 +3,11 @@ *** Changes since GDB 7.9 +* Python/Guile scripting + +** GDB now supports auto-loading of Python/Guile scripts contained in the + special section named `.debug_gdb_scripts'. + *** Changes in GDB 7.9 * GDB now supports hardware watchpoints on x86 GNU Hurd. diff --git a/gdb/auto-load.c b/gdb/auto-load.c index c152778..778eeb6 100644 --- a/gdb/auto-load.c +++ b/gdb/auto-load.c @@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "defs.h" +#include <ctype.h> #include "auto-load.h" #include "progspace.h" #include "gdb_regex.h" @@ -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; @@ -541,8 +543,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. */ @@ -553,7 +557,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 { @@ -561,7 +565,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. */ @@ -578,8 +582,10 @@ auto_load_pspace_data_cleanup (struct program_space *pspace, void *arg) { struct auto_load_pspace_info *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); } @@ -632,10 +638,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; @@ -650,23 +660,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; @@ -677,7 +688,7 @@ 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; @@ -703,6 +714,44 @@ 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 = 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 @@ -712,10 +761,12 @@ clear_section_scripts (void) struct auto_load_pspace_info *info; info = program_space_data (pspace, auto_load_pspace_data); - if (info != NULL && info->loaded_scripts != NULL) + 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; } @@ -803,7 +854,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. @@ -864,17 +916,183 @@ auto_load_objfile_script (struct objfile *objfile, do_cleanups (cleanups); } +/* 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) +{ + FILE *stream; + char *full_path; + int opened, in_hash_table; + struct cleanup *cleanups; + 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; + } + + opened = find_and_open_script (file, 1 /*search_path*/, + &stream, &full_path); + + cleanups = 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. */ + + maybe_print_script_not_found_warning (pspace_info, objfile, language, + section_name, offset); + } + + in_hash_table = maybe_add_script_file (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 (cleanups); +} + +/* 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, *end; + 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); +} + /* Load scripts specified in OBJFILE. START,END delimit a buffer containing a list of nul-terminated 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, @@ -887,20 +1105,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: @@ -909,105 +1126,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); } } @@ -1146,6 +1295,23 @@ 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 (VEC (loaded_script_ptr) *scripts) +{ + struct ui_out *uiout = current_uiout; + 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); +} + /* 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. */ @@ -1157,7 +1323,7 @@ auto_load_info_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; + VEC (loaded_script_ptr) *script_files, *script_texts; int nr_scripts; dont_repeat (); @@ -1180,25 +1346,38 @@ 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); + script_files = VEC_alloc (loaded_script_ptr, 10); + script_texts = VEC_alloc (loaded_script_ptr, 10); + script_chain = make_cleanup (VEC_cleanup (loaded_script_ptr), &script_files); + make_cleanup (VEC_cleanup (loaded_script_ptr), &script_texts); + + if (pspace_info != NULL && pspace_info->loaded_script_files != NULL) + { + struct 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); + } - 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 }; + struct 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); } - nr_scripts = VEC_length (loaded_script_ptr, scripts); + nr_scripts = (VEC_length (loaded_script_ptr, script_files) + + VEC_length (loaded_script_ptr, script_texts)); /* 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"); + /* Note: This creates a cleanup to output the table end marker. */ make_cleanup_ui_out_table_begin_end (uiout, 2, nr_scripts, "AutoLoadedScriptsTable"); @@ -1206,18 +1385,10 @@ auto_load_info_scripts (char *pattern, int from_tty, 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); - } + print_scripts (script_files); + print_scripts (script_texts); + /* Finish up the table before checking for no matching scripts. */ do_cleanups (script_chain); if (nr_scripts == 0) @@ -1253,32 +1424,48 @@ 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. */ diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index b059ac2..de02f15 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -23971,17 +23971,31 @@ is evaluated more than once. For systems using file formats like ELF and COFF, when @value{GDBN} loads a new object file it will look for a special section named @code{.debug_gdb_scripts}. -If this section exists, its contents is a list of NUL-terminated names -of scripts to load. Each entry begins with a non-NULL prefix byte that -specifies the kind of entry, typically the extension language. +If this section exists, its contents is a list of NUL-terminated entries +specifying scripts to load. Each entry begins with a non-NULL prefix byte that +specifies the kind of entry, typically the extension language and whether the +script is in a file or inlined in @code{.debug_gdb_scripts}. +Supported values for the prefix byte are define in the +@file{include/gdb/section-scripts.h} file in the @value{GDBN} source tree. -@value{GDBN} will look for each specified script file first in the -current directory and then along the source search path +The following entries are supported: + +@table @code +@item SECTION_SCRIPT_ID_PYTHON_FILE = 1 +@item SECTION_SCRIPT_ID_SCHEME_FILE = 3 +@item SECTION_SCRIPT_ID_PYTHON_TEXT = 4 +@item SECTION_SCRIPT_ID_SCHEME_TEXT = 6 +@end table + +@subsubsection Script File Entries + +If the entry specifies a file, @value{GDBN} will look for the file first +in the current directory and then along the source search path (@pxref{Source Path, ,Specifying Source Directories}), except that @file{$cdir} is not searched, since the compilation directory is not relevant to scripts. -Entries can be placed in section @code{.debug_gdb_scripts} with, +File entries can be placed in section @code{.debug_gdb_scripts} with, for example, this GCC macro for Python scripts. @example @@ -24013,6 +24027,45 @@ using this header will get a reference to the specified script, and with the use of @code{"MS"} attributes on the section, the linker will remove duplicates. +@subsubsection Script Text Entries + +In script text entries the script to execute is contained in the entry +instead of being loaded from a file. +The first line of the entry, everything up to the first newline (@code{0xa}) +character, is the script name, and must not contain any kind of space +character, e.g., spaces or tabs. +The rest of the entry, up to the trailing NUL byte, is the script to +execute in the specified language. The name needs to be unique among +all script names, as @value{GDBN} executes each script only once based +on its name. + +Here is an example from file @file{py-section-script.c} in the @value{GDBN} +testsuite. + +@example +#include "symcat.h" +#include "gdb/section-scripts.h" +asm( +".pushsection \".debug_gdb_scripts\", \"MS\",@@progbits,1\n" +".byte " XSTRING (SECTION_SCRIPT_ID_PYTHON_TEXT) "\n" +".ascii \"gdb.inlined-script\\n\"\n" +".ascii \"class test_cmd (gdb.Command):\\n\"\n" +".ascii \" def __init__ (self):\\n\"\n" +".ascii \" super (test_cmd, self).__init__ (" + "\\\"test-cmd\\\", gdb.COMMAND_OBSCURE)\\n\"\n" +".ascii \" def invoke (self, arg, from_tty):\\n\"\n" +".ascii \" print (\\\"test-cmd output, arg = %s\\\" % arg)\\n\"\n" +".ascii \"test_cmd ()\\n\"\n" +".byte 0\n" +".popsection\n" +); +@end example + +Loading of inlined scripts require a properly configured +@code{auto-load safe-path} (@pxref{Auto-loading safe path}). +The path to specify in @code{auto-load safe-path} is the path of the file +containing the @code{.debug_gdb_scripts} section. + @node Which flavor to choose? @subsection Which flavor to choose? diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index b9a50d0..e8548e1 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -4744,8 +4744,9 @@ Show whether auto-loading of Python scripts is enabled or disabled. Print the list of all Python scripts that @value{GDBN} auto-loaded. Also printed is the list of Python scripts that were mentioned in -the @code{.debug_gdb_scripts} section and were not found -(@pxref{dotdebug_gdb_scripts section}). +the @code{.debug_gdb_scripts} section and were either not found +(@pxref{dotdebug_gdb_scripts section}) or were not auto-loaded due to +@code{auto-load safe-path} rejection (@pxref{Auto-loading}). This is useful because their names are not printed when @value{GDBN} tries to load them and fails. There may be many of them, and printing an error message for each one is problematic. @@ -4763,7 +4764,7 @@ No my-foo-pretty-printers.py @end smallexample @end table -When reading an auto-loaded file, @value{GDBN} sets the +When reading an auto-loaded file or script, @value{GDBN} sets the @dfn{current objfile}. This is available via the @code{gdb.current_objfile} function (@pxref{Objfiles In Python}). This can be useful for registering objfile-specific pretty-printers and frame-filters. diff --git a/gdb/extension-priv.h b/gdb/extension-priv.h index fc05137..dd2600e 100644 --- a/gdb/extension-priv.h +++ b/gdb/extension-priv.h @@ -103,6 +103,11 @@ struct extension_language_script_ops but is not required to, throw an error. */ objfile_script_sourcer_func *objfile_script_sourcer; + /* Execute a script attached to an objfile. + If there's an error while processing the script this function may, + but is not required to, throw an error. */ + objfile_script_executor_func *objfile_script_executor; + /* Return non-zero if auto-loading scripts in this extension language is enabled. */ int (*auto_load_enabled) (const struct extension_language_defn *); diff --git a/gdb/extension.c b/gdb/extension.c index 853ef67..77b62e0 100644 --- a/gdb/extension.c +++ b/gdb/extension.c @@ -61,6 +61,7 @@ static const struct extension_language_script_ops { source_gdb_script, source_gdb_objfile_script, + NULL, /* objfile_script_executor */ auto_load_gdb_scripts_enabled }; @@ -286,6 +287,21 @@ ext_lang_objfile_script_sourcer (const struct extension_language_defn *extlang) return extlang->script_ops->objfile_script_sourcer; } +/* Return the objfile script "executor" function for EXTLANG. + This is the function that executes a script for a particular objfile. + If support for this language isn't compiled in, NULL is returned. + The extension language is not required to implement this function. */ + +objfile_script_executor_func * +ext_lang_objfile_script_executor + (const struct extension_language_defn *extlang) +{ + if (extlang->script_ops == NULL) + return NULL; + + return extlang->script_ops->objfile_script_executor; +} + /* Return non-zero if auto-loading of EXTLANG scripts is enabled. Zero is returned if support for this language isn't compiled in. */ diff --git a/gdb/extension.h b/gdb/extension.h index a53f0a7..e8d7478 100644 --- a/gdb/extension.h +++ b/gdb/extension.h @@ -48,6 +48,12 @@ typedef void objfile_script_sourcer_func (const struct extension_language_defn *, struct objfile *, FILE *stream, const char *filename); +/* A function to execute a script for an objfile. + Any exceptions are not caught, and are passed to the caller. */ +typedef void objfile_script_executor_func + (const struct extension_language_defn *, + struct objfile *, const char *name, const char *script); + /* Enum of each extension(/scripting) language. */ enum extension_language @@ -197,6 +203,9 @@ extern script_sourcer_func *ext_lang_script_sourcer extern objfile_script_sourcer_func *ext_lang_objfile_script_sourcer (const struct extension_language_defn *); +extern objfile_script_executor_func *ext_lang_objfile_script_executor + (const struct extension_language_defn *); + extern int ext_lang_auto_load_enabled (const struct extension_language_defn *); /* Wrappers for each extension language API function that iterate over all diff --git a/gdb/guile/guile-internal.h b/gdb/guile/guile-internal.h index 968b4d3..9a8ef68 100644 --- a/gdb/guile/guile-internal.h +++ b/gdb/guile/guile-internal.h @@ -549,6 +549,7 @@ extern struct value *vlscm_convert_value_from_scheme /* stript_lang methods */ extern objfile_script_sourcer_func gdbscm_source_objfile_script; +extern objfile_script_executor_func gdbscm_execute_objfile_script; extern int gdbscm_auto_load_enabled (const struct extension_language_defn *); diff --git a/gdb/guile/guile.c b/gdb/guile/guile.c index c434ec0..319b583 100644 --- a/gdb/guile/guile.c +++ b/gdb/guile/guile.c @@ -128,6 +128,7 @@ static const struct extension_language_script_ops guile_extension_script_ops = { gdbscm_source_script, gdbscm_source_objfile_script, + gdbscm_execute_objfile_script, gdbscm_auto_load_enabled }; diff --git a/gdb/guile/scm-objfile.c b/gdb/guile/scm-objfile.c index 8162d01..8e94b96 100644 --- a/gdb/guile/scm-objfile.c +++ b/gdb/guile/scm-objfile.c @@ -283,7 +283,8 @@ gdbscm_set_objfile_pretty_printers_x (SCM self, SCM printers) \f /* The "current" objfile. This is set when gdb detects that a new objfile has been loaded. It is only set for the duration of a call to - gdbscm_source_objfile_script; it is NULL at other times. */ + gdbscm_source_objfile_script and gdbscm_execute_objfile_script; it is NULL + at other times. */ static struct objfile *ofscm_current_objfile; /* Set the current objfile to OBJFILE and then read FILE named FILENAME @@ -311,6 +312,31 @@ gdbscm_source_objfile_script (const struct extension_language_defn *extlang, ofscm_current_objfile = NULL; } +/* Set the current objfile to OBJFILE and then read FILE named FILENAME + as Guile code. This does not throw any errors. If an exception + occurs Guile will print the backtrace. + This is the extension_language_script_ops.objfile_script_sourcer + "method". */ + +void +gdbscm_execute_objfile_script (const struct extension_language_defn *extlang, + struct objfile *objfile, const char *name, + const char *script) +{ + char *msg; + + ofscm_current_objfile = objfile; + + msg = gdbscm_safe_eval_string (script, 0 /* display_result */); + if (msg != NULL) + { + fprintf_filtered (gdb_stderr, "%s", msg); + xfree (msg); + } + + ofscm_current_objfile = NULL; +} + /* (current-objfile) -> <gdb:obfjile> Return the current objfile, or #f if there isn't one. Ideally this would be named ofscm_current_objfile, but that name is diff --git a/gdb/python/python.c b/gdb/python/python.c index f4b8fcf..344d8d2 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -131,6 +131,7 @@ PyObject *gdbpy_gdb_memory_error; static script_sourcer_func gdbpy_source_script; static objfile_script_sourcer_func gdbpy_source_objfile_script; +static objfile_script_executor_func gdbpy_execute_objfile_script; static void gdbpy_finish_initialization (const struct extension_language_defn *); static int gdbpy_initialized (const struct extension_language_defn *); @@ -155,6 +156,7 @@ static const struct extension_language_script_ops python_extension_script_ops = { gdbpy_source_script, gdbpy_source_objfile_script, + gdbpy_execute_objfile_script, gdbpy_auto_load_enabled }; @@ -1262,7 +1264,8 @@ gdbpy_progspaces (PyObject *unused1, PyObject *unused2) /* The "current" objfile. This is set when gdb detects that a new objfile has been loaded. It is only set for the duration of a call to - gdbpy_source_objfile_script; it is NULL at other times. */ + gdbpy_source_objfile_script and gdbpy_execute_objfile_script; it is NULL + at other times. */ static struct objfile *gdbpy_current_objfile; /* Set the current objfile to OBJFILE and then read FILE named FILENAME @@ -1290,6 +1293,31 @@ gdbpy_source_objfile_script (const struct extension_language_defn *extlang, gdbpy_current_objfile = NULL; } +/* Set the current objfile to OBJFILE and then execute SCRIPT + as Python code. This does not throw any errors. If an exception + occurs python will print the traceback and clear the error indicator. + This is the extension_language_script_ops.objfile_script_executor + "method". */ + +static void +gdbpy_execute_objfile_script (const struct extension_language_defn *extlang, + struct objfile *objfile, const char *name, + const char *script) +{ + struct cleanup *cleanups; + + if (!gdb_python_initialized) + return; + + cleanups = ensure_python_env (get_objfile_arch (objfile), current_language); + gdbpy_current_objfile = objfile; + + PyRun_SimpleString (script); + + do_cleanups (cleanups); + gdbpy_current_objfile = NULL; +} + /* Return the current Objfile, or None if there isn't one. */ static PyObject * diff --git a/gdb/testsuite/gdb.guile/scm-section-script.c b/gdb/testsuite/gdb.guile/scm-section-script.c index e668a49..cbff698 100644 --- a/gdb/testsuite/gdb.guile/scm-section-script.c +++ b/gdb/testsuite/gdb.guile/scm-section-script.c @@ -19,18 +19,52 @@ #include "gdb/section-scripts.h" /* Put the path to the pretty-printer script in .debug_gdb_scripts so - gdb will automagically loaded it. */ + gdb will automagically loaded it. + Normally "MS" would appear here, as in + .pushsection ".debug_gdb_scripts", "MS",@progbits,1 + but we remove it to test files appearing twice in the section. */ #define DEFINE_GDB_SCRIPT(script_name) \ asm("\ -.pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n\ +.pushsection \".debug_gdb_scripts\", \"S\",@progbits\n\ .byte " XSTRING (SECTION_SCRIPT_ID_SCHEME_FILE) "\n\ .asciz \"" script_name "\"\n\ .popsection \n\ "); +#ifndef SCRIPT_FILE +#error "SCRIPT_FILE not defined" +#endif + +/* Specify it twice to verify the file is only loaded once. */ +DEFINE_GDB_SCRIPT (SCRIPT_FILE) DEFINE_GDB_SCRIPT (SCRIPT_FILE) +/* Inlined scripts are harder to create in the same way as + DEFINE_GDB_SCRIPT_FILE. Keep things simple and just define it here. + Normally "MS" would appear here, as in + .pushsection ".debug_gdb_scripts", "MS",@progbits,1 + but we remove it to test scripts appearing twice in the section. */ + +#define DEFINE_GDB_SCRIPT_TEXT \ +asm( \ +".pushsection \".debug_gdb_scripts\", \"S\",@progbits\n" \ +".byte " XSTRING (SECTION_SCRIPT_ID_SCHEME_TEXT) "\n" \ +".ascii \"gdb.inlined-script\\n\"\n" \ +".ascii \"(define test-cmd\\n\"\n" \ +".ascii \" (make-command \\\"test-cmd\\\"\\n\"\n" \ +".ascii \" #:command-class COMMAND_OBSCURE\\n\"\n" \ +".ascii \" #:invoke (lambda (self arg from-tty)\\n\"\n" \ +".ascii \" (display (format #f \\\"test-cmd output, arg = ~a\\n\\\" arg)))))\\n\"\n" \ +".ascii \"(register-command! test-cmd)\\n\"\n" \ +".byte 0\n" \ +".popsection\n" \ +); + +/* Specify it twice to verify the script is only executed once. */ +DEFINE_GDB_SCRIPT_TEXT +DEFINE_GDB_SCRIPT_TEXT + struct ss { int a; diff --git a/gdb/testsuite/gdb.guile/scm-section-script.exp b/gdb/testsuite/gdb.guile/scm-section-script.exp index 93a10a0..8c04ac8 100644 --- a/gdb/testsuite/gdb.guile/scm-section-script.exp +++ b/gdb/testsuite/gdb.guile/scm-section-script.exp @@ -53,14 +53,51 @@ gdb_start if { [skip_guile_tests] } { continue } gdb_reinitialize_dir $srcdir/$subdir -gdb_test_no_output "set auto-load safe-path ${remote_guile_file}" \ + +# Try first with a restrictive safe-path. + +gdb_test_no_output "set auto-load safe-path /restricted" \ + "set restricted auto-load safe-path" +gdb_load ${binfile} + +# Verify gdb did not load the scripts. +set test_name "verify scripts not loaded" +gdb_test_multiple "info auto-load guile-scripts" "$test_name" { + -re "Yes.*${testfile}.scm.*Yes.*inlined-script.*$gdb_prompt $" { + fail "$test_name" + } + -re "No.*${testfile}.scm.*No.*inlined-script.*$gdb_prompt $" { + pass "$test_name" + } +} + +# Try again with a working safe-path. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +gdb_test_no_output "set auto-load safe-path ${remote_guile_file}:${binfile}" \ "set auto-load safe-path" gdb_load ${binfile} -# Verify gdb loaded the script. -gdb_test "info auto-load guile-scripts" "Yes.*${testfile}.scm.*" +# Verify gdb loaded each script and they appear once in the list. +set test_name "verify scripts loaded" +gdb_test_multiple "info auto-load guile-scripts" "$test_name" { + -re "${testfile}.scm.*${testfile}.scm.*$gdb_prompt $" { + fail "$test_name" + } + -re "inlined-script.*inlined-script.*$gdb_prompt $" { + fail "$test_name" + } + -re "Yes.*${testfile}.scm.*Yes.*inlined-script.*$gdb_prompt $" { + pass "$test_name" + } +} + # Again, with a regexp this time. gdb_test "info auto-load guile-scripts ${testfile}" "Yes.*${testfile}.scm.*" + # Again, with a regexp that matches no scripts. gdb_test "info auto-load guile-scripts no-script-matches-this" \ "No auto-load scripts matching no-script-matches-this." @@ -74,3 +111,5 @@ gdb_test "b [gdb_get_line_number {break to inspect} ${testfile}.c ]" \ gdb_test "continue" ".*Breakpoint.*" gdb_test "print ss" " = a=<1> b=<2>" + +gdb_test "test-cmd 1 2 3" "test-cmd output, arg = 1 2 3" diff --git a/gdb/testsuite/gdb.python/py-section-script.c b/gdb/testsuite/gdb.python/py-section-script.c index 2cb606b..53af8cb 100644 --- a/gdb/testsuite/gdb.python/py-section-script.c +++ b/gdb/testsuite/gdb.python/py-section-script.c @@ -15,18 +15,55 @@ 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 "symcat.h" +#include "gdb/section-scripts.h" + /* Put the path to the pretty-printer script in .debug_gdb_scripts so - gdb will automagically loaded it. */ + gdb will automagically loaded it. + Normally "MS" would appear here, as in + .pushsection ".debug_gdb_scripts", "MS",@progbits,1 + but we remove it to test files appearing twice in the section. */ -#define DEFINE_GDB_SCRIPT(script_name) \ +#define DEFINE_GDB_SCRIPT_FILE(script_name) \ asm("\ -.pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n\ -.byte 1\n\ +.pushsection \".debug_gdb_scripts\", \"S\",@progbits\n\ +.byte " XSTRING (SECTION_SCRIPT_ID_PYTHON_FILE) "\n\ .asciz \"" script_name "\"\n\ -.popsection \n\ +.popsection\n\ "); -DEFINE_GDB_SCRIPT (SCRIPT_FILE) +#ifndef SCRIPT_FILE +#error "SCRIPT_FILE not defined" +#endif + +/* Specify it twice to verify the file is only loaded once. */ +DEFINE_GDB_SCRIPT_FILE (SCRIPT_FILE) +DEFINE_GDB_SCRIPT_FILE (SCRIPT_FILE) + +/* Inlined scripts are harder to create in the same way as + DEFINE_GDB_SCRIPT_FILE. Keep things simple and just define it here. + Normally "MS" would appear here, as in + .pushsection ".debug_gdb_scripts", "MS",@progbits,1 + but we remove it to test scripts appearing twice in the section. */ + +#define DEFINE_GDB_SCRIPT_TEXT \ +asm( \ +".pushsection \".debug_gdb_scripts\", \"S\",@progbits\n" \ +".byte " XSTRING (SECTION_SCRIPT_ID_PYTHON_TEXT) "\n" \ +".ascii \"gdb.inlined-script\\n\"\n" \ +".ascii \"class test_cmd (gdb.Command):\\n\"\n" \ +".ascii \" def __init__ (self):\\n\"\n" \ +".ascii \" super (test_cmd, self).__init__ (\\\"test-cmd\\\", gdb.COMMAND_OBSCURE)\\n\"\n" \ +".ascii \" def invoke (self, arg, from_tty):\\n\"\n" \ +".ascii \" print (\\\"test-cmd output, arg = %s\\\" % arg)\\n\"\n" \ +".ascii \"test_cmd ()\\n\"\n" \ +".byte 0\n" \ +".popsection\n" \ +); + +/* Specify it twice to verify the script is only executed once. */ +DEFINE_GDB_SCRIPT_TEXT +DEFINE_GDB_SCRIPT_TEXT struct ss { diff --git a/gdb/testsuite/gdb.python/py-section-script.exp b/gdb/testsuite/gdb.python/py-section-script.exp index 11c0453..840430d 100644 --- a/gdb/testsuite/gdb.python/py-section-script.exp +++ b/gdb/testsuite/gdb.python/py-section-script.exp @@ -39,7 +39,9 @@ set remote_python_file [gdb_remote_download host \ set quoted_name "\"$remote_python_file\"" if {[build_executable $testfile.exp $testfile $srcfile \ - [list debug additional_flags=-DSCRIPT_FILE=$quoted_name]] == -1} { + [list debug \ + additional_flags=-I${srcdir}/../../include \ + additional_flags=-DSCRIPT_FILE=$quoted_name]] == -1} { return -1 } @@ -51,13 +53,51 @@ gdb_start if { [skip_python_tests] } { continue } gdb_reinitialize_dir $srcdir/$subdir -gdb_test_no_output "set auto-load safe-path ${remote_python_file}" "set auto-load safe-path" + +# Try first with a restrictive safe-path. + +gdb_test_no_output "set auto-load safe-path /restricted" \ + "set restricted auto-load safe-path" gdb_load ${binfile} -# Verify gdb loaded the script. -gdb_test "info auto-load python-scripts" "Yes.*${testfile}.py.*" +# Verify gdb did not load the scripts. +set test_name "verify scripts not loaded" +gdb_test_multiple "info auto-load python-scripts" "$test_name" { + -re "Yes.*${testfile}.py.*Yes.*inlined-script.*$gdb_prompt $" { + fail "$test_name" + } + -re "No.*${testfile}.py.*No.*inlined-script.*$gdb_prompt $" { + pass "$test_name" + } +} + +# Try again with a working safe-path. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +gdb_test_no_output "set auto-load safe-path ${remote_python_file}:${binfile}" \ + "set auto-load safe-path" +gdb_load ${binfile} + +# Verify gdb loaded each script and they appear once in the list. +set test_name "verify scripts loaded" +gdb_test_multiple "info auto-load python-scripts" "$test_name" { + -re "${testfile}.py.*${testfile}.py.*$gdb_prompt $" { + fail "$test_name" + } + -re "inlined-script.*inlined-script.*$gdb_prompt $" { + fail "$test_name" + } + -re "Yes.*${testfile}.py.*Yes.*inlined-script.*$gdb_prompt $" { + pass "$test_name" + } +} + # Again, with a regexp this time. gdb_test "info auto-load python-scripts ${testfile}" "Yes.*${testfile}.py.*" + # Again, with a regexp that matches no scripts. gdb_test "info auto-load python-scripts no-script-matches-this" \ "No auto-load scripts matching no-script-matches-this." @@ -72,3 +112,5 @@ gdb_test "b [gdb_get_line_number {break to inspect} ${testfile}.c ]" \ gdb_test "continue" ".*Breakpoint.*" gdb_test "print ss" " = a=<1> b=<2>" + +gdb_test "test-cmd 1 2 3" "test-cmd output, arg = 1 2 3" ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-01-15 17:32 [PATCH] Add support for embedding scripts in .debug_gdb_scripts Doug Evans @ 2015-01-15 18:11 ` Eli Zaretskii 2015-01-16 17:15 ` Doug Evans 2015-01-31 23:31 ` Doug Evans 1 sibling, 1 reply; 19+ messages in thread From: Eli Zaretskii @ 2015-01-15 18:11 UTC (permalink / raw) To: Doug Evans; +Cc: binutils, gdb-patches > From: Doug Evans <xdje42@gmail.com> > Date: Thu, 15 Jan 2015 09:31:48 -0800 > > +* Python/Guile scripting > + > +** GDB now supports auto-loading of Python/Guile scripts contained in the > + special section named `.debug_gdb_scripts'. I think we should tell here on what systems/targets this is supported. Otherwise, the NEWS entry is OK. > For systems using file formats like ELF and COFF, > when @value{GDBN} loads a new object file > it will look for a special section named @code{.debug_gdb_scripts}. Is this really supported with non-ELF targets? E.g., does pe-coff (Windows) support such sections? > +If this section exists, its contents is a list of NUL-terminated entries > +specifying scripts to load. Each entry begins with a non-NULL prefix byte that Let's be consistent here" "null", lower-case and with 2 'l'. This is just a plain English word, not an acronym or a C symbol. > +Supported values for the prefix byte are define in the ^^^^^^ "defined" > +@file{include/gdb/section-scripts.h} file in the @value{GDBN} source tree. Is this really helpful? If that file is installed, let's mention where to find it in the installed tree; if it is not installed, we ought to list the values here, since the reader might not have access to the source tree, let alone the one from which the binary was produced. > +The following entries are supported: > + > +@table @code > +@item SECTION_SCRIPT_ID_PYTHON_FILE = 1 > +@item SECTION_SCRIPT_ID_SCHEME_FILE = 3 > +@item SECTION_SCRIPT_ID_PYTHON_TEXT = 4 > +@item SECTION_SCRIPT_ID_SCHEME_TEXT = 6 > +@end table Are these the values of the prefix byte? If so, we should simply skip the pointer to the source tree. > +@subsubsection Script Text Entries > + > +In script text entries the script to execute is contained in the entry > +instead of being loaded from a file. Suggest to reword this sentence: Script text entries allow to put the executable script in the entry itself instead of loading it from a file. > +The rest of the entry, up to the trailing NUL byte, ^^^ "null" > is the script to > +execute in the specified language. Specified how and by what means? > +Loading of inlined scripts require a properly configured ^^^^^^^ "requires" Thanks. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-01-15 18:11 ` Eli Zaretskii @ 2015-01-16 17:15 ` Doug Evans 2015-01-16 18:02 ` Eli Zaretskii 0 siblings, 1 reply; 19+ messages in thread From: Doug Evans @ 2015-01-16 17:15 UTC (permalink / raw) To: Eli Zaretskii; +Cc: binutils, gdb-patches [-- Attachment #1: Type: text/plain, Size: 3034 bytes --] On Thu, Jan 15, 2015 at 10:11 AM, Eli Zaretskii <eliz@gnu.org> wrote: >> From: Doug Evans <xdje42@gmail.com> >> Date: Thu, 15 Jan 2015 09:31:48 -0800 >> >> +* Python/Guile scripting >> + >> +** GDB now supports auto-loading of Python/Guile scripts contained in the >> + special section named `.debug_gdb_scripts'. > > I think we should tell here on what systems/targets this is supported. > Otherwise, the NEWS entry is OK. The previous news entry didn't, and I'm following that. >> For systems using file formats like ELF and COFF, >> when @value{GDBN} loads a new object file >> it will look for a special section named @code{.debug_gdb_scripts}. > > Is this really supported with non-ELF targets? E.g., does pe-coff > (Windows) support such sections? My mingw32 toolchain generates DWARF (i.e., has .debug_* sections). >> +If this section exists, its contents is a list of NUL-terminated entries >> +specifying scripts to load. Each entry begins with a non-NULL prefix byte that > > Let's be consistent here" "null", lower-case and with 2 'l'. This is > just a plain English word, not an acronym or a C symbol. NULL is a typo, thanks for catching that. I'm just following usage elsewhere in gdb.texinfo, and I like this choice. > >> +Supported values for the prefix byte are define in the > ^^^^^^ > "defined" Done. > >> +@file{include/gdb/section-scripts.h} file in the @value{GDBN} source tree. > > Is this really helpful? If that file is installed, let's mention > where to find it in the installed tree; if it is not installed, we > ought to list the values here, since the reader might not have access > to the source tree, let alone the one from which the binary was > produced. > >> +The following entries are supported: >> + >> +@table @code >> +@item SECTION_SCRIPT_ID_PYTHON_FILE = 1 >> +@item SECTION_SCRIPT_ID_SCHEME_FILE = 3 >> +@item SECTION_SCRIPT_ID_PYTHON_TEXT = 4 >> +@item SECTION_SCRIPT_ID_SCHEME_TEXT = 6 >> +@end table > > Are these the values of the prefix byte? If so, we should simply skip > the pointer to the source tree. Done. > >> +@subsubsection Script Text Entries >> + >> +In script text entries the script to execute is contained in the entry >> +instead of being loaded from a file. > > Suggest to reword this sentence: > > Script text entries allow to put the executable script in the entry > itself instead of loading it from a file. Done. > >> +The rest of the entry, up to the trailing NUL byte, > ^^^ > "null" Copied from gdb.texinfo. Plus we've had this conversation before. :-) https://sourceware.org/ml/gdb-patches/2013-12/msg00892.html https://sourceware.org/ml/gdb-patches/2013-12/msg00894.html > >> is the script to >> +execute in the specified language. > > Specified how and by what means? > >> +Loading of inlined scripts require a properly configured > ^^^^^^^ > "requires" Done. [-- Attachment #2: embedded-scripts-2.patch.txt --] [-- Type: text/plain, Size: 51497 bytes --] 2015-01-16 Doug Evans <xdje42@gmail.com> Add support for inlining scripts into .debug_gdb_scripts. include/ * gdb/section-scripts.h: Remove "future extension" comment. (SECTION_SCRIPT_ID_PYTHON_TEXT): New macro. (SECTION_SCRIPT_ID_SCHEME_TEXT): New macro. gdb/ * NEWS: Mention inlined scripts in .debug_gdb_scripts section. * auto-load.c: #include ctype.h. (struct auto_load_pspace_info): Replace member loaded_scripts with new members loaded_script_files, loaded_script_texts. (auto_load_pspace_data_cleanup): Update. (init_loaded_scripts_info): Update. (get_auto_load_pspace_data_for_loading): Update. (maybe_add_script_file): Renamed from maybe_add_script. All callers updated. (maybe_add_script_text): New function. (clear_section_scripts): Update. (source_script_file, execute_script_contents): New functions. (source_section_scripts): Add support for SECTION_SCRIPT_ID_PYTHON_TEXT, SECTION_SCRIPT_ID_GUILE_TEXT. (print_scripts): New function. (auto_load_info_scripts): Also print inlined scripts. (maybe_print_unsupported_script_warning): Renamed from unsupported_script_warning_print. All callers updated. (maybe_print_script_not_found_warning): Renamed from script_not_found_warning_print. All callers updated. * extension-priv.h (struct extension_language_script_ops): New member objfile_script_executor. * extension.c (ext_lang_objfile_script_executor): New function. * extension.h (objfile_script_executor_func): New typedef. (ext_lang_objfile_script_executor): Declare. * guile/guile-internal.h (gdbscm_execute_objfile_script): Declare. * guile/guile.c (guile_extension_script_ops): Update. * guile/scm-objfile.c (gdbscm_execute_objfile_script): New function. * python/python.c (python_extension_script_ops): Update. (gdbpy_execute_objfile_script): New function. doc/ * gdb.texinfo (dotdebug_gdb_scripts section): Update docs to distinguish script files vs inlined scripts. * python.texi (Python Auto-loading): Ditto. testsuite/ * gdb.guile/scm-section-script.c: Add duplicate inlined section script entries. Duplicate file section script entries. * gdb.guile/scm-section-script.exp: Add tests for duplicate entries, inlined entries. Add test for safe-path rejection. * gdb.python/py-section-script.c: Add duplicate inlined section script entries. Duplicate file section script entries. * gdb.python/py-section-script.exp: Add tests for duplicate entries, inlined entries. Add test for safe-path rejection. diff --git a/include/gdb/section-scripts.h b/include/gdb/section-scripts.h index c4b7a1c..effce62 100644 --- a/include/gdb/section-scripts.h +++ b/include/gdb/section-scripts.h @@ -28,8 +28,6 @@ Other unused values needn't specify different scripting languages, but we have no need for anything else at the moment. - Future extension: Include the contents of the script in the section. - These values are defined as macros so that they can be used in embedded asms and assembler source files. */ @@ -47,4 +45,18 @@ file. */ #define SECTION_SCRIPT_ID_SCHEME_FILE 3 +/* The record is a nul-terminated string. + The first line is the name of the script. + Subsequent lines are interpreted as a python script. */ +#define SECTION_SCRIPT_ID_PYTHON_TEXT 4 + +/* Native GDB scripts are not currently supported in .debug_gdb_scripts, + but we reserve a value for it. */ +/*#define SECTION_SCRIPT_ID_GDB_TEXT 5*/ + +/* The record is a nul-terminated string. + The first line is the name of the script. + Subsequent lines are interpreted as a guile(scheme) script. */ +#define SECTION_SCRIPT_ID_SCHEME_TEXT 6 + #endif /* GDB_SECTION_SCRIPTS_H */ diff --git a/gdb/NEWS b/gdb/NEWS index 2d2c941..baf1868 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -3,6 +3,11 @@ *** Changes since GDB 7.9 +* Python/Guile scripting + +** GDB now supports auto-loading of Python/Guile scripts contained in the + special section named `.debug_gdb_scripts'. + *** Changes in GDB 7.9 * GDB now supports hardware watchpoints on x86 GNU Hurd. diff --git a/gdb/auto-load.c b/gdb/auto-load.c index c152778..778eeb6 100644 --- a/gdb/auto-load.c +++ b/gdb/auto-load.c @@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "defs.h" +#include <ctype.h> #include "auto-load.h" #include "progspace.h" #include "gdb_regex.h" @@ -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; @@ -541,8 +543,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. */ @@ -553,7 +557,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 { @@ -561,7 +565,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. */ @@ -578,8 +582,10 @@ auto_load_pspace_data_cleanup (struct program_space *pspace, void *arg) { struct auto_load_pspace_info *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); } @@ -632,10 +638,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; @@ -650,23 +660,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; @@ -677,7 +688,7 @@ 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; @@ -703,6 +714,44 @@ 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 = 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 @@ -712,10 +761,12 @@ clear_section_scripts (void) struct auto_load_pspace_info *info; info = program_space_data (pspace, auto_load_pspace_data); - if (info != NULL && info->loaded_scripts != NULL) + 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; } @@ -803,7 +854,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. @@ -864,17 +916,183 @@ auto_load_objfile_script (struct objfile *objfile, do_cleanups (cleanups); } +/* 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) +{ + FILE *stream; + char *full_path; + int opened, in_hash_table; + struct cleanup *cleanups; + 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; + } + + opened = find_and_open_script (file, 1 /*search_path*/, + &stream, &full_path); + + cleanups = 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. */ + + maybe_print_script_not_found_warning (pspace_info, objfile, language, + section_name, offset); + } + + in_hash_table = maybe_add_script_file (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 (cleanups); +} + +/* 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, *end; + 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); +} + /* Load scripts specified in OBJFILE. START,END delimit a buffer containing a list of nul-terminated 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, @@ -887,20 +1105,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: @@ -909,105 +1126,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); } } @@ -1146,6 +1295,23 @@ 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 (VEC (loaded_script_ptr) *scripts) +{ + struct ui_out *uiout = current_uiout; + 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); +} + /* 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. */ @@ -1157,7 +1323,7 @@ auto_load_info_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; + VEC (loaded_script_ptr) *script_files, *script_texts; int nr_scripts; dont_repeat (); @@ -1180,25 +1346,38 @@ 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); + script_files = VEC_alloc (loaded_script_ptr, 10); + script_texts = VEC_alloc (loaded_script_ptr, 10); + script_chain = make_cleanup (VEC_cleanup (loaded_script_ptr), &script_files); + make_cleanup (VEC_cleanup (loaded_script_ptr), &script_texts); + + if (pspace_info != NULL && pspace_info->loaded_script_files != NULL) + { + struct 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); + } - 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 }; + struct 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); } - nr_scripts = VEC_length (loaded_script_ptr, scripts); + nr_scripts = (VEC_length (loaded_script_ptr, script_files) + + VEC_length (loaded_script_ptr, script_texts)); /* 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"); + /* Note: This creates a cleanup to output the table end marker. */ make_cleanup_ui_out_table_begin_end (uiout, 2, nr_scripts, "AutoLoadedScriptsTable"); @@ -1206,18 +1385,10 @@ auto_load_info_scripts (char *pattern, int from_tty, 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); - } + print_scripts (script_files); + print_scripts (script_texts); + /* Finish up the table before checking for no matching scripts. */ do_cleanups (script_chain); if (nr_scripts == 0) @@ -1253,32 +1424,48 @@ 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. */ diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index b059ac2..31f3138 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -23971,17 +23971,29 @@ is evaluated more than once. For systems using file formats like ELF and COFF, when @value{GDBN} loads a new object file it will look for a special section named @code{.debug_gdb_scripts}. -If this section exists, its contents is a list of NUL-terminated names -of scripts to load. Each entry begins with a non-NULL prefix byte that -specifies the kind of entry, typically the extension language. +If this section exists, its contents is a list of NUL-terminated entries +specifying scripts to load. Each entry begins with a non-NUL prefix byte that +specifies the kind of entry, typically the extension language and whether the +script is in a file or inlined in @code{.debug_gdb_scripts}. -@value{GDBN} will look for each specified script file first in the -current directory and then along the source search path +The following entries are supported: + +@table @code +@item SECTION_SCRIPT_ID_PYTHON_FILE = 1 +@item SECTION_SCRIPT_ID_SCHEME_FILE = 3 +@item SECTION_SCRIPT_ID_PYTHON_TEXT = 4 +@item SECTION_SCRIPT_ID_SCHEME_TEXT = 6 +@end table + +@subsubsection Script File Entries + +If the entry specifies a file, @value{GDBN} will look for the file first +in the current directory and then along the source search path (@pxref{Source Path, ,Specifying Source Directories}), except that @file{$cdir} is not searched, since the compilation directory is not relevant to scripts. -Entries can be placed in section @code{.debug_gdb_scripts} with, +File entries can be placed in section @code{.debug_gdb_scripts} with, for example, this GCC macro for Python scripts. @example @@ -24013,6 +24025,45 @@ using this header will get a reference to the specified script, and with the use of @code{"MS"} attributes on the section, the linker will remove duplicates. +@subsubsection Script Text Entries + +Script text entries allow to put the executable script in the entry +itself instead of loading it from a file. +The first line of the entry, everything up to the first newline (@code{0xa}) +character, is the script name, and must not contain any kind of space +character, e.g., spaces or tabs. +The rest of the entry, up to the trailing NUL byte, is the script to +execute in the specified language. The name needs to be unique among +all script names, as @value{GDBN} executes each script only once based +on its name. + +Here is an example from file @file{py-section-script.c} in the @value{GDBN} +testsuite. + +@example +#include "symcat.h" +#include "gdb/section-scripts.h" +asm( +".pushsection \".debug_gdb_scripts\", \"MS\",@@progbits,1\n" +".byte " XSTRING (SECTION_SCRIPT_ID_PYTHON_TEXT) "\n" +".ascii \"gdb.inlined-script\\n\"\n" +".ascii \"class test_cmd (gdb.Command):\\n\"\n" +".ascii \" def __init__ (self):\\n\"\n" +".ascii \" super (test_cmd, self).__init__ (" + "\\\"test-cmd\\\", gdb.COMMAND_OBSCURE)\\n\"\n" +".ascii \" def invoke (self, arg, from_tty):\\n\"\n" +".ascii \" print (\\\"test-cmd output, arg = %s\\\" % arg)\\n\"\n" +".ascii \"test_cmd ()\\n\"\n" +".byte 0\n" +".popsection\n" +); +@end example + +Loading of inlined scripts requires a properly configured +@code{auto-load safe-path} (@pxref{Auto-loading safe path}). +The path to specify in @code{auto-load safe-path} is the path of the file +containing the @code{.debug_gdb_scripts} section. + @node Which flavor to choose? @subsection Which flavor to choose? diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index b9a50d0..e8548e1 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -4744,8 +4744,9 @@ Show whether auto-loading of Python scripts is enabled or disabled. Print the list of all Python scripts that @value{GDBN} auto-loaded. Also printed is the list of Python scripts that were mentioned in -the @code{.debug_gdb_scripts} section and were not found -(@pxref{dotdebug_gdb_scripts section}). +the @code{.debug_gdb_scripts} section and were either not found +(@pxref{dotdebug_gdb_scripts section}) or were not auto-loaded due to +@code{auto-load safe-path} rejection (@pxref{Auto-loading}). This is useful because their names are not printed when @value{GDBN} tries to load them and fails. There may be many of them, and printing an error message for each one is problematic. @@ -4763,7 +4764,7 @@ No my-foo-pretty-printers.py @end smallexample @end table -When reading an auto-loaded file, @value{GDBN} sets the +When reading an auto-loaded file or script, @value{GDBN} sets the @dfn{current objfile}. This is available via the @code{gdb.current_objfile} function (@pxref{Objfiles In Python}). This can be useful for registering objfile-specific pretty-printers and frame-filters. diff --git a/gdb/extension-priv.h b/gdb/extension-priv.h index fc05137..dd2600e 100644 --- a/gdb/extension-priv.h +++ b/gdb/extension-priv.h @@ -103,6 +103,11 @@ struct extension_language_script_ops but is not required to, throw an error. */ objfile_script_sourcer_func *objfile_script_sourcer; + /* Execute a script attached to an objfile. + If there's an error while processing the script this function may, + but is not required to, throw an error. */ + objfile_script_executor_func *objfile_script_executor; + /* Return non-zero if auto-loading scripts in this extension language is enabled. */ int (*auto_load_enabled) (const struct extension_language_defn *); diff --git a/gdb/extension.c b/gdb/extension.c index 853ef67..77b62e0 100644 --- a/gdb/extension.c +++ b/gdb/extension.c @@ -61,6 +61,7 @@ static const struct extension_language_script_ops { source_gdb_script, source_gdb_objfile_script, + NULL, /* objfile_script_executor */ auto_load_gdb_scripts_enabled }; @@ -286,6 +287,21 @@ ext_lang_objfile_script_sourcer (const struct extension_language_defn *extlang) return extlang->script_ops->objfile_script_sourcer; } +/* Return the objfile script "executor" function for EXTLANG. + This is the function that executes a script for a particular objfile. + If support for this language isn't compiled in, NULL is returned. + The extension language is not required to implement this function. */ + +objfile_script_executor_func * +ext_lang_objfile_script_executor + (const struct extension_language_defn *extlang) +{ + if (extlang->script_ops == NULL) + return NULL; + + return extlang->script_ops->objfile_script_executor; +} + /* Return non-zero if auto-loading of EXTLANG scripts is enabled. Zero is returned if support for this language isn't compiled in. */ diff --git a/gdb/extension.h b/gdb/extension.h index a53f0a7..e8d7478 100644 --- a/gdb/extension.h +++ b/gdb/extension.h @@ -48,6 +48,12 @@ typedef void objfile_script_sourcer_func (const struct extension_language_defn *, struct objfile *, FILE *stream, const char *filename); +/* A function to execute a script for an objfile. + Any exceptions are not caught, and are passed to the caller. */ +typedef void objfile_script_executor_func + (const struct extension_language_defn *, + struct objfile *, const char *name, const char *script); + /* Enum of each extension(/scripting) language. */ enum extension_language @@ -197,6 +203,9 @@ extern script_sourcer_func *ext_lang_script_sourcer extern objfile_script_sourcer_func *ext_lang_objfile_script_sourcer (const struct extension_language_defn *); +extern objfile_script_executor_func *ext_lang_objfile_script_executor + (const struct extension_language_defn *); + extern int ext_lang_auto_load_enabled (const struct extension_language_defn *); /* Wrappers for each extension language API function that iterate over all diff --git a/gdb/guile/guile-internal.h b/gdb/guile/guile-internal.h index 968b4d3..9a8ef68 100644 --- a/gdb/guile/guile-internal.h +++ b/gdb/guile/guile-internal.h @@ -549,6 +549,7 @@ extern struct value *vlscm_convert_value_from_scheme /* stript_lang methods */ extern objfile_script_sourcer_func gdbscm_source_objfile_script; +extern objfile_script_executor_func gdbscm_execute_objfile_script; extern int gdbscm_auto_load_enabled (const struct extension_language_defn *); diff --git a/gdb/guile/guile.c b/gdb/guile/guile.c index c434ec0..319b583 100644 --- a/gdb/guile/guile.c +++ b/gdb/guile/guile.c @@ -128,6 +128,7 @@ static const struct extension_language_script_ops guile_extension_script_ops = { gdbscm_source_script, gdbscm_source_objfile_script, + gdbscm_execute_objfile_script, gdbscm_auto_load_enabled }; diff --git a/gdb/guile/scm-objfile.c b/gdb/guile/scm-objfile.c index 8162d01..8e94b96 100644 --- a/gdb/guile/scm-objfile.c +++ b/gdb/guile/scm-objfile.c @@ -283,7 +283,8 @@ gdbscm_set_objfile_pretty_printers_x (SCM self, SCM printers) \f /* The "current" objfile. This is set when gdb detects that a new objfile has been loaded. It is only set for the duration of a call to - gdbscm_source_objfile_script; it is NULL at other times. */ + gdbscm_source_objfile_script and gdbscm_execute_objfile_script; it is NULL + at other times. */ static struct objfile *ofscm_current_objfile; /* Set the current objfile to OBJFILE and then read FILE named FILENAME @@ -311,6 +312,31 @@ gdbscm_source_objfile_script (const struct extension_language_defn *extlang, ofscm_current_objfile = NULL; } +/* Set the current objfile to OBJFILE and then read FILE named FILENAME + as Guile code. This does not throw any errors. If an exception + occurs Guile will print the backtrace. + This is the extension_language_script_ops.objfile_script_sourcer + "method". */ + +void +gdbscm_execute_objfile_script (const struct extension_language_defn *extlang, + struct objfile *objfile, const char *name, + const char *script) +{ + char *msg; + + ofscm_current_objfile = objfile; + + msg = gdbscm_safe_eval_string (script, 0 /* display_result */); + if (msg != NULL) + { + fprintf_filtered (gdb_stderr, "%s", msg); + xfree (msg); + } + + ofscm_current_objfile = NULL; +} + /* (current-objfile) -> <gdb:obfjile> Return the current objfile, or #f if there isn't one. Ideally this would be named ofscm_current_objfile, but that name is diff --git a/gdb/python/python.c b/gdb/python/python.c index f4b8fcf..344d8d2 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -131,6 +131,7 @@ PyObject *gdbpy_gdb_memory_error; static script_sourcer_func gdbpy_source_script; static objfile_script_sourcer_func gdbpy_source_objfile_script; +static objfile_script_executor_func gdbpy_execute_objfile_script; static void gdbpy_finish_initialization (const struct extension_language_defn *); static int gdbpy_initialized (const struct extension_language_defn *); @@ -155,6 +156,7 @@ static const struct extension_language_script_ops python_extension_script_ops = { gdbpy_source_script, gdbpy_source_objfile_script, + gdbpy_execute_objfile_script, gdbpy_auto_load_enabled }; @@ -1262,7 +1264,8 @@ gdbpy_progspaces (PyObject *unused1, PyObject *unused2) /* The "current" objfile. This is set when gdb detects that a new objfile has been loaded. It is only set for the duration of a call to - gdbpy_source_objfile_script; it is NULL at other times. */ + gdbpy_source_objfile_script and gdbpy_execute_objfile_script; it is NULL + at other times. */ static struct objfile *gdbpy_current_objfile; /* Set the current objfile to OBJFILE and then read FILE named FILENAME @@ -1290,6 +1293,31 @@ gdbpy_source_objfile_script (const struct extension_language_defn *extlang, gdbpy_current_objfile = NULL; } +/* Set the current objfile to OBJFILE and then execute SCRIPT + as Python code. This does not throw any errors. If an exception + occurs python will print the traceback and clear the error indicator. + This is the extension_language_script_ops.objfile_script_executor + "method". */ + +static void +gdbpy_execute_objfile_script (const struct extension_language_defn *extlang, + struct objfile *objfile, const char *name, + const char *script) +{ + struct cleanup *cleanups; + + if (!gdb_python_initialized) + return; + + cleanups = ensure_python_env (get_objfile_arch (objfile), current_language); + gdbpy_current_objfile = objfile; + + PyRun_SimpleString (script); + + do_cleanups (cleanups); + gdbpy_current_objfile = NULL; +} + /* Return the current Objfile, or None if there isn't one. */ static PyObject * diff --git a/gdb/testsuite/gdb.guile/scm-section-script.c b/gdb/testsuite/gdb.guile/scm-section-script.c index e668a49..cbff698 100644 --- a/gdb/testsuite/gdb.guile/scm-section-script.c +++ b/gdb/testsuite/gdb.guile/scm-section-script.c @@ -19,18 +19,52 @@ #include "gdb/section-scripts.h" /* Put the path to the pretty-printer script in .debug_gdb_scripts so - gdb will automagically loaded it. */ + gdb will automagically loaded it. + Normally "MS" would appear here, as in + .pushsection ".debug_gdb_scripts", "MS",@progbits,1 + but we remove it to test files appearing twice in the section. */ #define DEFINE_GDB_SCRIPT(script_name) \ asm("\ -.pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n\ +.pushsection \".debug_gdb_scripts\", \"S\",@progbits\n\ .byte " XSTRING (SECTION_SCRIPT_ID_SCHEME_FILE) "\n\ .asciz \"" script_name "\"\n\ .popsection \n\ "); +#ifndef SCRIPT_FILE +#error "SCRIPT_FILE not defined" +#endif + +/* Specify it twice to verify the file is only loaded once. */ +DEFINE_GDB_SCRIPT (SCRIPT_FILE) DEFINE_GDB_SCRIPT (SCRIPT_FILE) +/* Inlined scripts are harder to create in the same way as + DEFINE_GDB_SCRIPT_FILE. Keep things simple and just define it here. + Normally "MS" would appear here, as in + .pushsection ".debug_gdb_scripts", "MS",@progbits,1 + but we remove it to test scripts appearing twice in the section. */ + +#define DEFINE_GDB_SCRIPT_TEXT \ +asm( \ +".pushsection \".debug_gdb_scripts\", \"S\",@progbits\n" \ +".byte " XSTRING (SECTION_SCRIPT_ID_SCHEME_TEXT) "\n" \ +".ascii \"gdb.inlined-script\\n\"\n" \ +".ascii \"(define test-cmd\\n\"\n" \ +".ascii \" (make-command \\\"test-cmd\\\"\\n\"\n" \ +".ascii \" #:command-class COMMAND_OBSCURE\\n\"\n" \ +".ascii \" #:invoke (lambda (self arg from-tty)\\n\"\n" \ +".ascii \" (display (format #f \\\"test-cmd output, arg = ~a\\n\\\" arg)))))\\n\"\n" \ +".ascii \"(register-command! test-cmd)\\n\"\n" \ +".byte 0\n" \ +".popsection\n" \ +); + +/* Specify it twice to verify the script is only executed once. */ +DEFINE_GDB_SCRIPT_TEXT +DEFINE_GDB_SCRIPT_TEXT + struct ss { int a; diff --git a/gdb/testsuite/gdb.guile/scm-section-script.exp b/gdb/testsuite/gdb.guile/scm-section-script.exp index 93a10a0..8c04ac8 100644 --- a/gdb/testsuite/gdb.guile/scm-section-script.exp +++ b/gdb/testsuite/gdb.guile/scm-section-script.exp @@ -53,14 +53,51 @@ gdb_start if { [skip_guile_tests] } { continue } gdb_reinitialize_dir $srcdir/$subdir -gdb_test_no_output "set auto-load safe-path ${remote_guile_file}" \ + +# Try first with a restrictive safe-path. + +gdb_test_no_output "set auto-load safe-path /restricted" \ + "set restricted auto-load safe-path" +gdb_load ${binfile} + +# Verify gdb did not load the scripts. +set test_name "verify scripts not loaded" +gdb_test_multiple "info auto-load guile-scripts" "$test_name" { + -re "Yes.*${testfile}.scm.*Yes.*inlined-script.*$gdb_prompt $" { + fail "$test_name" + } + -re "No.*${testfile}.scm.*No.*inlined-script.*$gdb_prompt $" { + pass "$test_name" + } +} + +# Try again with a working safe-path. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +gdb_test_no_output "set auto-load safe-path ${remote_guile_file}:${binfile}" \ "set auto-load safe-path" gdb_load ${binfile} -# Verify gdb loaded the script. -gdb_test "info auto-load guile-scripts" "Yes.*${testfile}.scm.*" +# Verify gdb loaded each script and they appear once in the list. +set test_name "verify scripts loaded" +gdb_test_multiple "info auto-load guile-scripts" "$test_name" { + -re "${testfile}.scm.*${testfile}.scm.*$gdb_prompt $" { + fail "$test_name" + } + -re "inlined-script.*inlined-script.*$gdb_prompt $" { + fail "$test_name" + } + -re "Yes.*${testfile}.scm.*Yes.*inlined-script.*$gdb_prompt $" { + pass "$test_name" + } +} + # Again, with a regexp this time. gdb_test "info auto-load guile-scripts ${testfile}" "Yes.*${testfile}.scm.*" + # Again, with a regexp that matches no scripts. gdb_test "info auto-load guile-scripts no-script-matches-this" \ "No auto-load scripts matching no-script-matches-this." @@ -74,3 +111,5 @@ gdb_test "b [gdb_get_line_number {break to inspect} ${testfile}.c ]" \ gdb_test "continue" ".*Breakpoint.*" gdb_test "print ss" " = a=<1> b=<2>" + +gdb_test "test-cmd 1 2 3" "test-cmd output, arg = 1 2 3" diff --git a/gdb/testsuite/gdb.python/py-section-script.c b/gdb/testsuite/gdb.python/py-section-script.c index 2cb606b..53af8cb 100644 --- a/gdb/testsuite/gdb.python/py-section-script.c +++ b/gdb/testsuite/gdb.python/py-section-script.c @@ -15,18 +15,55 @@ 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 "symcat.h" +#include "gdb/section-scripts.h" + /* Put the path to the pretty-printer script in .debug_gdb_scripts so - gdb will automagically loaded it. */ + gdb will automagically loaded it. + Normally "MS" would appear here, as in + .pushsection ".debug_gdb_scripts", "MS",@progbits,1 + but we remove it to test files appearing twice in the section. */ -#define DEFINE_GDB_SCRIPT(script_name) \ +#define DEFINE_GDB_SCRIPT_FILE(script_name) \ asm("\ -.pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n\ -.byte 1\n\ +.pushsection \".debug_gdb_scripts\", \"S\",@progbits\n\ +.byte " XSTRING (SECTION_SCRIPT_ID_PYTHON_FILE) "\n\ .asciz \"" script_name "\"\n\ -.popsection \n\ +.popsection\n\ "); -DEFINE_GDB_SCRIPT (SCRIPT_FILE) +#ifndef SCRIPT_FILE +#error "SCRIPT_FILE not defined" +#endif + +/* Specify it twice to verify the file is only loaded once. */ +DEFINE_GDB_SCRIPT_FILE (SCRIPT_FILE) +DEFINE_GDB_SCRIPT_FILE (SCRIPT_FILE) + +/* Inlined scripts are harder to create in the same way as + DEFINE_GDB_SCRIPT_FILE. Keep things simple and just define it here. + Normally "MS" would appear here, as in + .pushsection ".debug_gdb_scripts", "MS",@progbits,1 + but we remove it to test scripts appearing twice in the section. */ + +#define DEFINE_GDB_SCRIPT_TEXT \ +asm( \ +".pushsection \".debug_gdb_scripts\", \"S\",@progbits\n" \ +".byte " XSTRING (SECTION_SCRIPT_ID_PYTHON_TEXT) "\n" \ +".ascii \"gdb.inlined-script\\n\"\n" \ +".ascii \"class test_cmd (gdb.Command):\\n\"\n" \ +".ascii \" def __init__ (self):\\n\"\n" \ +".ascii \" super (test_cmd, self).__init__ (\\\"test-cmd\\\", gdb.COMMAND_OBSCURE)\\n\"\n" \ +".ascii \" def invoke (self, arg, from_tty):\\n\"\n" \ +".ascii \" print (\\\"test-cmd output, arg = %s\\\" % arg)\\n\"\n" \ +".ascii \"test_cmd ()\\n\"\n" \ +".byte 0\n" \ +".popsection\n" \ +); + +/* Specify it twice to verify the script is only executed once. */ +DEFINE_GDB_SCRIPT_TEXT +DEFINE_GDB_SCRIPT_TEXT struct ss { diff --git a/gdb/testsuite/gdb.python/py-section-script.exp b/gdb/testsuite/gdb.python/py-section-script.exp index 11c0453..840430d 100644 --- a/gdb/testsuite/gdb.python/py-section-script.exp +++ b/gdb/testsuite/gdb.python/py-section-script.exp @@ -39,7 +39,9 @@ set remote_python_file [gdb_remote_download host \ set quoted_name "\"$remote_python_file\"" if {[build_executable $testfile.exp $testfile $srcfile \ - [list debug additional_flags=-DSCRIPT_FILE=$quoted_name]] == -1} { + [list debug \ + additional_flags=-I${srcdir}/../../include \ + additional_flags=-DSCRIPT_FILE=$quoted_name]] == -1} { return -1 } @@ -51,13 +53,51 @@ gdb_start if { [skip_python_tests] } { continue } gdb_reinitialize_dir $srcdir/$subdir -gdb_test_no_output "set auto-load safe-path ${remote_python_file}" "set auto-load safe-path" + +# Try first with a restrictive safe-path. + +gdb_test_no_output "set auto-load safe-path /restricted" \ + "set restricted auto-load safe-path" gdb_load ${binfile} -# Verify gdb loaded the script. -gdb_test "info auto-load python-scripts" "Yes.*${testfile}.py.*" +# Verify gdb did not load the scripts. +set test_name "verify scripts not loaded" +gdb_test_multiple "info auto-load python-scripts" "$test_name" { + -re "Yes.*${testfile}.py.*Yes.*inlined-script.*$gdb_prompt $" { + fail "$test_name" + } + -re "No.*${testfile}.py.*No.*inlined-script.*$gdb_prompt $" { + pass "$test_name" + } +} + +# Try again with a working safe-path. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +gdb_test_no_output "set auto-load safe-path ${remote_python_file}:${binfile}" \ + "set auto-load safe-path" +gdb_load ${binfile} + +# Verify gdb loaded each script and they appear once in the list. +set test_name "verify scripts loaded" +gdb_test_multiple "info auto-load python-scripts" "$test_name" { + -re "${testfile}.py.*${testfile}.py.*$gdb_prompt $" { + fail "$test_name" + } + -re "inlined-script.*inlined-script.*$gdb_prompt $" { + fail "$test_name" + } + -re "Yes.*${testfile}.py.*Yes.*inlined-script.*$gdb_prompt $" { + pass "$test_name" + } +} + # Again, with a regexp this time. gdb_test "info auto-load python-scripts ${testfile}" "Yes.*${testfile}.py.*" + # Again, with a regexp that matches no scripts. gdb_test "info auto-load python-scripts no-script-matches-this" \ "No auto-load scripts matching no-script-matches-this." @@ -72,3 +112,5 @@ gdb_test "b [gdb_get_line_number {break to inspect} ${testfile}.c ]" \ gdb_test "continue" ".*Breakpoint.*" gdb_test "print ss" " = a=<1> b=<2>" + +gdb_test "test-cmd 1 2 3" "test-cmd output, arg = 1 2 3" ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-01-16 17:15 ` Doug Evans @ 2015-01-16 18:02 ` Eli Zaretskii 2015-01-17 1:16 ` Doug Evans 0 siblings, 1 reply; 19+ messages in thread From: Eli Zaretskii @ 2015-01-16 18:02 UTC (permalink / raw) To: Doug Evans; +Cc: binutils, gdb-patches > Date: Fri, 16 Jan 2015 09:15:35 -0800 > From: Doug Evans <xdje42@gmail.com> > Cc: binutils@sourceware.org, "gdb-patches@sourceware.org" <gdb-patches@sourceware.org> > > >> +* Python/Guile scripting > >> + > >> +** GDB now supports auto-loading of Python/Guile scripts contained in the > >> + special section named `.debug_gdb_scripts'. > > > > I think we should tell here on what systems/targets this is supported. > > Otherwise, the NEWS entry is OK. > > The previous news entry didn't, and I'm following that. So we have no hope for ever fixing past mistakes? > > Let's be consistent here" "null", lower-case and with 2 'l'. This is > > just a plain English word, not an acronym or a C symbol. > > NULL is a typo, thanks for catching that. > I'm just following usage elsewhere in gdb.texinfo, > and I like this choice. So we have no hope for ever fixing past mistakes? > >> +The rest of the entry, up to the trailing NUL byte, > > ^^^ > > "null" > > Copied from gdb.texinfo. > Plus we've had this conversation before. :-) > > https://sourceware.org/ml/gdb-patches/2013-12/msg00892.html > https://sourceware.org/ml/gdb-patches/2013-12/msg00894.html So we have no hope for ever fixing past mistakes? ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-01-16 18:02 ` Eli Zaretskii @ 2015-01-17 1:16 ` Doug Evans 2015-01-17 8:16 ` Eli Zaretskii 0 siblings, 1 reply; 19+ messages in thread From: Doug Evans @ 2015-01-17 1:16 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches [- binutils] On Fri, Jan 16, 2015 at 10:01 AM, Eli Zaretskii <eliz@gnu.org> wrote: > So we have no hope for ever fixing past mistakes? Past mistakes? .debug_gdb_scripts isn't that old of a feature. Maybe we need more formal community-agreed-on conventions and rules for NEWS and docs. These things seem to be of a "shall be this way" flavor, and I wasn't expecting that. When I cut-n-paste from code I can usually tell what's expected, but I can't do that for NEWS/doc, and we should fix that. [Imagine if coding conventions changed like this.] ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-01-17 1:16 ` Doug Evans @ 2015-01-17 8:16 ` Eli Zaretskii 2015-01-18 4:16 ` Doug Evans 0 siblings, 1 reply; 19+ messages in thread From: Eli Zaretskii @ 2015-01-17 8:16 UTC (permalink / raw) To: Doug Evans; +Cc: gdb-patches > Date: Fri, 16 Jan 2015 17:15:49 -0800 > From: Doug Evans <xdje42@gmail.com> > Cc: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org> > > On Fri, Jan 16, 2015 at 10:01 AM, Eli Zaretskii <eliz@gnu.org> wrote: > > So we have no hope for ever fixing past mistakes? > > Past mistakes? > .debug_gdb_scripts isn't that old of a feature. I wasn't talking only about that. I was talking in general about the argument "we do this elsewhere 'like this', so let's continue doing that 'like this'". For example, the "NUL" thingie. > Maybe we need more formal community-agreed-on > conventions and rules for NEWS and docs. Maybe we should, but I'd like first to agree that an argument of this kind doesn't have too much weight. It's okay to look at past practices when the choice is purely stylistic. But when there are clear advantages to deviating from past practices, those past practices shouldn't hold us back, otherwise we will stagnate. Agreed? In this case, "NUL" is simply incorrect English: there's no such word or acronym. The only legitimate use of "NUL" I know of is in reference to the DOS/Windows null device. As for showing the systems where .debug_gdb_scripts feature is supported, there are clear advantages to providing that information in NEWS, and the price is quite low, I hope you will agree. I can also live with you asking me in response to please change all the other instances to use the same style. But what I would prefer not to live with is flat refusal to make a requested change in your patch because "we do that elsewhere". > These things seem to be of a "shall be this way" flavor, > and I wasn't expecting that. Isn't that normal during patch review process? > When I cut-n-paste from code I can usually > tell what's expected, but I can't do that for NEWS/doc, From experience, my requests are remarkably consistent, even if the same issues pop up with quite some time in-between. You've just cited a similar discussion about NUL from more than a year ago, which I didn't event remember. > [Imagine if coding conventions changed like this.] They do, because standards.texi is actively maintained. Things I've read and memorized years ago have changed, sometimes radically so, and I keep bumping into them when people say my code isn't according to GCS and cite from there. That's life, and I accept it. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-01-17 8:16 ` Eli Zaretskii @ 2015-01-18 4:16 ` Doug Evans 2015-01-18 16:23 ` Eli Zaretskii 0 siblings, 1 reply; 19+ messages in thread From: Doug Evans @ 2015-01-18 4:16 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches On Sat, Jan 17, 2015 at 12:17 AM, Eli Zaretskii <eliz@gnu.org> wrote: >> Date: Fri, 16 Jan 2015 17:15:49 -0800 >> From: Doug Evans <xdje42@gmail.com> >> Cc: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org> >> >> On Fri, Jan 16, 2015 at 10:01 AM, Eli Zaretskii <eliz@gnu.org> wrote: >> > So we have no hope for ever fixing past mistakes? >> >> Past mistakes? >> .debug_gdb_scripts isn't that old of a feature. > > I wasn't talking only about that. I was talking in general about the > argument "we do this elsewhere 'like this', so let's continue doing > that 'like this'". For example, the "NUL" thingie. NUL has been the name of the zero byte in ASCII since the early 60s. It's hardly a "thingie". http://en.wikipedia.org/wiki/ASCII > >> Maybe we need more formal community-agreed-on >> conventions and rules for NEWS and docs. > > Maybe we should, but I'd like first to agree that an argument of this > kind doesn't have too much weight. It's okay to look at past > practices when the choice is purely stylistic. But when there are > clear advantages to deviating from past practices, those past > practices shouldn't hold us back, otherwise we will stagnate. Agreed? Only to the extent that such reasoning must be re-evaluated every time it is applied. Plus, I don't understand the point about more formal conventions not having too much weight. People should be able to write code with some expectation that what they've written is correct. The same should be true with NEWS/doc. And one way we do that is with documented rules and conventions. If we're going to have such stringent rules in gdb for NEWS/docs, then I think at least things that have been non-obvious in the past should be written down. > In this case, "NUL" is simply incorrect English: there's no such word > or acronym. The only legitimate use of "NUL" I know of is in > reference to the DOS/Windows null device. Au contraire. NUL has been the common name of the zero byte since long before gdb was born. Ref: above link on ASCII, for example > As for showing the systems where .debug_gdb_scripts feature is > supported, there are clear advantages to providing that information in > NEWS, and the price is quite low, I hope you will agree. It is documented in gdb.texinfo. I don't see the point of repeating it in NEWS, especially for a case such as this. [I just don't see its presence in this particular case making a material difference in anyone's life.] https://sourceware.org/gdb/current/onlinedocs/gdb/dotdebug_005fgdb_005fscripts-section.html#dotdebug_005fgdb_005fscripts-section Tell ya what though. Let's add a new section to the conventions wiki for NEWS/docs. One of those entries will be: All NEWS entries for new features shall specify the platform(s) on which the feature is available, if it is not a generally available feature. [or words to that effect] And let's enforce all these rules the way we do coding conventions (which I don't have a problem with). Ok? That way everyone can be on the same page, and there is a document one can refer people to. > I can also live with you asking me in response to please change all > the other instances to use the same style. But what I would prefer > not to live with is flat refusal to make a requested change in your > patch because "we do that elsewhere". If I believe the request is invalid (e.g., NUL), then I've got to push back. In the NUL case, this term is so common that to outlaw it in gdb docs would be a real shame. I wasn't aware, until now, that you weren't aware of how common NUL is. Otherwise I would have pointed it out sooner. Sorry! Also, until the patch is checked in, it's premature to assess whether anything was flatly refused. I proposed writing down rules NEWS/doc entries are expected to follow. Ideally there won't be many, but certainly non-obvious ones should be, and as for who decides what's non-obvious: anytime discussions like these comes up works for me. If the community agrees to requiring new non-general features in NEWS to always specify the platform they're for, then I'm happy to go with the flow. >> These things seem to be of a "shall be this way" flavor, >> and I wasn't expecting that. > > Isn't that normal during patch review process? Not when one of the choices is perfectly valid (e.g., NUL). >> When I cut-n-paste from code I can usually >> tell what's expected, but I can't do that for NEWS/doc, > > From experience, my requests are remarkably consistent, even if the > same issues pop up with quite some time in-between. You've just cited > a similar discussion about NUL from more than a year ago, which I > didn't event remember. > >> [Imagine if coding conventions changed like this.] > > They do, because standards.texi is actively maintained. Things I've > read and memorized years ago have changed, sometimes radically so, and > I keep bumping into them when people say my code isn't according to > GCS and cite from there. That's life, and I accept it. They don't change the way I was thinking of when I wrote that. a) gdb's coding standards don't change that frequently. b) they're documented. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-01-18 4:16 ` Doug Evans @ 2015-01-18 16:23 ` Eli Zaretskii 2015-01-18 20:48 ` Doug Evans 0 siblings, 1 reply; 19+ messages in thread From: Eli Zaretskii @ 2015-01-18 16:23 UTC (permalink / raw) To: Doug Evans; +Cc: gdb-patches > Date: Sat, 17 Jan 2015 20:15:46 -0800 > From: Doug Evans <xdje42@gmail.com> > Cc: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org> > > > I wasn't talking only about that. I was talking in general about the > > argument "we do this elsewhere 'like this', so let's continue doing > > that 'like this'". For example, the "NUL" thingie. > > NUL has been the name of the zero byte in ASCII since the early 60s. Not any longer: its Unicode name is "NULL" (upper-case, because Unicode uses upper-case for all character names). And even back then, this was an abbreviation, not the full name. > > Maybe we should, but I'd like first to agree that an argument of this > > kind doesn't have too much weight. It's okay to look at past > > practices when the choice is purely stylistic. But when there are > > clear advantages to deviating from past practices, those past > > practices shouldn't hold us back, otherwise we will stagnate. Agreed? > > Only to the extent that such reasoning must be re-evaluated > every time it is applied. I agree with "re-evaluated". I don't agree with "rejected" as the default modus operandi. > Plus, I don't understand the point about more formal conventions > not having too much weight. People should be able to write code > with some expectation that what they've written is correct. > The same should be true with NEWS/doc. > And one way we do that is with documented rules and conventions. I don't think it's reasonable, or even practical, to codify each and every case like that. Did you really mean that we write down something like "use 'null byte' for the byte whose value is zero, including, but not limited to, when talking about C-style string terminator"? There would be any number of such "rules"; following them will probably be a much higher PITA than occasionally having to replace words after a review. I normally don't argue about style, except when I think there's more than just style at stake. Eventually, people should trust the validity of my views on these matters, or ask me to step down. > > In this case, "NUL" is simply incorrect English: there's no such word > > or acronym. The only legitimate use of "NUL" I know of is in > > reference to the DOS/Windows null device. > > Au contraire. > NUL has been the common name of the zero byte since long before > gdb was born. > Ref: above link on ASCII, for example See above. In any case, you weren't talking about "NUL" the name, you said things like "NUL-terminated names" and "non-NUL prefix byte". This isn't about "NUL" the character's archaic name, this is about a byte whose value is zero, a.k.a. "null". And our audience is 21st century readers, not vintage 1960s flock of assembly-language programmers, for whom NUL and STX were acronyms they saw all day every day. Nowadays, this is simply an obstacle to reading and understanding the text. The purpose of my comments was to make the text more readable. > Let's add a new section to the conventions wiki for NEWS/docs. > One of those entries will be: > > All NEWS entries for new features shall specify the platform(s) on which > the feature is available, if it is not a generally available feature. > [or words to that effect] > And let's enforce all these rules the way we do > coding conventions (which I don't have a problem with). > > Ok? I'm fine with that, if no one objects. But you cannot possibly codify all such minor issues, they are too many. And it isn't needed, from my POV. > > I can also live with you asking me in response to please change all > > the other instances to use the same style. But what I would prefer > > not to live with is flat refusal to make a requested change in your > > patch because "we do that elsewhere". > > If I believe the request is invalid (e.g., NUL), then > I've got to push back. You did, and I called you. If it weren't important, I would've accepted. I didn't. Where do we go from here? > Also, until the patch is checked in, it's premature > to assess whether anything was flatly refused. You didn't agree and didn't propose any compromise, so how else to understand your reaction? > If the community agrees to requiring new non-general features > in NEWS to always specify the platform they're for, then I'm happy > to go with the flow. IMO, which changes need to mention the platforms is a judgment call. So no such generally enforced rule is necessary. But if we want to state that always, I don't object, although in many cases it will be redundant, and will probably say something like "supported on all platforms". I suspect we won't like the result. > >> These things seem to be of a "shall be this way" flavor, > >> and I wasn't expecting that. > > > > Isn't that normal during patch review process? > > Not when one of the choices is perfectly valid (e.g., NUL). So is the text I proposed instead. This isn't about validity, this is about making the text more easily read and understood. Judging human-readable text includes suggesting better wording, even if the original one is valid. When I suggest a different wording or spelling, I don't necessarily mean to say the original was incorrect or invalid, just that there's a better one. Don't we want our manual to be as best as possible? ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-01-18 16:23 ` Eli Zaretskii @ 2015-01-18 20:48 ` Doug Evans 2015-01-19 14:49 ` Joel Brobecker 2015-01-19 16:05 ` Eli Zaretskii 0 siblings, 2 replies; 19+ messages in thread From: Doug Evans @ 2015-01-18 20:48 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches On Sun, Jan 18, 2015 at 8:22 AM, Eli Zaretskii <eliz@gnu.org> wrote: >> Date: Sat, 17 Jan 2015 20:15:46 -0800 >> From: Doug Evans <xdje42@gmail.com> >> Cc: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org> >> >> > I wasn't talking only about that. I was talking in general about the >> > argument "we do this elsewhere 'like this', so let's continue doing >> > that 'like this'". For example, the "NUL" thingie. >> >> NUL has been the name of the zero byte in ASCII since the early 60s. > > Not any longer: its Unicode name is "NULL" (upper-case, because > Unicode uses upper-case for all character names). I guess what we need is an agreed upon reference saying NUL is gone. I *like* NUL. It's explicitly different than null or NULL. Last time you said you wouldn't argue, but now it's become an absolute requirement. The rules for how to write NUL/null/NULL have changed, and that's unfortunate. And there was no discussion going into this decision (I guess we're having it now, but still ...). > And even back then, > this was an abbreviation, not the full name. It's a name, abbreviated or otherwise. And a nice one to because it's clear and unambiguous. >> > Maybe we should, but I'd like first to agree that an argument of this >> > kind doesn't have too much weight. It's okay to look at past >> > practices when the choice is purely stylistic. But when there are >> > clear advantages to deviating from past practices, those past >> > practices shouldn't hold us back, otherwise we will stagnate. Agreed? >> >> Only to the extent that such reasoning must be re-evaluated >> every time it is applied. > > I agree with "re-evaluated". I don't agree with "rejected" as the > default modus operandi. > >> Plus, I don't understand the point about more formal conventions >> not having too much weight. People should be able to write code >> with some expectation that what they've written is correct. >> The same should be true with NEWS/doc. >> And one way we do that is with documented rules and conventions. > > I don't think it's reasonable, or even practical, to codify each and > every case like that. Did you really mean that we write down > something like "use 'null byte' for the byte whose value is zero, > including, but not limited to, when talking about C-style string > terminator"? I'm not sure I'd use formal phrasings such as "but not limited to", but I would want to say that one must write, e.g., null-terminated instead of NUL-terminated. We have a bazillion coding convention rules, for good reasons. I think we can manage a few more for docs. There are doc writing conventions already, btw, http://www.gnu.org/prep/standards/standards.html#Documentation and, heh, I'd forgotten that I'd already started a wiki page for local rules/conventions. https://sourceware.org/gdb/wiki/Internals%20GDB-Doc-Standards So at least that part is done. :-) > There would be any number of such "rules"; following > them will probably be a much higher PITA than occasionally having to > replace words after a review. Depends, I think. If in the future one doesn't understand or even disagrees with the replacement (how many disagree with our coding convention of half-indented braces! 1/2 :-)) then having such things written down will help advance the discussion, in part because the discussion has already been had and decided! > I normally don't argue about style, except when I think there's more > than just style at stake. Eventually, people should trust the > validity of my views on these matters, or ask me to step down. This isn't about asking anyone to step down. This should also not be about trust. If you can present a convincing argument that draws on external references to support your claim that NUL is "archaic" and shall not be used in new documentation, I'll certainly re-evaluate my opinion. [I'll also hold an Irish-style wake for NUL. Guinness for everyone! 1/2 :-)] >> > In this case, "NUL" is simply incorrect English: there's no such word >> > or acronym. The only legitimate use of "NUL" I know of is in >> > reference to the DOS/Windows null device. >> >> Au contraire. >> NUL has been the common name of the zero byte since long before >> gdb was born. >> Ref: above link on ASCII, for example > > See above. I still see NUL being referred to in the various places I look as a valid name (abbreviation or otherwise). > In any case, you weren't talking about "NUL" the name, you said things > like "NUL-terminated names" and "non-NUL prefix byte". This isn't > about "NUL" the character's archaic name, this is about a byte whose > value is zero, a.k.a. "null". The distinction is lost on me. E.g., NUL-terminated names are strings of characters, the last one of which has the valid name of NUL. > And our audience is 21st century > readers, not vintage 1960s flock of assembly-language programmers, for > whom NUL and STX were acronyms they saw all day every day. for reference sake, This characterization bothers me. > Nowadays, > this is simply an obstacle to reading and understanding the text. The > purpose of my comments was to make the text more readable. Alas the loss in readability is lost on me. Is it really an obstacle to reading and understanding the text? I'm not convinced. >> Let's add a new section to the conventions wiki for NEWS/docs. >> One of those entries will be: >> >> All NEWS entries for new features shall specify the platform(s) on which >> the feature is available, if it is not a generally available feature. >> [or words to that effect] >> And let's enforce all these rules the way we do >> coding conventions (which I don't have a problem with). >> >> Ok? > > I'm fine with that, if no one objects. But you cannot possibly codify > all such minor issues, they are too many. And it isn't needed, from > my POV. If it serves to put in writing absolute rules that someone is likely to get tripped up by or not understand then it will have served its purpose. >> > I can also live with you asking me in response to please change all >> > the other instances to use the same style. But what I would prefer >> > not to live with is flat refusal to make a requested change in your >> > patch because "we do that elsewhere". >> >> If I believe the request is invalid (e.g., NUL), then >> I've got to push back. > > You did, and I called you. If it weren't important, I would've > accepted. I didn't. Where do we go from here? Called me? I'm not sure how to interpret that. I'm guessing no one else is interested in the discussion, which is not unreasonable :-), so where we go is I write "null-terminated" and get it written down so that I can remember it. >> Also, until the patch is checked in, it's premature >> to assess whether anything was flatly refused. > > You didn't agree and didn't propose any compromise, so how else to > understand your reaction? Not rush to judgment would be a start. "flatly refused" is pretty out there. If our roles were reversed (the topic would have be different of course) I would have said something like "I really think [...] is the way to go because [...]. Please reconsider." And even then I may not impose any kind of veto. [E.g., in a different thread the pascal folks want to add a patch that I think is unnecessary (though there's still an outstanding question, and there may be a use-case where the patch adds value) but I can live with it, with perhaps a few mods and comments to the effect that it's a pascal-specific choice. Depending on the answer to the outstanding question, I'd be uncomfortable with that choice becoming more general though.] >> If the community agrees to requiring new non-general features >> in NEWS to always specify the platform they're for, then I'm happy >> to go with the flow. > > IMO, which changes need to mention the platforms is a judgment call. > So no such generally enforced rule is necessary. But if we want to > state that always, I don't object, although in many cases it will be > redundant, and will probably say something like "supported on all > platforms". I suspect we won't like the result. I don't understand. I explicitly wrote that I was only talking about the cases other than "supported on all platforms." Of course we wouldn't like THAT result. >> >> These things seem to be of a "shall be this way" flavor, >> >> and I wasn't expecting that. >> > >> > Isn't that normal during patch review process? >> >> Not when one of the choices is perfectly valid (e.g., NUL). > > So is the text I proposed instead. This isn't about validity, this is > about making the text more easily read and understood. IMO it's not an improvement. > Judging human-readable text includes suggesting better wording, even > if the original one is valid. When I suggest a different wording or > spelling, I don't necessarily mean to say the original was incorrect > or invalid, just that there's a better one. Don't we want our manual > to be as best as possible? "Suggest"? Are you sure you meant to write that? [I do try to review what I say before I hit Send, but I don't always succeed and catch everything, and I certainly allow anyone else to hit Send to soon as well.] If I've made a suggestion to someone, and they don't take it, then if it really was just a suggestion I'd accept that. If, OTOH, they still preferred their solution, and while I may have used the word suggestion the first time when in reality it was intended as a command, then I would then say so. The person I'm talking to might take my future "suggestions" a little more tepidly though, so clarity is important here. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-01-18 20:48 ` Doug Evans @ 2015-01-19 14:49 ` Joel Brobecker 2015-01-20 16:35 ` Doug Evans 2015-01-19 16:05 ` Eli Zaretskii 1 sibling, 1 reply; 19+ messages in thread From: Joel Brobecker @ 2015-01-19 14:49 UTC (permalink / raw) To: Doug Evans; +Cc: Eli Zaretskii, gdb-patches > >> All NEWS entries for new features shall specify the platform(s) on which > >> the feature is available, if it is not a generally available feature. > >> [or words to that effect] > >> And let's enforce all these rules the way we do > >> coding conventions (which I don't have a problem with). > >> > >> Ok? > > > > I'm fine with that, if no one objects. But you cannot possibly codify > > all such minor issues, they are too many. And it isn't needed, from > > my POV. > > If it serves to put in writing absolute rules that someone is likely > to get tripped up by or not understand then it will have served its > purpose. I just personally think this is too extreme a measure. There are times when absolute rules may be useful, but I don't think this is the case here. Eli is our documentation maintainer,so let's continue trusting his judgement. This discussion is not about black and white, and as such, it's easy to disagree. But I don't think it's important enough to spend more time on this. I know it can be fustrating to make a change one does not believe in, but after a reasonable attempt at discussing it, I'd go with his call. -- Joel ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-01-19 14:49 ` Joel Brobecker @ 2015-01-20 16:35 ` Doug Evans 2015-01-21 9:57 ` Joel Brobecker ` (2 more replies) 0 siblings, 3 replies; 19+ messages in thread From: Doug Evans @ 2015-01-20 16:35 UTC (permalink / raw) To: Joel Brobecker; +Cc: Eli Zaretskii, gdb-patches On Mon, Jan 19, 2015 at 6:49 AM, Joel Brobecker <brobecker@adacore.com> wrote: >> >> All NEWS entries for new features shall specify the platform(s) on which >> >> the feature is available, if it is not a generally available feature. >> >> [or words to that effect] >> >> And let's enforce all these rules the way we do >> >> coding conventions (which I don't have a problem with). >> >> >> >> Ok? >> > >> > I'm fine with that, if no one objects. But you cannot possibly codify >> > all such minor issues, they are too many. And it isn't needed, from >> > my POV. >> >> If it serves to put in writing absolute rules that someone is likely >> to get tripped up by or not understand then it will have served its >> purpose. > > I just personally think this is too extreme a measure. There are times > when absolute rules may be useful, but I don't think this is the case > here. Eh? What we have here *is* an absolute rule: We used to be allowed to use phrases like NUL-terminated in documentation, now we are not. > Eli is our documentation maintainer,so let's continue trusting > his judgement. This discussion is not about black and white, and > as such, it's easy to disagree. But I don't think it's important > enough to spend more time on this. I know it can be fustrating > to make a change one does not believe in, but after a reasonable > attempt at discussing it, I'd go with his call. I for one would liked to have seen the data to back up the claim that NUL-terminated is archaic. It's not that I don't trust someone's judgement, rather it's that that's the wrong way to impose the change. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-01-20 16:35 ` Doug Evans @ 2015-01-21 9:57 ` Joel Brobecker 2015-02-13 16:15 ` Stan Shebs 2015-02-13 18:05 ` Pedro Alves 2 siblings, 0 replies; 19+ messages in thread From: Joel Brobecker @ 2015-01-21 9:57 UTC (permalink / raw) To: Doug Evans; +Cc: Eli Zaretskii, gdb-patches > > I just personally think this is too extreme a measure. There are times > > when absolute rules may be useful, but I don't think this is the case > > here. > > Eh? What we have here *is* an absolute rule: > We used to be allowed to use phrases like NUL-terminated > in documentation, now we are not. True, but I just think it's not worth starting to write _rules_ down. If we start writing such rules down, then that means that we must write down all other rules. Which seems OK in principle, but when you get to that level of details, the list can become so long as to be really hard to keep in mind. What I'm getting at is that this is really a detail, and if we want to make a rule of it, I'd create one more general that says "no outdated expression" may be used. > > Eli is our documentation maintainer,so let's continue trusting > > his judgement. This discussion is not about black and white, and > > as such, it's easy to disagree. But I don't think it's important > > enough to spend more time on this. I know it can be fustrating > > to make a change one does not believe in, but after a reasonable > > attempt at discussing it, I'd go with his call. > > I for one would liked to have seen the data to back up > the claim that NUL-terminated is archaic. > It's not that I don't trust someone's judgement, rather it's that that's > the wrong way to impose the change. FWIW, and this is only my personal opinion of course, since you are in fact entitled to getting an explanation: Eli telling me, as our Documentation Maintainer, "it reads better if you use [blah]", is usually enough for me to follow his lead and make the change. I'd have to disagree fairly strongly to argue further. Since (I think) Eli tried to explain, is that the case, here? That you disagree fairly strongly with Eli's assessment? -- Joel ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-01-20 16:35 ` Doug Evans 2015-01-21 9:57 ` Joel Brobecker @ 2015-02-13 16:15 ` Stan Shebs 2015-02-13 16:45 ` Eli Zaretskii 2015-02-13 16:46 ` Andreas Schwab 2015-02-13 18:05 ` Pedro Alves 2 siblings, 2 replies; 19+ messages in thread From: Stan Shebs @ 2015-02-13 16:15 UTC (permalink / raw) To: gdb-patches On 1/20/15 8:35 AM, Doug Evans wrote: > [...] > > I for one would liked to have seen the data to back up > the claim that NUL-terminated is archaic. > It's not that I don't trust someone's judgement, rather it's that that's > the wrong way to impose the change. Reminiscent of my Wikipedia editing days! It's pretty difficult to prove obsolescence of a particular usage; Wikipedia editors trying to decide the "most common" form of a term would resort to elaborate combinations of Google searches, and then get mired down in meta-debate about whether the searches were returning valid numbers - or whether 55% for A and 45% for B was a meaningful difference. My instant reaction is that "NUL-terminated" is an old-fashioned usage, but I can't say exactly when it declined. To some extent all the control codes became more obscure due to the shift from terminals to window systems, and I imagine the increasing use of char encodings beyond original ASCII has had an effect as well. In general, I would like to have the documentation maintainer be more of an editor, to have more of a free hand in deciding style rules, and to not insist that everything has to be written down beforehand. The flip side of the expectation is that we do need patches that make the documents follow the rules reliably, so future contributors are not misled. Stan ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-02-13 16:15 ` Stan Shebs @ 2015-02-13 16:45 ` Eli Zaretskii 2015-02-13 16:46 ` Andreas Schwab 1 sibling, 0 replies; 19+ messages in thread From: Eli Zaretskii @ 2015-02-13 16:45 UTC (permalink / raw) To: Stan Shebs; +Cc: gdb-patches > Date: Fri, 13 Feb 2015 08:15:32 -0800 > From: Stan Shebs <stanshebs@earthlink.net> > > In general, I would like to have the documentation maintainer be more of > an editor, to have more of a free hand in deciding style rules, and to > not insist that everything has to be written down beforehand. I'm okay with that, but I'm also trying not to prevent contributors from saying things their way. Some people quite understandably feel attached to what they wrote, so unnecessary changes risk causing aggravation. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-02-13 16:15 ` Stan Shebs 2015-02-13 16:45 ` Eli Zaretskii @ 2015-02-13 16:46 ` Andreas Schwab 1 sibling, 0 replies; 19+ messages in thread From: Andreas Schwab @ 2015-02-13 16:46 UTC (permalink / raw) To: Stan Shebs; +Cc: gdb-patches How about using "zero-terminated"? Andreas. -- Andreas Schwab, schwab@linux-m68k.org GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different." ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-01-20 16:35 ` Doug Evans 2015-01-21 9:57 ` Joel Brobecker 2015-02-13 16:15 ` Stan Shebs @ 2015-02-13 18:05 ` Pedro Alves 2015-02-15 11:53 ` Corinna Vinschen 2 siblings, 1 reply; 19+ messages in thread From: Pedro Alves @ 2015-02-13 18:05 UTC (permalink / raw) To: Doug Evans, Joel Brobecker; +Cc: Eli Zaretskii, gdb-patches On 01/20/2015 04:35 PM, Doug Evans wrote: > I for one would liked to have seen the data to back up > the claim that NUL-terminated is archaic. > It's not that I don't trust someone's judgement, rather it's that that's > the wrong way to impose the change. I think saying NUL instead of "null" is as archaic as saying CR instead of "carriage return", LF instead of "line feed", NL instead of "new line", etc. I mean, maybe archaicness is not really the issue. IMO, it's just a matter of whether we think using the character's control code symbol is OK instead of the full name. I think the decision should be based on that alone. E.g., would we write: "If this section exists, its contents is a list of entries separated by CR NL, specifying scripts to load. The list is terminated with a NUL character." ? Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-02-13 18:05 ` Pedro Alves @ 2015-02-15 11:53 ` Corinna Vinschen 0 siblings, 0 replies; 19+ messages in thread From: Corinna Vinschen @ 2015-02-15 11:53 UTC (permalink / raw) To: gdb-patches [-- Attachment #1: Type: text/plain, Size: 1572 bytes --] On Feb 13 18:05, Pedro Alves wrote: > On 01/20/2015 04:35 PM, Doug Evans wrote: > > > I for one would liked to have seen the data to back up > > the claim that NUL-terminated is archaic. > > It's not that I don't trust someone's judgement, rather it's that that's > > the wrong way to impose the change. > > I think saying NUL instead of "null" is as archaic as saying CR instead of > "carriage return", LF instead of "line feed", NL instead of "new line", > etc. I mean, maybe archaicness is not really the issue. > > IMO, it's just a matter of whether we think using the character's > control code symbol is OK instead of the full name. I think the > decision should be based on that alone. > > E.g., would we write: > > "If this section exists, its contents is a list of entries separated > by CR NL, specifying scripts to load. The list is terminated with > a NUL character." Sure, except for s/NL/LF/g. What I don't grok here either is the usage of the word "archaic" in terms of a well-known, well-established, documented, and, above all, *standardised*(*) set of abreviations of characters with a certain meaning. NUL is the character with the value \0. Why is that suddenly a problem? Aren't developers the target group of the GDB documentation? Isn't ASCII developer 101? Corinna (*) https://tools.ietf.org/html/rfc20 https://mailarchive.ietf.org/arch/msg/ietf-announce/KIbuNLhChScLC2JBTmFOjj8fT78 http://www.rfc-editor.org/std/std-index.txt -- Corinna Vinschen Cygwin Maintainer Red Hat [-- Attachment #2: Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-01-18 20:48 ` Doug Evans 2015-01-19 14:49 ` Joel Brobecker @ 2015-01-19 16:05 ` Eli Zaretskii 1 sibling, 0 replies; 19+ messages in thread From: Eli Zaretskii @ 2015-01-19 16:05 UTC (permalink / raw) To: Doug Evans; +Cc: gdb-patches > Date: Sun, 18 Jan 2015 12:47:55 -0800 > From: Doug Evans <xdje42@gmail.com> > Cc: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org> > > I'm guessing no one else is interested in the discussion, > which is not unreasonable :-), so where we go is > I write "null-terminated" and get it written down so > that I can remember it. Yes, let's do that, please. TIA. (I don't see a good reason to continue arguing about the rest of the points, as doing that evidently doesn't bring us closer to a resolution.) ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Add support for embedding scripts in .debug_gdb_scripts. 2015-01-15 17:32 [PATCH] Add support for embedding scripts in .debug_gdb_scripts Doug Evans 2015-01-15 18:11 ` Eli Zaretskii @ 2015-01-31 23:31 ` Doug Evans 1 sibling, 0 replies; 19+ messages in thread From: Doug Evans @ 2015-01-31 23:31 UTC (permalink / raw) To: gdb-patches, binutils; +Cc: eliz, brobecker Doug Evans <xdje42@gmail.com> writes: > Hi. This is a feature I've been planning to add for awhile. > There's note of it in the current gdb/section-scripts.h. > > It extends .debug_gdb_scripts to allow including the script in > the section, whereas the current support just allows including > a file to be loaded. > > One use-case I have for this is supporting static linking > where there is no shared-library.so to attach a -gdb.py file to. > > Regression tested on amd64-linux. Here is what I committed. 2015-01-31 Doug Evans <xdje42@gmail.com> Add support for inlining scripts into .debug_gdb_scripts. include/gdb/ * section-scripts.h: Remove "future extension" comment. (SECTION_SCRIPT_ID_PYTHON_TEXT): New macro. (SECTION_SCRIPT_ID_SCHEME_TEXT): New macro. gdb/ * NEWS: Mention inlined scripts in .debug_gdb_scripts section. * auto-load.c: #include ctype.h. (struct auto_load_pspace_info): Replace member loaded_scripts with new members loaded_script_files, loaded_script_texts. (auto_load_pspace_data_cleanup): Update. (init_loaded_scripts_info): Update. (get_auto_load_pspace_data_for_loading): Update. (maybe_add_script_file): Renamed from maybe_add_script. All callers updated. (maybe_add_script_text): New function. (clear_section_scripts): Update. (source_script_file, execute_script_contents): New functions. (source_section_scripts): Add support for SECTION_SCRIPT_ID_PYTHON_TEXT, SECTION_SCRIPT_ID_GUILE_TEXT. (print_scripts): New function. (auto_load_info_scripts): Also print inlined scripts. (maybe_print_unsupported_script_warning): Renamed from unsupported_script_warning_print. All callers updated. (maybe_print_script_not_found_warning): Renamed from script_not_found_warning_print. All callers updated. * extension-priv.h (struct extension_language_script_ops): New member objfile_script_executor. * extension.c (ext_lang_objfile_script_executor): New function. * extension.h (objfile_script_executor_func): New typedef. (ext_lang_objfile_script_executor): Declare. * guile/guile-internal.h (gdbscm_execute_objfile_script): Declare. * guile/guile.c (guile_extension_script_ops): Update. * guile/scm-objfile.c (gdbscm_execute_objfile_script): New function. * python/python.c (python_extension_script_ops): Update. (gdbpy_execute_objfile_script): New function. doc/ * gdb.texinfo (dotdebug_gdb_scripts section): Update docs to distinguish script files vs inlined scripts. * python.texi (Python Auto-loading): Ditto. testsuite/ * gdb.guile/scm-section-script.c: Add duplicate inlined section script entries. Duplicate file section script entries. * gdb.guile/scm-section-script.exp: Add tests for duplicate entries, inlined entries. Add test for safe-path rejection. * gdb.python/py-section-script.c: Add duplicate inlined section script entries. Duplicate file section script entries. * gdb.python/py-section-script.exp: Add tests for duplicate entries, inlined entries. Add test for safe-path rejection. diff --git a/gdb/NEWS b/gdb/NEWS index 2fca5f2..dd3da09 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -18,6 +18,11 @@ * The command 'thread apply all' can now support new option '-ascending' to call its specified command for all threads in ascending order. +* Python/Guile scripting + + ** GDB now supports auto-loading of Python/Guile scripts contained in the + special section named `.debug_gdb_scripts'. + *** Changes in GDB 7.9 * GDB now supports hardware watchpoints on x86 GNU Hurd. diff --git a/gdb/auto-load.c b/gdb/auto-load.c index c152778..778eeb6 100644 --- a/gdb/auto-load.c +++ b/gdb/auto-load.c @@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "defs.h" +#include <ctype.h> #include "auto-load.h" #include "progspace.h" #include "gdb_regex.h" @@ -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; @@ -541,8 +543,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. */ @@ -553,7 +557,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 { @@ -561,7 +565,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. */ @@ -578,8 +582,10 @@ auto_load_pspace_data_cleanup (struct program_space *pspace, void *arg) { struct auto_load_pspace_info *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); } @@ -632,10 +638,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; @@ -650,23 +660,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; @@ -677,7 +688,7 @@ 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; @@ -703,6 +714,44 @@ 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 = 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 @@ -712,10 +761,12 @@ clear_section_scripts (void) struct auto_load_pspace_info *info; info = program_space_data (pspace, auto_load_pspace_data); - if (info != NULL && info->loaded_scripts != NULL) + 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; } @@ -803,7 +854,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. @@ -864,17 +916,183 @@ auto_load_objfile_script (struct objfile *objfile, do_cleanups (cleanups); } +/* 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) +{ + FILE *stream; + char *full_path; + int opened, in_hash_table; + struct cleanup *cleanups; + 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; + } + + opened = find_and_open_script (file, 1 /*search_path*/, + &stream, &full_path); + + cleanups = 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. */ + + maybe_print_script_not_found_warning (pspace_info, objfile, language, + section_name, offset); + } + + in_hash_table = maybe_add_script_file (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 (cleanups); +} + +/* 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, *end; + 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); +} + /* Load scripts specified in OBJFILE. START,END delimit a buffer containing a list of nul-terminated 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, @@ -887,20 +1105,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: @@ -909,105 +1126,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); } } @@ -1146,6 +1295,23 @@ 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 (VEC (loaded_script_ptr) *scripts) +{ + struct ui_out *uiout = current_uiout; + 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); +} + /* 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. */ @@ -1157,7 +1323,7 @@ auto_load_info_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; + VEC (loaded_script_ptr) *script_files, *script_texts; int nr_scripts; dont_repeat (); @@ -1180,25 +1346,38 @@ 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); + script_files = VEC_alloc (loaded_script_ptr, 10); + script_texts = VEC_alloc (loaded_script_ptr, 10); + script_chain = make_cleanup (VEC_cleanup (loaded_script_ptr), &script_files); + make_cleanup (VEC_cleanup (loaded_script_ptr), &script_texts); + + if (pspace_info != NULL && pspace_info->loaded_script_files != NULL) + { + struct 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); + } - 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 }; + struct 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); } - nr_scripts = VEC_length (loaded_script_ptr, scripts); + nr_scripts = (VEC_length (loaded_script_ptr, script_files) + + VEC_length (loaded_script_ptr, script_texts)); /* 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"); + /* Note: This creates a cleanup to output the table end marker. */ make_cleanup_ui_out_table_begin_end (uiout, 2, nr_scripts, "AutoLoadedScriptsTable"); @@ -1206,18 +1385,10 @@ auto_load_info_scripts (char *pattern, int from_tty, 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); - } + print_scripts (script_files); + print_scripts (script_texts); + /* Finish up the table before checking for no matching scripts. */ do_cleanups (script_chain); if (nr_scripts == 0) @@ -1253,32 +1424,48 @@ 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. */ diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 2e58a53..61a317c 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -23977,17 +23977,29 @@ is evaluated more than once. For systems using file formats like ELF and COFF, when @value{GDBN} loads a new object file it will look for a special section named @code{.debug_gdb_scripts}. -If this section exists, its contents is a list of NUL-terminated names -of scripts to load. Each entry begins with a non-NULL prefix byte that -specifies the kind of entry, typically the extension language. +If this section exists, its contents is a list of null-terminated entries +specifying scripts to load. Each entry begins with a non-null prefix byte that +specifies the kind of entry, typically the extension language and whether the +script is in a file or inlined in @code{.debug_gdb_scripts}. -@value{GDBN} will look for each specified script file first in the -current directory and then along the source search path +The following entries are supported: + +@table @code +@item SECTION_SCRIPT_ID_PYTHON_FILE = 1 +@item SECTION_SCRIPT_ID_SCHEME_FILE = 3 +@item SECTION_SCRIPT_ID_PYTHON_TEXT = 4 +@item SECTION_SCRIPT_ID_SCHEME_TEXT = 6 +@end table + +@subsubsection Script File Entries + +If the entry specifies a file, @value{GDBN} will look for the file first +in the current directory and then along the source search path (@pxref{Source Path, ,Specifying Source Directories}), except that @file{$cdir} is not searched, since the compilation directory is not relevant to scripts. -Entries can be placed in section @code{.debug_gdb_scripts} with, +File entries can be placed in section @code{.debug_gdb_scripts} with, for example, this GCC macro for Python scripts. @example @@ -24019,6 +24031,45 @@ using this header will get a reference to the specified script, and with the use of @code{"MS"} attributes on the section, the linker will remove duplicates. +@subsubsection Script Text Entries + +Script text entries allow to put the executable script in the entry +itself instead of loading it from a file. +The first line of the entry, everything after the prefix byte and up to +the first newline (@code{0xa}) character, is the script name, and must not +contain any kind of space character, e.g., spaces or tabs. +The rest of the entry, up to the trailing null byte, is the script to +execute in the specified language. The name needs to be unique among +all script names, as @value{GDBN} executes each script only once based +on its name. + +Here is an example from file @file{py-section-script.c} in the @value{GDBN} +testsuite. + +@example +#include "symcat.h" +#include "gdb/section-scripts.h" +asm( +".pushsection \".debug_gdb_scripts\", \"MS\",@@progbits,1\n" +".byte " XSTRING (SECTION_SCRIPT_ID_PYTHON_TEXT) "\n" +".ascii \"gdb.inlined-script\\n\"\n" +".ascii \"class test_cmd (gdb.Command):\\n\"\n" +".ascii \" def __init__ (self):\\n\"\n" +".ascii \" super (test_cmd, self).__init__ (" + "\\\"test-cmd\\\", gdb.COMMAND_OBSCURE)\\n\"\n" +".ascii \" def invoke (self, arg, from_tty):\\n\"\n" +".ascii \" print (\\\"test-cmd output, arg = %s\\\" % arg)\\n\"\n" +".ascii \"test_cmd ()\\n\"\n" +".byte 0\n" +".popsection\n" +); +@end example + +Loading of inlined scripts requires a properly configured +@code{auto-load safe-path} (@pxref{Auto-loading safe path}). +The path to specify in @code{auto-load safe-path} is the path of the file +containing the @code{.debug_gdb_scripts} section. + @node Which flavor to choose? @subsection Which flavor to choose? diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index 7c04af7..d725eb0 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -4754,8 +4754,9 @@ Show whether auto-loading of Python scripts is enabled or disabled. Print the list of all Python scripts that @value{GDBN} auto-loaded. Also printed is the list of Python scripts that were mentioned in -the @code{.debug_gdb_scripts} section and were not found -(@pxref{dotdebug_gdb_scripts section}). +the @code{.debug_gdb_scripts} section and were either not found +(@pxref{dotdebug_gdb_scripts section}) or were not auto-loaded due to +@code{auto-load safe-path} rejection (@pxref{Auto-loading}). This is useful because their names are not printed when @value{GDBN} tries to load them and fails. There may be many of them, and printing an error message for each one is problematic. @@ -4773,7 +4774,7 @@ No my-foo-pretty-printers.py @end smallexample @end table -When reading an auto-loaded file, @value{GDBN} sets the +When reading an auto-loaded file or script, @value{GDBN} sets the @dfn{current objfile}. This is available via the @code{gdb.current_objfile} function (@pxref{Objfiles In Python}). This can be useful for registering objfile-specific pretty-printers and frame-filters. diff --git a/gdb/extension-priv.h b/gdb/extension-priv.h index fc05137..dd2600e 100644 --- a/gdb/extension-priv.h +++ b/gdb/extension-priv.h @@ -103,6 +103,11 @@ struct extension_language_script_ops but is not required to, throw an error. */ objfile_script_sourcer_func *objfile_script_sourcer; + /* Execute a script attached to an objfile. + If there's an error while processing the script this function may, + but is not required to, throw an error. */ + objfile_script_executor_func *objfile_script_executor; + /* Return non-zero if auto-loading scripts in this extension language is enabled. */ int (*auto_load_enabled) (const struct extension_language_defn *); diff --git a/gdb/extension.c b/gdb/extension.c index 853ef67..77b62e0 100644 --- a/gdb/extension.c +++ b/gdb/extension.c @@ -61,6 +61,7 @@ static const struct extension_language_script_ops { source_gdb_script, source_gdb_objfile_script, + NULL, /* objfile_script_executor */ auto_load_gdb_scripts_enabled }; @@ -286,6 +287,21 @@ ext_lang_objfile_script_sourcer (const struct extension_language_defn *extlang) return extlang->script_ops->objfile_script_sourcer; } +/* Return the objfile script "executor" function for EXTLANG. + This is the function that executes a script for a particular objfile. + If support for this language isn't compiled in, NULL is returned. + The extension language is not required to implement this function. */ + +objfile_script_executor_func * +ext_lang_objfile_script_executor + (const struct extension_language_defn *extlang) +{ + if (extlang->script_ops == NULL) + return NULL; + + return extlang->script_ops->objfile_script_executor; +} + /* Return non-zero if auto-loading of EXTLANG scripts is enabled. Zero is returned if support for this language isn't compiled in. */ diff --git a/gdb/extension.h b/gdb/extension.h index a53f0a7..e8d7478 100644 --- a/gdb/extension.h +++ b/gdb/extension.h @@ -48,6 +48,12 @@ typedef void objfile_script_sourcer_func (const struct extension_language_defn *, struct objfile *, FILE *stream, const char *filename); +/* A function to execute a script for an objfile. + Any exceptions are not caught, and are passed to the caller. */ +typedef void objfile_script_executor_func + (const struct extension_language_defn *, + struct objfile *, const char *name, const char *script); + /* Enum of each extension(/scripting) language. */ enum extension_language @@ -197,6 +203,9 @@ extern script_sourcer_func *ext_lang_script_sourcer extern objfile_script_sourcer_func *ext_lang_objfile_script_sourcer (const struct extension_language_defn *); +extern objfile_script_executor_func *ext_lang_objfile_script_executor + (const struct extension_language_defn *); + extern int ext_lang_auto_load_enabled (const struct extension_language_defn *); /* Wrappers for each extension language API function that iterate over all diff --git a/gdb/guile/guile-internal.h b/gdb/guile/guile-internal.h index 968b4d3..9a8ef68 100644 --- a/gdb/guile/guile-internal.h +++ b/gdb/guile/guile-internal.h @@ -549,6 +549,7 @@ extern struct value *vlscm_convert_value_from_scheme /* stript_lang methods */ extern objfile_script_sourcer_func gdbscm_source_objfile_script; +extern objfile_script_executor_func gdbscm_execute_objfile_script; extern int gdbscm_auto_load_enabled (const struct extension_language_defn *); diff --git a/gdb/guile/guile.c b/gdb/guile/guile.c index c434ec0..319b583 100644 --- a/gdb/guile/guile.c +++ b/gdb/guile/guile.c @@ -128,6 +128,7 @@ static const struct extension_language_script_ops guile_extension_script_ops = { gdbscm_source_script, gdbscm_source_objfile_script, + gdbscm_execute_objfile_script, gdbscm_auto_load_enabled }; diff --git a/gdb/guile/scm-objfile.c b/gdb/guile/scm-objfile.c index 8162d01..8e94b96 100644 --- a/gdb/guile/scm-objfile.c +++ b/gdb/guile/scm-objfile.c @@ -283,7 +283,8 @@ gdbscm_set_objfile_pretty_printers_x (SCM self, SCM printers) \f /* The "current" objfile. This is set when gdb detects that a new objfile has been loaded. It is only set for the duration of a call to - gdbscm_source_objfile_script; it is NULL at other times. */ + gdbscm_source_objfile_script and gdbscm_execute_objfile_script; it is NULL + at other times. */ static struct objfile *ofscm_current_objfile; /* Set the current objfile to OBJFILE and then read FILE named FILENAME @@ -311,6 +312,31 @@ gdbscm_source_objfile_script (const struct extension_language_defn *extlang, ofscm_current_objfile = NULL; } +/* Set the current objfile to OBJFILE and then read FILE named FILENAME + as Guile code. This does not throw any errors. If an exception + occurs Guile will print the backtrace. + This is the extension_language_script_ops.objfile_script_sourcer + "method". */ + +void +gdbscm_execute_objfile_script (const struct extension_language_defn *extlang, + struct objfile *objfile, const char *name, + const char *script) +{ + char *msg; + + ofscm_current_objfile = objfile; + + msg = gdbscm_safe_eval_string (script, 0 /* display_result */); + if (msg != NULL) + { + fprintf_filtered (gdb_stderr, "%s", msg); + xfree (msg); + } + + ofscm_current_objfile = NULL; +} + /* (current-objfile) -> <gdb:obfjile> Return the current objfile, or #f if there isn't one. Ideally this would be named ofscm_current_objfile, but that name is diff --git a/gdb/python/python.c b/gdb/python/python.c index f4b8fcf..344d8d2 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -131,6 +131,7 @@ PyObject *gdbpy_gdb_memory_error; static script_sourcer_func gdbpy_source_script; static objfile_script_sourcer_func gdbpy_source_objfile_script; +static objfile_script_executor_func gdbpy_execute_objfile_script; static void gdbpy_finish_initialization (const struct extension_language_defn *); static int gdbpy_initialized (const struct extension_language_defn *); @@ -155,6 +156,7 @@ static const struct extension_language_script_ops python_extension_script_ops = { gdbpy_source_script, gdbpy_source_objfile_script, + gdbpy_execute_objfile_script, gdbpy_auto_load_enabled }; @@ -1262,7 +1264,8 @@ gdbpy_progspaces (PyObject *unused1, PyObject *unused2) /* The "current" objfile. This is set when gdb detects that a new objfile has been loaded. It is only set for the duration of a call to - gdbpy_source_objfile_script; it is NULL at other times. */ + gdbpy_source_objfile_script and gdbpy_execute_objfile_script; it is NULL + at other times. */ static struct objfile *gdbpy_current_objfile; /* Set the current objfile to OBJFILE and then read FILE named FILENAME @@ -1290,6 +1293,31 @@ gdbpy_source_objfile_script (const struct extension_language_defn *extlang, gdbpy_current_objfile = NULL; } +/* Set the current objfile to OBJFILE and then execute SCRIPT + as Python code. This does not throw any errors. If an exception + occurs python will print the traceback and clear the error indicator. + This is the extension_language_script_ops.objfile_script_executor + "method". */ + +static void +gdbpy_execute_objfile_script (const struct extension_language_defn *extlang, + struct objfile *objfile, const char *name, + const char *script) +{ + struct cleanup *cleanups; + + if (!gdb_python_initialized) + return; + + cleanups = ensure_python_env (get_objfile_arch (objfile), current_language); + gdbpy_current_objfile = objfile; + + PyRun_SimpleString (script); + + do_cleanups (cleanups); + gdbpy_current_objfile = NULL; +} + /* Return the current Objfile, or None if there isn't one. */ static PyObject * diff --git a/gdb/testsuite/gdb.guile/scm-section-script.c b/gdb/testsuite/gdb.guile/scm-section-script.c index e668a49..cbff698 100644 --- a/gdb/testsuite/gdb.guile/scm-section-script.c +++ b/gdb/testsuite/gdb.guile/scm-section-script.c @@ -19,18 +19,52 @@ #include "gdb/section-scripts.h" /* Put the path to the pretty-printer script in .debug_gdb_scripts so - gdb will automagically loaded it. */ + gdb will automagically loaded it. + Normally "MS" would appear here, as in + .pushsection ".debug_gdb_scripts", "MS",@progbits,1 + but we remove it to test files appearing twice in the section. */ #define DEFINE_GDB_SCRIPT(script_name) \ asm("\ -.pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n\ +.pushsection \".debug_gdb_scripts\", \"S\",@progbits\n\ .byte " XSTRING (SECTION_SCRIPT_ID_SCHEME_FILE) "\n\ .asciz \"" script_name "\"\n\ .popsection \n\ "); +#ifndef SCRIPT_FILE +#error "SCRIPT_FILE not defined" +#endif + +/* Specify it twice to verify the file is only loaded once. */ +DEFINE_GDB_SCRIPT (SCRIPT_FILE) DEFINE_GDB_SCRIPT (SCRIPT_FILE) +/* Inlined scripts are harder to create in the same way as + DEFINE_GDB_SCRIPT_FILE. Keep things simple and just define it here. + Normally "MS" would appear here, as in + .pushsection ".debug_gdb_scripts", "MS",@progbits,1 + but we remove it to test scripts appearing twice in the section. */ + +#define DEFINE_GDB_SCRIPT_TEXT \ +asm( \ +".pushsection \".debug_gdb_scripts\", \"S\",@progbits\n" \ +".byte " XSTRING (SECTION_SCRIPT_ID_SCHEME_TEXT) "\n" \ +".ascii \"gdb.inlined-script\\n\"\n" \ +".ascii \"(define test-cmd\\n\"\n" \ +".ascii \" (make-command \\\"test-cmd\\\"\\n\"\n" \ +".ascii \" #:command-class COMMAND_OBSCURE\\n\"\n" \ +".ascii \" #:invoke (lambda (self arg from-tty)\\n\"\n" \ +".ascii \" (display (format #f \\\"test-cmd output, arg = ~a\\n\\\" arg)))))\\n\"\n" \ +".ascii \"(register-command! test-cmd)\\n\"\n" \ +".byte 0\n" \ +".popsection\n" \ +); + +/* Specify it twice to verify the script is only executed once. */ +DEFINE_GDB_SCRIPT_TEXT +DEFINE_GDB_SCRIPT_TEXT + struct ss { int a; diff --git a/gdb/testsuite/gdb.guile/scm-section-script.exp b/gdb/testsuite/gdb.guile/scm-section-script.exp index 93a10a0..8c04ac8 100644 --- a/gdb/testsuite/gdb.guile/scm-section-script.exp +++ b/gdb/testsuite/gdb.guile/scm-section-script.exp @@ -53,14 +53,51 @@ gdb_start if { [skip_guile_tests] } { continue } gdb_reinitialize_dir $srcdir/$subdir -gdb_test_no_output "set auto-load safe-path ${remote_guile_file}" \ + +# Try first with a restrictive safe-path. + +gdb_test_no_output "set auto-load safe-path /restricted" \ + "set restricted auto-load safe-path" +gdb_load ${binfile} + +# Verify gdb did not load the scripts. +set test_name "verify scripts not loaded" +gdb_test_multiple "info auto-load guile-scripts" "$test_name" { + -re "Yes.*${testfile}.scm.*Yes.*inlined-script.*$gdb_prompt $" { + fail "$test_name" + } + -re "No.*${testfile}.scm.*No.*inlined-script.*$gdb_prompt $" { + pass "$test_name" + } +} + +# Try again with a working safe-path. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +gdb_test_no_output "set auto-load safe-path ${remote_guile_file}:${binfile}" \ "set auto-load safe-path" gdb_load ${binfile} -# Verify gdb loaded the script. -gdb_test "info auto-load guile-scripts" "Yes.*${testfile}.scm.*" +# Verify gdb loaded each script and they appear once in the list. +set test_name "verify scripts loaded" +gdb_test_multiple "info auto-load guile-scripts" "$test_name" { + -re "${testfile}.scm.*${testfile}.scm.*$gdb_prompt $" { + fail "$test_name" + } + -re "inlined-script.*inlined-script.*$gdb_prompt $" { + fail "$test_name" + } + -re "Yes.*${testfile}.scm.*Yes.*inlined-script.*$gdb_prompt $" { + pass "$test_name" + } +} + # Again, with a regexp this time. gdb_test "info auto-load guile-scripts ${testfile}" "Yes.*${testfile}.scm.*" + # Again, with a regexp that matches no scripts. gdb_test "info auto-load guile-scripts no-script-matches-this" \ "No auto-load scripts matching no-script-matches-this." @@ -74,3 +111,5 @@ gdb_test "b [gdb_get_line_number {break to inspect} ${testfile}.c ]" \ gdb_test "continue" ".*Breakpoint.*" gdb_test "print ss" " = a=<1> b=<2>" + +gdb_test "test-cmd 1 2 3" "test-cmd output, arg = 1 2 3" diff --git a/gdb/testsuite/gdb.python/py-section-script.c b/gdb/testsuite/gdb.python/py-section-script.c index 2cb606b..53af8cb 100644 --- a/gdb/testsuite/gdb.python/py-section-script.c +++ b/gdb/testsuite/gdb.python/py-section-script.c @@ -15,18 +15,55 @@ 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 "symcat.h" +#include "gdb/section-scripts.h" + /* Put the path to the pretty-printer script in .debug_gdb_scripts so - gdb will automagically loaded it. */ + gdb will automagically loaded it. + Normally "MS" would appear here, as in + .pushsection ".debug_gdb_scripts", "MS",@progbits,1 + but we remove it to test files appearing twice in the section. */ -#define DEFINE_GDB_SCRIPT(script_name) \ +#define DEFINE_GDB_SCRIPT_FILE(script_name) \ asm("\ -.pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n\ -.byte 1\n\ +.pushsection \".debug_gdb_scripts\", \"S\",@progbits\n\ +.byte " XSTRING (SECTION_SCRIPT_ID_PYTHON_FILE) "\n\ .asciz \"" script_name "\"\n\ -.popsection \n\ +.popsection\n\ "); -DEFINE_GDB_SCRIPT (SCRIPT_FILE) +#ifndef SCRIPT_FILE +#error "SCRIPT_FILE not defined" +#endif + +/* Specify it twice to verify the file is only loaded once. */ +DEFINE_GDB_SCRIPT_FILE (SCRIPT_FILE) +DEFINE_GDB_SCRIPT_FILE (SCRIPT_FILE) + +/* Inlined scripts are harder to create in the same way as + DEFINE_GDB_SCRIPT_FILE. Keep things simple and just define it here. + Normally "MS" would appear here, as in + .pushsection ".debug_gdb_scripts", "MS",@progbits,1 + but we remove it to test scripts appearing twice in the section. */ + +#define DEFINE_GDB_SCRIPT_TEXT \ +asm( \ +".pushsection \".debug_gdb_scripts\", \"S\",@progbits\n" \ +".byte " XSTRING (SECTION_SCRIPT_ID_PYTHON_TEXT) "\n" \ +".ascii \"gdb.inlined-script\\n\"\n" \ +".ascii \"class test_cmd (gdb.Command):\\n\"\n" \ +".ascii \" def __init__ (self):\\n\"\n" \ +".ascii \" super (test_cmd, self).__init__ (\\\"test-cmd\\\", gdb.COMMAND_OBSCURE)\\n\"\n" \ +".ascii \" def invoke (self, arg, from_tty):\\n\"\n" \ +".ascii \" print (\\\"test-cmd output, arg = %s\\\" % arg)\\n\"\n" \ +".ascii \"test_cmd ()\\n\"\n" \ +".byte 0\n" \ +".popsection\n" \ +); + +/* Specify it twice to verify the script is only executed once. */ +DEFINE_GDB_SCRIPT_TEXT +DEFINE_GDB_SCRIPT_TEXT struct ss { diff --git a/gdb/testsuite/gdb.python/py-section-script.exp b/gdb/testsuite/gdb.python/py-section-script.exp index 11c0453..840430d 100644 --- a/gdb/testsuite/gdb.python/py-section-script.exp +++ b/gdb/testsuite/gdb.python/py-section-script.exp @@ -39,7 +39,9 @@ set remote_python_file [gdb_remote_download host \ set quoted_name "\"$remote_python_file\"" if {[build_executable $testfile.exp $testfile $srcfile \ - [list debug additional_flags=-DSCRIPT_FILE=$quoted_name]] == -1} { + [list debug \ + additional_flags=-I${srcdir}/../../include \ + additional_flags=-DSCRIPT_FILE=$quoted_name]] == -1} { return -1 } @@ -51,13 +53,51 @@ gdb_start if { [skip_python_tests] } { continue } gdb_reinitialize_dir $srcdir/$subdir -gdb_test_no_output "set auto-load safe-path ${remote_python_file}" "set auto-load safe-path" + +# Try first with a restrictive safe-path. + +gdb_test_no_output "set auto-load safe-path /restricted" \ + "set restricted auto-load safe-path" gdb_load ${binfile} -# Verify gdb loaded the script. -gdb_test "info auto-load python-scripts" "Yes.*${testfile}.py.*" +# Verify gdb did not load the scripts. +set test_name "verify scripts not loaded" +gdb_test_multiple "info auto-load python-scripts" "$test_name" { + -re "Yes.*${testfile}.py.*Yes.*inlined-script.*$gdb_prompt $" { + fail "$test_name" + } + -re "No.*${testfile}.py.*No.*inlined-script.*$gdb_prompt $" { + pass "$test_name" + } +} + +# Try again with a working safe-path. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +gdb_test_no_output "set auto-load safe-path ${remote_python_file}:${binfile}" \ + "set auto-load safe-path" +gdb_load ${binfile} + +# Verify gdb loaded each script and they appear once in the list. +set test_name "verify scripts loaded" +gdb_test_multiple "info auto-load python-scripts" "$test_name" { + -re "${testfile}.py.*${testfile}.py.*$gdb_prompt $" { + fail "$test_name" + } + -re "inlined-script.*inlined-script.*$gdb_prompt $" { + fail "$test_name" + } + -re "Yes.*${testfile}.py.*Yes.*inlined-script.*$gdb_prompt $" { + pass "$test_name" + } +} + # Again, with a regexp this time. gdb_test "info auto-load python-scripts ${testfile}" "Yes.*${testfile}.py.*" + # Again, with a regexp that matches no scripts. gdb_test "info auto-load python-scripts no-script-matches-this" \ "No auto-load scripts matching no-script-matches-this." @@ -72,3 +112,5 @@ gdb_test "b [gdb_get_line_number {break to inspect} ${testfile}.c ]" \ gdb_test "continue" ".*Breakpoint.*" gdb_test "print ss" " = a=<1> b=<2>" + +gdb_test "test-cmd 1 2 3" "test-cmd output, arg = 1 2 3" diff --git a/include/gdb/section-scripts.h b/include/gdb/section-scripts.h index c4b7a1c..effce62 100644 --- a/include/gdb/section-scripts.h +++ b/include/gdb/section-scripts.h @@ -28,8 +28,6 @@ Other unused values needn't specify different scripting languages, but we have no need for anything else at the moment. - Future extension: Include the contents of the script in the section. - These values are defined as macros so that they can be used in embedded asms and assembler source files. */ @@ -47,4 +45,18 @@ file. */ #define SECTION_SCRIPT_ID_SCHEME_FILE 3 +/* The record is a nul-terminated string. + The first line is the name of the script. + Subsequent lines are interpreted as a python script. */ +#define SECTION_SCRIPT_ID_PYTHON_TEXT 4 + +/* Native GDB scripts are not currently supported in .debug_gdb_scripts, + but we reserve a value for it. */ +/*#define SECTION_SCRIPT_ID_GDB_TEXT 5*/ + +/* The record is a nul-terminated string. + The first line is the name of the script. + Subsequent lines are interpreted as a guile(scheme) script. */ +#define SECTION_SCRIPT_ID_SCHEME_TEXT 6 + #endif /* GDB_SECTION_SCRIPTS_H */ ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2015-02-15 11:53 UTC | newest] Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2015-01-15 17:32 [PATCH] Add support for embedding scripts in .debug_gdb_scripts Doug Evans 2015-01-15 18:11 ` Eli Zaretskii 2015-01-16 17:15 ` Doug Evans 2015-01-16 18:02 ` Eli Zaretskii 2015-01-17 1:16 ` Doug Evans 2015-01-17 8:16 ` Eli Zaretskii 2015-01-18 4:16 ` Doug Evans 2015-01-18 16:23 ` Eli Zaretskii 2015-01-18 20:48 ` Doug Evans 2015-01-19 14:49 ` Joel Brobecker 2015-01-20 16:35 ` Doug Evans 2015-01-21 9:57 ` Joel Brobecker 2015-02-13 16:15 ` Stan Shebs 2015-02-13 16:45 ` Eli Zaretskii 2015-02-13 16:46 ` Andreas Schwab 2015-02-13 18:05 ` Pedro Alves 2015-02-15 11:53 ` Corinna Vinschen 2015-01-19 16:05 ` Eli Zaretskii 2015-01-31 23:31 ` Doug Evans
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).