X-Git-Url: https://repo.jachan.dev/binutils.git/blobdiff_plain/590042fc45f857c981bee4e0c76f6b3b528a224e..HEAD:/gdb/source.c diff --git a/gdb/source.c b/gdb/source.c index b27f210802..d0f2d1c763 100644 --- a/gdb/source.c +++ b/gdb/source.c @@ -1,5 +1,5 @@ /* List lines of source files for GDB, the GNU debugger. - Copyright (C) 1986-2019 Free Software Foundation, Inc. + Copyright (C) 1986-2022 Free Software Foundation, Inc. This file is part of GDB. @@ -31,7 +31,7 @@ #include #include #include "gdbcore.h" -#include "gdb_regex.h" +#include "gdbsupport/gdb_regex.h" #include "symfile.h" #include "objfiles.h" #include "annotate.h" @@ -40,12 +40,17 @@ #include "filenames.h" /* for DOSish file names */ #include "completer.h" #include "ui-out.h" -#include "readline/readline.h" +#include "readline/tilde.h" #include "gdbsupport/enum-flags.h" #include "gdbsupport/scoped_fd.h" #include #include "gdbsupport/pathstuff.h" #include "source-cache.h" +#include "cli/cli-style.h" +#include "observable.h" +#include "build-id.h" +#include "debuginfod-support.h" +#include "gdbsupport/buildargv.h" #define OPEN_MODE (O_RDONLY | O_BINARY) #define FDOPEN_MODE FOPEN_RB @@ -53,28 +58,65 @@ /* Path of directories to search for source files. Same format as the PATH environment variable's value. */ -char *source_path; +std::string source_path; /* Support for source path substitution commands. */ struct substitute_path_rule { - char *from; - char *to; - struct substitute_path_rule *next; + substitute_path_rule (const char *from_, const char *to_) + : from (from_), + to (to_) + { + } + + std::string from; + std::string to; }; -static struct substitute_path_rule *substitute_path_rules = NULL; +static std::list substitute_path_rules; -/* Symtab of default file for listing lines of. */ +/* An instance of this is attached to each program space. */ -static struct symtab *current_source_symtab; +struct current_source_location +{ +public: + + current_source_location () = default; + + /* Set the value. */ + void set (struct symtab *s, int l) + { + m_symtab = s; + m_line = l; + gdb::observers::current_source_symtab_and_line_changed.notify (); + } + + /* Get the symtab. */ + struct symtab *symtab () const + { + return m_symtab; + } + + /* Get the line number. */ + int line () const + { + return m_line; + } -/* Default next line to list. */ +private: -static int current_source_line; + /* Symtab of default file for listing lines of. */ -static struct program_space *current_source_pspace; + struct symtab *m_symtab = nullptr; + + /* Default next line to list. */ + + int m_line = 0; +}; + +static const registry::key + current_source_key; /* Default number of lines to print with commands like "list". This is based on guessing how many long (i.e. more than chars_per_line @@ -87,10 +129,10 @@ static void show_lines_to_list (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, - _("Number of source lines gdb " - "will list by default is %s.\n"), - value); + gdb_printf (file, + _("Number of source lines gdb " + "will list by default is %s.\n"), + value); } /* Possible values of 'set filename-display'. */ @@ -111,9 +153,23 @@ static void show_filename_display_string (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("Filenames are displayed as \"%s\".\n"), value); + gdb_printf (file, _("Filenames are displayed as \"%s\".\n"), value); } - + +/* When true GDB will stat and open source files as required, but when + false, GDB will avoid accessing source files as much as possible. */ + +static bool source_open = true; + +/* Implement 'show source open'. */ + +static void +show_source_open (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + gdb_printf (file, _("Source opening is \"%s\".\n"), value); +} + /* Line number of last line printed. Default for various commands. current_source_line is usually, but not always, the same as this. */ @@ -162,6 +218,19 @@ get_lines_to_list (void) return lines_to_list; } +/* A helper to return the current source location object for PSPACE, + creating it if it does not exist. */ + +static current_source_location * +get_source_location (program_space *pspace) +{ + current_source_location *loc + = current_source_key.get (pspace); + if (loc == nullptr) + loc = current_source_key.emplace (pspace); + return loc; +} + /* Return the current source file for listing and next line to list. NOTE: The returned sal pc and end fields are not valid. */ @@ -169,10 +238,11 @@ struct symtab_and_line get_current_source_symtab_and_line (void) { symtab_and_line cursal; + current_source_location *loc = get_source_location (current_program_space); - cursal.pspace = current_source_pspace; - cursal.symtab = current_source_symtab; - cursal.line = current_source_line; + cursal.pspace = current_program_space; + cursal.symtab = loc->symtab (); + cursal.line = loc->line (); cursal.pc = 0; cursal.end = 0; @@ -194,7 +264,8 @@ set_default_source_symtab_and_line (void) error (_("No symbol table is loaded. Use the \"file\" command.")); /* Pull in a current source symtab if necessary. */ - if (current_source_symtab == 0) + current_source_location *loc = get_source_location (current_program_space); + if (loc->symtab () == nullptr) select_source_symtab (0); } @@ -208,15 +279,15 @@ set_current_source_symtab_and_line (const symtab_and_line &sal) { symtab_and_line cursal; - cursal.pspace = current_source_pspace; - cursal.symtab = current_source_symtab; - cursal.line = current_source_line; + current_source_location *loc = get_source_location (sal.pspace); + + cursal.pspace = sal.pspace; + cursal.symtab = loc->symtab (); + cursal.line = loc->line (); cursal.pc = 0; cursal.end = 0; - current_source_pspace = sal.pspace; - current_source_symtab = sal.symtab; - current_source_line = sal.line; + loc->set (sal.symtab, sal.line); /* Force the next "list" to center around the current line. */ clear_lines_listed_range (); @@ -229,8 +300,8 @@ set_current_source_symtab_and_line (const symtab_and_line &sal) void clear_current_source_symtab_and_line (void) { - current_source_symtab = 0; - current_source_line = 0; + current_source_location *loc = get_source_location (current_program_space); + loc->set (nullptr, 0); } /* See source.h. */ @@ -240,66 +311,67 @@ select_source_symtab (struct symtab *s) { if (s) { - current_source_symtab = s; - current_source_line = 1; - current_source_pspace = SYMTAB_PSPACE (s); + current_source_location *loc + = get_source_location (s->compunit ()->objfile ()->pspace); + loc->set (s, 1); return; } - if (current_source_symtab) + current_source_location *loc = get_source_location (current_program_space); + if (loc->symtab () != nullptr) return; /* Make the default place to list be the function `main' if one exists. */ - if (lookup_symbol (main_name (), 0, VAR_DOMAIN, 0).symbol) + block_symbol bsym = lookup_symbol (main_name (), 0, VAR_DOMAIN, 0); + if (bsym.symbol != nullptr && bsym.symbol->aclass () == LOC_BLOCK) { - std::vector sals - = decode_line_with_current_source (main_name (), - DECODE_LINE_FUNFIRSTLINE); - const symtab_and_line &sal = sals[0]; - current_source_pspace = sal.pspace; - current_source_symtab = sal.symtab; - current_source_line = std::max (sal.line - (lines_to_list - 1), 1); - if (current_source_symtab) - return; + symtab_and_line sal = find_function_start_sal (bsym.symbol, true); + if (sal.symtab == NULL) + /* We couldn't find the location of `main', possibly due to missing + line number info, fall back to line 1 in the corresponding file. */ + loc->set (bsym.symbol->symtab (), 1); + else + loc->set (sal.symtab, std::max (sal.line - (lines_to_list - 1), 1)); + return; } /* Alright; find the last file in the symtab list (ignoring .h's and namespace symtabs). */ - current_source_line = 1; + struct symtab *new_symtab = nullptr; for (objfile *ofp : current_program_space->objfiles ()) { for (compunit_symtab *cu : ofp->compunits ()) { - for (symtab *symtab : compunit_filetabs (cu)) + for (symtab *symtab : cu->filetabs ()) { const char *name = symtab->filename; int len = strlen (name); if (!(len > 2 && (strcmp (&name[len - 2], ".h") == 0 || strcmp (name, "<>") == 0))) - { - current_source_pspace = current_program_space; - current_source_symtab = symtab; - } + new_symtab = symtab; } } } - if (current_source_symtab) + loc->set (new_symtab, 1); + if (new_symtab != nullptr) return; for (objfile *objfile : current_program_space->objfiles ()) { - if (objfile->sf) - s = objfile->sf->qf->find_last_source_symtab (objfile); + s = objfile->find_last_source_symtab (); if (s) - current_source_symtab = s; + new_symtab = s; + } + if (new_symtab != nullptr) + { + loc->set (new_symtab,1); + return; } - if (current_source_symtab) - return; error (_("Can't find a default source file")); } @@ -314,17 +386,15 @@ set_directories_command (const char *args, { /* This is the value that was set. It needs to be processed to maintain $cdir:$cwd and remove dups. */ - char *set_path = source_path; + std::string set_path = source_path; /* We preserve the invariant that $cdir:$cwd begins life at the end of the list by calling init_source_path. If they appear earlier in SET_PATH then mod_path will move them appropriately. mod_path will also remove duplicates. */ init_source_path (); - if (*set_path != '\0') - mod_path (set_path, &source_path); - - xfree (set_path); + if (!set_path.empty ()) + mod_path (set_path.c_str (), source_path); } /* Print the list of source directories. @@ -332,11 +402,11 @@ set_directories_command (const char *args, function. */ static void -show_directories_1 (char *ignore, int from_tty) +show_directories_1 (ui_file *file, char *ignore, int from_tty) { - puts_filtered ("Source directories searched: "); - puts_filtered (source_path); - puts_filtered ("\n"); + gdb_puts ("Source directories searched: ", file); + gdb_puts (source_path.c_str (), file); + gdb_puts ("\n", file); } /* Handler for "show directories" command. */ @@ -345,7 +415,7 @@ static void show_directories_command (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - show_directories_1 (NULL, from_tty); + show_directories_1 (file, NULL, from_tty); } /* See source.h. */ @@ -355,7 +425,7 @@ forget_cached_source_info_for_objfile (struct objfile *objfile) { for (compunit_symtab *cu : objfile->compunits ()) { - for (symtab *s : compunit_filetabs (cu)) + for (symtab *s : cu->filetabs ()) { if (s->fullname != NULL) { @@ -365,8 +435,7 @@ forget_cached_source_info_for_objfile (struct objfile *objfile) } } - if (objfile->sf) - objfile->sf->qf->forget_cached_source_info (objfile); + objfile->forget_cached_source_info (); } /* See source.h. */ @@ -374,9 +443,7 @@ forget_cached_source_info_for_objfile (struct objfile *objfile) void forget_cached_source_info (void) { - struct program_space *pspace; - - ALL_PSPACES (pspace) + for (struct program_space *pspace : program_spaces) for (objfile *objfile : pspace->objfiles ()) { forget_cached_source_info_for_objfile (objfile); @@ -389,10 +456,7 @@ forget_cached_source_info (void) void init_source_path (void) { - char buf[20]; - - xsnprintf (buf, sizeof (buf), "$cdir%c$cwd", DIRNAME_SEPARATOR); - source_path = xstrdup (buf); + source_path = string_printf ("$cdir%c$cwd", DIRNAME_SEPARATOR); forget_cached_source_info (); } @@ -401,23 +465,30 @@ init_source_path (void) static void directory_command (const char *dirname, int from_tty) { + bool value_changed = false; dont_repeat (); /* FIXME, this goes to "delete dir"... */ if (dirname == 0) { if (!from_tty || query (_("Reinitialize source path to empty? "))) { - xfree (source_path); init_source_path (); + value_changed = true; } } else { - mod_path (dirname, &source_path); + mod_path (dirname, source_path); forget_cached_source_info (); + value_changed = true; + } + if (value_changed) + { + gdb::observers::command_param_changed.notify ("directories", + source_path.c_str ()); + if (from_tty) + show_directories_1 (gdb_stdout, (char *) 0, from_tty); } - if (from_tty) - show_directories_1 ((char *) 0, from_tty); } /* Add a path given with the -d command line switch. @@ -426,13 +497,13 @@ directory_command (const char *dirname, int from_tty) void directory_switch (const char *dirname, int from_tty) { - add_path (dirname, &source_path, 0); + add_path (dirname, source_path, 0); } /* Add zero or more directories to the front of an arbitrary path. */ void -mod_path (const char *dirname, char **which_path) +mod_path (const char *dirname, std::string &which_path) { add_path (dirname, which_path, 1); } @@ -467,21 +538,22 @@ add_path (const char *dirname, char **which_path, int parse_separators) for (const gdb::unique_xmalloc_ptr &name_up : dir_vec) { - char *name = name_up.get (); + const char *name = name_up.get (); char *p; struct stat st; - gdb::unique_xmalloc_ptr new_name_holder; + std::string new_name_holder; /* Spaces and tabs will have been removed by buildargv(). - NAME is the start of the directory. + NAME is the start of the directory. P is the '\0' following the end. */ - p = name + strlen (name); + p = name_up.get () + strlen (name); while (!(IS_DIR_SEPARATOR (*name) && p <= name + 1) /* "/" */ #ifdef HAVE_DOS_BASED_FILE_SYSTEM /* On MS-DOS and MS-Windows, h:\ is different from h: */ && !(p == name + 3 && name[1] == ':') /* "d:/" */ #endif + && p > name && IS_DIR_SEPARATOR (p[-1])) /* Sigh. "foo/" => "foo" */ --p; @@ -515,18 +587,21 @@ add_path (const char *dirname, char **which_path, int parse_separators) break; } + if (name[0] == '\0') + goto skip_dup; if (name[0] == '~') - new_name_holder.reset (tilde_expand (name)); + new_name_holder + = gdb::unique_xmalloc_ptr (tilde_expand (name)).get (); #ifdef HAVE_DOS_BASED_FILE_SYSTEM else if (IS_ABSOLUTE_PATH (name) && p == name + 2) /* "d:" => "d:." */ - new_name_holder.reset (concat (name, ".", (char *) NULL)); + new_name_holder = std::string (name) + "."; #endif else if (!IS_ABSOLUTE_PATH (name) && name[0] != '$') - new_name_holder.reset (concat (current_directory, SLASH_STRING, name, - (char *) NULL)); + new_name_holder = gdb_abspath (name); else - new_name_holder.reset (savestring (name, p - name)); - name = new_name_holder.get (); + new_name_holder = std::string (name, p - name); + + name = new_name_holder.c_str (); /* Unless it's a variable, check existence. */ if (name[0] != '$') @@ -544,7 +619,7 @@ add_path (const char *dirname, char **which_path, int parse_separators) { int save_errno = errno; - fprintf_unfiltered (gdb_stderr, "Warning: "); + gdb_printf (gdb_stderr, "Warning: "); print_sys_errmsg (name, save_errno); } else if ((st.st_mode & S_IFMT) != S_IFDIR) @@ -594,15 +669,10 @@ add_path (const char *dirname, char **which_path, int parse_separators) more. */ if (prefix) { - char *temp, c; - - c = old[prefix]; - old[prefix] = '\0'; - temp = concat (old, tinybuf, name, (char *)NULL); - old[prefix] = c; - *which_path = concat (temp, "", &old[prefix], (char *) NULL); - prefix = strlen (temp); - xfree (temp); + std::string temp = std::string (old, prefix) + tinybuf + name; + *which_path = concat (temp.c_str (), &old[prefix], + (char *) nullptr); + prefix = temp.length (); } else { @@ -618,42 +688,86 @@ add_path (const char *dirname, char **which_path, int parse_separators) } } +/* add_path would need to be re-written to work on an std::string, but this is + not trivial. Hence this overload which copies to a `char *` and back. */ + +void +add_path (const char *dirname, std::string &which_path, int parse_separators) +{ + char *which_path_copy = xstrdup (which_path.data ()); + add_path (dirname, &which_path_copy, parse_separators); + which_path = which_path_copy; + xfree (which_path_copy); +} static void info_source_command (const char *ignore, int from_tty) { - struct symtab *s = current_source_symtab; + current_source_location *loc + = get_source_location (current_program_space); + struct symtab *s = loc->symtab (); struct compunit_symtab *cust; if (!s) { - printf_filtered (_("No current source file.\n")); + gdb_printf (_("No current source file.\n")); return; } - cust = SYMTAB_COMPUNIT (s); - printf_filtered (_("Current source file is %s\n"), s->filename); - if (SYMTAB_DIRNAME (s) != NULL) - printf_filtered (_("Compilation directory is %s\n"), SYMTAB_DIRNAME (s)); + cust = s->compunit (); + gdb_printf (_("Current source file is %s\n"), s->filename); + if (s->compunit ()->dirname () != NULL) + gdb_printf (_("Compilation directory is %s\n"), s->compunit ()->dirname ()); if (s->fullname) - printf_filtered (_("Located in %s\n"), s->fullname); + gdb_printf (_("Located in %s\n"), s->fullname); const std::vector *offsets; if (g_source_cache.get_line_charpos (s, &offsets)) - printf_filtered (_("Contains %d line%s.\n"), (int) offsets->size (), - offsets->size () == 1 ? "" : "s"); - - printf_filtered (_("Source language is %s.\n"), language_str (s->language)); - printf_filtered (_("Producer is %s.\n"), - COMPUNIT_PRODUCER (cust) != NULL - ? COMPUNIT_PRODUCER (cust) : _("unknown")); - printf_filtered (_("Compiled with %s debugging format.\n"), - COMPUNIT_DEBUGFORMAT (cust)); - printf_filtered (_("%s preprocessor macro info.\n"), - COMPUNIT_MACRO_TABLE (cust) != NULL - ? "Includes" : "Does not include"); + gdb_printf (_("Contains %d line%s.\n"), (int) offsets->size (), + offsets->size () == 1 ? "" : "s"); + + gdb_printf (_("Source language is %s.\n"), + language_str (s->language ())); + gdb_printf (_("Producer is %s.\n"), + (cust->producer ()) != nullptr + ? cust->producer () : _("unknown")); + gdb_printf (_("Compiled with %s debugging format.\n"), + cust->debugformat ()); + gdb_printf (_("%s preprocessor macro info.\n"), + (cust->macro_table () != nullptr + ? "Includes" : "Does not include")); } +/* Helper function to remove characters from the start of PATH so that + PATH can then be appended to a directory name. We remove leading drive + letters (for dos) as well as leading '/' characters and './' + sequences. */ + +static const char * +prepare_path_for_appending (const char *path) +{ + /* For dos paths, d:/foo -> /foo, and d:foo -> foo. */ + if (HAS_DRIVE_SPEC (path)) + path = STRIP_DRIVE_SPEC (path); + + const char *old_path; + do + { + old_path = path; + + /* /foo => foo, to avoid multiple slashes that Emacs doesn't like. */ + while (IS_DIR_SEPARATOR(path[0])) + path++; + + /* ./foo => foo */ + while (path[0] == '.' && IS_DIR_SEPARATOR (path[1])) + path += 2; + } + while (old_path != path); + + return path; +} + /* Open a file named STRING, searching path PATH (dir names sep by some char) using mode MODE in the calls to open. You cannot use this function to create files (O_CREAT). @@ -729,7 +843,7 @@ openp (const char *path, openp_flags opts, const char *string, { filename = (char *) alloca (strlen (string) + 1); strcpy (filename, string); - fd = gdb_open_cloexec (filename, mode, 0); + fd = gdb_open_cloexec (filename, mode, 0).release (); if (fd >= 0) goto done; last_errno = errno; @@ -747,17 +861,9 @@ openp (const char *path, openp_flags opts, const char *string, goto done; } - /* For dos paths, d:/foo -> /foo, and d:foo -> foo. */ - if (HAS_DRIVE_SPEC (string)) - string = STRIP_DRIVE_SPEC (string); - - /* /foo => foo, to avoid multiple slashes that Emacs doesn't like. */ - while (IS_DIR_SEPARATOR(string[0])) - string++; - - /* ./foo => foo */ - while (string[0] == '.' && IS_DIR_SEPARATOR (string[1])) - string += 2; + /* Remove characters from the start of PATH that we don't need when PATH + is appended to a directory name. */ + string = prepare_path_for_appending (string); alloclen = strlen (path) + strlen (string) + 2; filename = (char *) alloca (alloclen); @@ -829,7 +935,7 @@ openp (const char *path, openp_flags opts, const char *string, if (is_regular_file (filename, ®_file_errno)) { - fd = gdb_open_cloexec (filename, mode, 0); + fd = gdb_open_cloexec (filename, mode, 0).release (); if (fd >= 0) break; last_errno = errno; @@ -847,7 +953,8 @@ done: else if ((opts & OPF_RETURN_REALPATH) != 0) *filename_opened = gdb_realpath (filename); else - *filename_opened = gdb_abspath (filename); + *filename_opened + = make_unique_xstrdup (gdb_abspath (filename).c_str ()); } errno = last_errno; @@ -872,7 +979,7 @@ source_full_path_of (const char *filename, { int fd; - fd = openp (source_path, + fd = openp (source_path.c_str (), OPF_TRY_CWD_FIRST | OPF_SEARCH_IN_PATH | OPF_RETURN_REALPATH, filename, O_RDONLY, full_pathname); if (fd < 0) @@ -890,9 +997,9 @@ source_full_path_of (const char *filename, static int substitute_path_rule_matches (const struct substitute_path_rule *rule, - const char *path) + const char *path) { - const int from_len = strlen (rule->from); + const int from_len = rule->from.length (); const int path_len = strlen (path); if (path_len < from_len) @@ -901,7 +1008,7 @@ substitute_path_rule_matches (const struct substitute_path_rule *rule, /* The substitution rules are anchored at the start of the path, so the path should start with rule->from. */ - if (filename_ncmp (path, rule->from, from_len) != 0) + if (filename_ncmp (path, rule->from.c_str (), from_len) != 0) return 0; /* Make sure that the region in the path that matches the substitution @@ -920,12 +1027,11 @@ substitute_path_rule_matches (const struct substitute_path_rule *rule, static struct substitute_path_rule * get_substitute_path_rule (const char *path) { - struct substitute_path_rule *rule = substitute_path_rules; + for (substitute_path_rule &rule : substitute_path_rules) + if (substitute_path_rule_matches (&rule, path)) + return &rule; - while (rule != NULL && !substitute_path_rule_matches (rule, path)) - rule = rule->next; - - return rule; + return nullptr; } /* If the user specified a source path substitution rule that applies @@ -938,22 +1044,14 @@ gdb::unique_xmalloc_ptr rewrite_source_path (const char *path) { const struct substitute_path_rule *rule = get_substitute_path_rule (path); - char *new_path; - int from_len; - - if (rule == NULL) - return NULL; - from_len = strlen (rule->from); + if (rule == nullptr) + return nullptr; /* Compute the rewritten path and return it. */ - new_path = - (char *) xmalloc (strlen (path) + 1 + strlen (rule->to) - from_len); - strcpy (new_path, rule->to); - strcat (new_path, path + from_len); - - return gdb::unique_xmalloc_ptr (new_path); + return (gdb::unique_xmalloc_ptr + (concat (rule->to.c_str (), path + rule->from.length (), nullptr))); } /* See source.h. */ @@ -963,31 +1061,33 @@ find_and_open_source (const char *filename, const char *dirname, gdb::unique_xmalloc_ptr *fullname) { - char *path = source_path; + const char *path = source_path.c_str (); + std::string expanded_path_holder; const char *p; - int result; - /* Quick way out if we already know its full name. */ + /* If reading of source files is disabled then return a result indicating + the attempt to read this source file failed. GDB will then display + the filename and line number instead. */ + if (!source_open) + return scoped_fd (-1); + /* Quick way out if we already know its full name. */ if (*fullname) { /* The user may have requested that source paths be rewritten - according to substitution rules he provided. If a substitution - rule applies to this path, then apply it. */ + according to substitution rules he provided. If a substitution + rule applies to this path, then apply it. */ gdb::unique_xmalloc_ptr rewritten_fullname = rewrite_source_path (fullname->get ()); if (rewritten_fullname != NULL) *fullname = std::move (rewritten_fullname); - result = gdb_open_cloexec (fullname->get (), OPEN_MODE, 0); - if (result >= 0) + scoped_fd result = gdb_open_cloexec (fullname->get (), OPEN_MODE, 0); + if (result.get () >= 0) { - if (basenames_may_differ) - *fullname = gdb_realpath (fullname->get ()); - else - *fullname = gdb_abspath (fullname->get ()); - return scoped_fd (result); + *fullname = gdb_realpath (fullname->get ()); + return result; } /* Didn't work -- free old one, try again. */ @@ -998,7 +1098,7 @@ find_and_open_source (const char *filename, if (dirname != NULL) { /* If necessary, rewrite the compilation directory name according - to the source path substitution rules specified by the user. */ + to the source path substitution rules specified by the user. */ rewritten_dirname = rewrite_source_path (dirname); @@ -1008,19 +1108,22 @@ find_and_open_source (const char *filename, /* Replace a path entry of $cdir with the compilation directory name. */ #define cdir_len 5 - p = strstr (source_path, "$cdir"); + p = strstr (source_path.c_str (), "$cdir"); if (p && (p == path || p[-1] == DIRNAME_SEPARATOR) && (p[cdir_len] == DIRNAME_SEPARATOR || p[cdir_len] == '\0')) { - int len; - - path = (char *) - alloca (strlen (source_path) + 1 + strlen (dirname) + 1); - len = p - source_path; - strncpy (path, source_path, len); /* Before $cdir */ - strcpy (path + len, dirname); /* new stuff */ - strcat (path + len, source_path + len + cdir_len); /* After - $cdir */ + int len = p - source_path.c_str (); + + /* Before $cdir */ + expanded_path_holder = source_path.substr (0, len); + + /* new stuff */ + expanded_path_holder += dirname; + + /* After $cdir */ + expanded_path_holder += source_path.c_str () + len + cdir_len; + + path = expanded_path_holder.c_str (); } } @@ -1030,16 +1133,31 @@ find_and_open_source (const char *filename, if (rewritten_filename != NULL) filename = rewritten_filename.get (); - openp_flags flags = OPF_SEARCH_IN_PATH; - if (basenames_may_differ) - flags |= OPF_RETURN_REALPATH; - result = openp (path, flags, filename, OPEN_MODE, fullname); + /* Try to locate file using filename. */ + int result = openp (path, OPF_SEARCH_IN_PATH | OPF_RETURN_REALPATH, filename, + OPEN_MODE, fullname); + if (result < 0 && dirname != NULL) + { + /* Remove characters from the start of PATH that we don't need when + PATH is appended to a directory name. */ + const char *filename_start = prepare_path_for_appending (filename); + + /* Try to locate file using compilation dir + filename. This is + helpful if part of the compilation directory was removed, + e.g. using gcc's -fdebug-prefix-map, and we have added the missing + prefix to source_path. */ + std::string cdir_filename = path_join (dirname, filename_start); + + result = openp (path, OPF_SEARCH_IN_PATH | OPF_RETURN_REALPATH, + cdir_filename.c_str (), OPEN_MODE, fullname); + } if (result < 0) { /* Didn't work. Try using just the basename. */ p = lbasename (filename); if (p != filename) - result = openp (path, flags, p, OPEN_MODE, fullname); + result = openp (path, OPF_SEARCH_IN_PATH | OPF_RETURN_REALPATH, p, + OPEN_MODE, fullname); } return scoped_fd (result); @@ -1048,7 +1166,7 @@ find_and_open_source (const char *filename, /* Open a source file given a symtab S. Returns a file descriptor or negative number for error. - This function is a convience function to find_and_open_source. */ + This function is a convenience function to find_and_open_source. */ scoped_fd open_source_file (struct symtab *s) @@ -1058,12 +1176,69 @@ open_source_file (struct symtab *s) gdb::unique_xmalloc_ptr fullname (s->fullname); s->fullname = NULL; - scoped_fd fd = find_and_open_source (s->filename, SYMTAB_DIRNAME (s), + scoped_fd fd = find_and_open_source (s->filename, s->compunit ()->dirname (), &fullname); + + if (fd.get () < 0) + { + if (s->compunit () != nullptr) + { + const objfile *ofp = s->compunit ()->objfile (); + + std::string srcpath; + if (IS_ABSOLUTE_PATH (s->filename)) + srcpath = s->filename; + else if (s->compunit ()->dirname () != nullptr) + { + srcpath = s->compunit ()->dirname (); + srcpath += SLASH_STRING; + srcpath += s->filename; + } + + const struct bfd_build_id *build_id + = build_id_bfd_get (ofp->obfd.get ()); + + /* Query debuginfod for the source file. */ + if (build_id != nullptr && !srcpath.empty ()) + fd = debuginfod_source_query (build_id->data, + build_id->size, + srcpath.c_str (), + &fullname); + } + } + s->fullname = fullname.release (); return fd; } +/* See source.h. */ + +gdb::unique_xmalloc_ptr +find_source_or_rewrite (const char *filename, const char *dirname) +{ + gdb::unique_xmalloc_ptr fullname; + + scoped_fd fd = find_and_open_source (filename, dirname, &fullname); + if (fd.get () < 0) + { + /* rewrite_source_path would be applied by find_and_open_source, we + should report the pathname where GDB tried to find the file. */ + + if (dirname == nullptr || IS_ABSOLUTE_PATH (filename)) + fullname.reset (xstrdup (filename)); + else + fullname.reset (concat (dirname, SLASH_STRING, + filename, (char *) nullptr)); + + gdb::unique_xmalloc_ptr rewritten + = rewrite_source_path (fullname.get ()); + if (rewritten != nullptr) + fullname = std::move (rewritten); + } + + return fullname; +} + /* Finds the fullname that a symtab represents. This functions finds the fullname and saves it in s->fullname. @@ -1090,10 +1265,11 @@ symtab_to_fullname (struct symtab *s) /* rewrite_source_path would be applied by find_and_open_source, we should report the pathname where GDB tried to find the file. */ - if (SYMTAB_DIRNAME (s) == NULL || IS_ABSOLUTE_PATH (s->filename)) + if (s->compunit ()->dirname () == nullptr + || IS_ABSOLUTE_PATH (s->filename)) fullname.reset (xstrdup (s->filename)); else - fullname.reset (concat (SYMTAB_DIRNAME (s), SLASH_STRING, + fullname.reset (concat (s->compunit ()->dirname (), SLASH_STRING, s->filename, (char *) NULL)); s->fullname = rewrite_source_path (fullname.get ()).release (); @@ -1117,7 +1293,7 @@ symtab_to_filename_for_display (struct symtab *symtab) else if (filename_display_string == filename_display_relative) return symtab->filename; else - internal_error (__FILE__, __LINE__, _("invalid filename_display_string")); + internal_error (_("invalid filename_display_string")); } @@ -1134,13 +1310,16 @@ print_source_lines_base (struct symtab *s, int line, int stopline, struct ui_out *uiout = current_uiout; /* Regardless of whether we can open the file, set current_source_symtab. */ - current_source_symtab = s; - current_source_line = line; + current_source_location *loc + = get_source_location (current_program_space); + + loc->set (s, line); first_line_listed = line; + last_line_listed = line; /* If printing of source lines is disabled, just print file and line number. */ - if (uiout->test_flags (ui_source_list)) + if (uiout->test_flags (ui_source_list) && source_open) { /* Only prints "No such file or directory" once. */ if (s == last_source_visited) @@ -1188,9 +1367,9 @@ print_source_lines_base (struct symtab *s, int line, int stopline, not for TUI. */ if (uiout->is_mi_like_p () || uiout->test_flags (ui_source_list)) uiout->field_string ("file", symtab_to_filename_for_display (s), - ui_out_style_kind::FILE); + file_name_style.style ()); if (uiout->is_mi_like_p () || !uiout->test_flags (ui_source_list)) - { + { const char *s_fullname = symtab_to_fullname (s); char *local_fullname; @@ -1201,7 +1380,7 @@ print_source_lines_base (struct symtab *s, int line, int stopline, strcpy (local_fullname, s_fullname); uiout->field_string ("fullname", local_fullname); - } + } uiout->text ("\n"); } @@ -1225,17 +1404,18 @@ print_source_lines_base (struct symtab *s, int line, int stopline, } const char *iter = lines.c_str (); + int new_lineno = loc->line (); while (nlines-- > 0 && *iter != '\0') { char buf[20]; - last_line_listed = current_source_line; + last_line_listed = loc->line (); if (flags & PRINT_SOURCE_LINES_FILENAME) - { - uiout->text (symtab_to_filename_for_display (s)); - uiout->text (":"); - } - xsnprintf (buf, sizeof (buf), "%d\t", current_source_line++); + { + uiout->text (symtab_to_filename_for_display (s)); + uiout->text (":"); + } + xsnprintf (buf, sizeof (buf), "%d\t", new_lineno++); uiout->text (buf); while (*iter != '\0') @@ -1261,7 +1441,7 @@ print_source_lines_base (struct symtab *s, int line, int stopline, if (iter > start) { std::string text (start, iter); - uiout->text (text.c_str ()); + uiout->text (text); } if (*iter == '\r') { @@ -1290,6 +1470,8 @@ print_source_lines_base (struct symtab *s, int line, int stopline, } uiout->text ("\n"); } + + loc->set (loc->symtab (), new_lineno); } @@ -1327,12 +1509,14 @@ info_line_command (const char *arg, int from_tty) if (arg == 0) { - curr_sal.symtab = current_source_symtab; + current_source_location *loc + = get_source_location (current_program_space); + curr_sal.symtab = loc->symtab (); curr_sal.pspace = current_program_space; if (last_line_listed != 0) curr_sal.line = last_line_listed; else - curr_sal.line = current_source_line; + curr_sal.line = loc->line (); sals = curr_sal; } @@ -1356,49 +1540,48 @@ info_line_command (const char *arg, int from_tty) { struct gdbarch *gdbarch = get_current_arch (); - printf_filtered (_("No line number information available")); + gdb_printf (_("No line number information available")); if (sal.pc != 0) { /* This is useful for "info line *0x7f34". If we can't tell the - user about a source line, at least let them have the symbolic - address. */ - printf_filtered (" for address "); - wrap_here (" "); + user about a source line, at least let them have the symbolic + address. */ + gdb_printf (" for address "); + gdb_stdout->wrap_here (2); print_address (gdbarch, sal.pc, gdb_stdout); } else - printf_filtered ("."); - printf_filtered ("\n"); + gdb_printf ("."); + gdb_printf ("\n"); } else if (sal.line > 0 && find_line_pc_range (sal, &start_pc, &end_pc)) { - struct gdbarch *gdbarch - = get_objfile_arch (SYMTAB_OBJFILE (sal.symtab)); + gdbarch *gdbarch = sal.symtab->compunit ()->objfile ()->arch (); if (start_pc == end_pc) { - printf_filtered ("Line %d of \"%s\"", - sal.line, - symtab_to_filename_for_display (sal.symtab)); - wrap_here (" "); - printf_filtered (" is at address "); + gdb_printf ("Line %d of \"%s\"", + sal.line, + symtab_to_filename_for_display (sal.symtab)); + gdb_stdout->wrap_here (2); + gdb_printf (" is at address "); print_address (gdbarch, start_pc, gdb_stdout); - wrap_here (" "); - printf_filtered (" but contains no code.\n"); + gdb_stdout->wrap_here (2); + gdb_printf (" but contains no code.\n"); } else { - printf_filtered ("Line %d of \"%s\"", - sal.line, - symtab_to_filename_for_display (sal.symtab)); - wrap_here (" "); - printf_filtered (" starts at address "); + gdb_printf ("Line %d of \"%s\"", + sal.line, + symtab_to_filename_for_display (sal.symtab)); + gdb_stdout->wrap_here (2); + gdb_printf (" starts at address "); print_address (gdbarch, start_pc, gdb_stdout); - wrap_here (" "); - printf_filtered (" and ends at "); + gdb_stdout->wrap_here (2); + gdb_printf (" and ends at "); print_address (gdbarch, end_pc, gdb_stdout); - printf_filtered (".\n"); + gdb_printf (".\n"); } /* x/i should display this line's code. */ @@ -1409,15 +1592,15 @@ info_line_command (const char *arg, int from_tty) /* If this is the only line, show the source code. If it could not find the file, don't do anything special. */ - if (sals.size () == 1) + if (annotation_level > 0 && sals.size () == 1) annotate_source_line (sal.symtab, sal.line, 0, start_pc); } else /* Is there any case in which we get here, and have an address which the user would want to see? If we have debugging symbols and no line numbers? */ - printf_filtered (_("Line number %d is out of range for \"%s\".\n"), - sal.line, symtab_to_filename_for_display (sal.symtab)); + gdb_printf (_("Line number %d is out of range for \"%s\".\n"), + sal.line, symtab_to_filename_for_display (sal.symtab)); } } @@ -1434,12 +1617,17 @@ search_command_helper (const char *regex, int from_tty, bool forward) if (msg) error (("%s"), msg); - if (current_source_symtab == 0) + current_source_location *loc + = get_source_location (current_program_space); + if (loc->symtab () == nullptr) select_source_symtab (0); - scoped_fd desc (open_source_file (current_source_symtab)); + if (!source_open) + error (_("source code access disabled")); + + scoped_fd desc (open_source_file (loc->symtab ())); if (desc.get () < 0) - perror_with_name (symtab_to_filename_for_display (current_source_symtab)); + perror_with_name (symtab_to_filename_for_display (loc->symtab ())); int line = (forward ? last_line_listed + 1 @@ -1447,12 +1635,12 @@ search_command_helper (const char *regex, int from_tty, bool forward) const std::vector *offsets; if (line < 1 - || !g_source_cache.get_line_charpos (current_source_symtab, &offsets) + || !g_source_cache.get_line_charpos (loc->symtab (), &offsets) || line > offsets->size ()) error (_("Expression not found")); if (lseek (desc.get (), (*offsets)[line - 1], 0) < 0) - perror_with_name (symtab_to_filename_for_display (current_source_symtab)); + perror_with_name (symtab_to_filename_for_display (loc->symtab ())); gdb_file_up stream = desc.to_file (FDOPEN_MODE); clearerr (stream.get ()); @@ -1474,7 +1662,7 @@ search_command_helper (const char *regex, int from_tty, bool forward) while (c != '\n' && (c = fgetc (stream.get ())) >= 0); /* Remove the \r, if any, at the end of the line, otherwise - regular expressions that end with $ or \n won't work. */ + regular expressions that end with $ or \n won't work. */ size_t sz = buf.size (); if (sz >= 2 && buf[sz - 2] == '\r') { @@ -1487,9 +1675,9 @@ search_command_helper (const char *regex, int from_tty, bool forward) if (re_exec (buf.data ()) > 0) { /* Match! */ - print_source_lines (current_source_symtab, line, line + 1, 0); + print_source_lines (loc->symtab (), line, line + 1, 0); set_internalvar_integer (lookup_internalvar ("_"), line); - current_source_line = std::max (line - lines_to_list / 2, 1); + loc->set (loc->symtab (), std::max (line - lines_to_list / 2, 1)); return; } @@ -1503,13 +1691,13 @@ search_command_helper (const char *regex, int from_tty, bool forward) if (fseek (stream.get (), (*offsets)[line - 1], 0) < 0) { const char *filename - = symtab_to_filename_for_display (current_source_symtab); + = symtab_to_filename_for_display (loc->symtab ()); perror_with_name (filename); } } } - printf_filtered (_("Expression not found\n")); + gdb_printf (_("Expression not found\n")); } static void @@ -1538,79 +1726,13 @@ strip_trailing_directory_separator (char *path) path[last] = '\0'; } -/* Return the path substitution rule that matches FROM. - Return NULL if no rule matches. */ - -static struct substitute_path_rule * -find_substitute_path_rule (const char *from) -{ - struct substitute_path_rule *rule = substitute_path_rules; - - while (rule != NULL) - { - if (FILENAME_CMP (rule->from, from) == 0) - return rule; - rule = rule->next; - } - - return NULL; -} - /* Add a new substitute-path rule at the end of the current list of rules. The new rule will replace FROM into TO. */ void -add_substitute_path_rule (char *from, char *to) +add_substitute_path_rule (const char *from, const char *to) { - struct substitute_path_rule *rule; - struct substitute_path_rule *new_rule = XNEW (struct substitute_path_rule); - - new_rule->from = xstrdup (from); - new_rule->to = xstrdup (to); - new_rule->next = NULL; - - /* If the list of rules are empty, then insert the new rule - at the head of the list. */ - - if (substitute_path_rules == NULL) - { - substitute_path_rules = new_rule; - return; - } - - /* Otherwise, skip to the last rule in our list and then append - the new rule. */ - - rule = substitute_path_rules; - while (rule->next != NULL) - rule = rule->next; - - rule->next = new_rule; -} - -/* Remove the given source path substitution rule from the current list - of rules. The memory allocated for that rule is also deallocated. */ - -static void -delete_substitute_path_rule (struct substitute_path_rule *rule) -{ - if (rule == substitute_path_rules) - substitute_path_rules = rule->next; - else - { - struct substitute_path_rule *prev = substitute_path_rules; - - while (prev != NULL && prev->next != rule) - prev = prev->next; - - gdb_assert (prev != NULL); - - prev->next = rule->next; - } - - xfree (rule->from); - xfree (rule->to); - xfree (rule); + substitute_path_rules.emplace_back (from, to); } /* Implement the "show substitute-path" command. */ @@ -1618,7 +1740,6 @@ delete_substitute_path_rule (struct substitute_path_rule *rule) static void show_substitute_path_command (const char *args, int from_tty) { - struct substitute_path_rule *rule = substitute_path_rules; char *from = NULL; gdb_argv argv (args); @@ -1634,16 +1755,16 @@ show_substitute_path_command (const char *args, int from_tty) /* Print the substitution rules. */ if (from != NULL) - printf_filtered + gdb_printf (_("Source path substitution rule matching `%s':\n"), from); else - printf_filtered (_("List of all source path substitution rules:\n")); + gdb_printf (_("List of all source path substitution rules:\n")); - while (rule != NULL) + for (substitute_path_rule &rule : substitute_path_rules) { - if (from == NULL || substitute_path_rule_matches (rule, from) != 0) - printf_filtered (" `%s' -> `%s'.\n", rule->from, rule->to); - rule = rule->next; + if (from == NULL || substitute_path_rule_matches (&rule, from) != 0) + gdb_printf (" `%s' -> `%s'.\n", rule.from.c_str (), + rule.to.c_str ()); } } @@ -1652,10 +1773,8 @@ show_substitute_path_command (const char *args, int from_tty) static void unset_substitute_path_command (const char *args, int from_tty) { - struct substitute_path_rule *rule = substitute_path_rules; gdb_argv argv (args); char *from = NULL; - int rule_found = 0; /* This function takes either 0 or 1 argument. */ @@ -1676,24 +1795,27 @@ unset_substitute_path_command (const char *args, int from_tty) /* Delete the rule matching the argument. No argument means that all rules should be deleted. */ - while (rule != NULL) + if (from == nullptr) + substitute_path_rules.clear (); + else { - struct substitute_path_rule *next = rule->next; - - if (from == NULL || FILENAME_CMP (from, rule->from) == 0) - { - delete_substitute_path_rule (rule); - rule_found = 1; - } - - rule = next; + auto iter + = std::remove_if (substitute_path_rules.begin (), + substitute_path_rules.end (), + [&] (const substitute_path_rule &rule) + { + return FILENAME_CMP (from, + rule.from.c_str ()) == 0; + }); + bool rule_found = iter != substitute_path_rules.end (); + substitute_path_rules.erase (iter, substitute_path_rules.end ()); + + /* If the user asked for a specific rule to be deleted but + we could not find it, then report an error. */ + + if (!rule_found) + error (_("No substitution rule defined for `%s'"), from); } - - /* If the user asked for a specific rule to be deleted but - we could not find it, then report an error. */ - - if (from != NULL && !rule_found) - error (_("No substitution rule defined for `%s'"), from); forget_cached_source_info (); } @@ -1703,8 +1825,6 @@ unset_substitute_path_command (const char *args, int from_tty) static void set_substitute_path_command (const char *args, int from_tty) { - struct substitute_path_rule *rule; - gdb_argv argv (args); if (argv == NULL || argv[0] == NULL || argv [1] == NULL) @@ -1724,10 +1844,15 @@ set_substitute_path_command (const char *args, int from_tty) /* If a rule with the same "from" was previously defined, then delete it. This new rule replaces it. */ - rule = find_substitute_path_rule (argv[0]); - if (rule != NULL) - delete_substitute_path_rule (rule); - + auto iter + = std::remove_if (substitute_path_rules.begin (), + substitute_path_rules.end (), + [&] (const substitute_path_rule &rule) + { + return FILENAME_CMP (argv[0], rule.from.c_str ()) == 0; + }); + substitute_path_rules.erase (iter, substitute_path_rules.end ()); + /* Insert the new substitution rule. */ add_substitute_path_rule (argv[0], argv[1]); @@ -1761,13 +1886,27 @@ source_lines_range::source_lines_range (int startline, } } +/* Handle the "set source" base command. */ + +static void +set_source (const char *arg, int from_tty) +{ + help_list (setsourcelist, "set source ", all_commands, gdb_stdout); +} + +/* Handle the "show source" base command. */ + +static void +show_source (const char *args, int from_tty) +{ + help_list (showsourcelist, "show source ", all_commands, gdb_stdout); +} + +void _initialize_source (); void -_initialize_source (void) +_initialize_source () { - struct cmd_list_element *c; - - current_source_symtab = 0; init_source_path (); /* The intention is to use POSIX Basic Regular Expressions. @@ -1776,7 +1915,8 @@ _initialize_source (void) just an approximation. */ re_set_syntax (RE_SYNTAX_GREP); - c = add_cmd ("directory", class_files, directory_command, _("\ + cmd_list_element *directory_cmd + = add_cmd ("directory", class_files, directory_command, _("\ Add directory DIR to beginning of search path for source files.\n\ Forget cached info on source file locations and line positions.\n\ DIR can also be $cwd for the current working directory, or $cdir for the\n\ @@ -1784,10 +1924,7 @@ directory in which the source file was compiled into object code.\n\ With no argument, reset the search path to $cdir:$cwd, the default."), &cmdlist); - if (dbx_commands) - add_com_alias ("use", "directory", class_files, 0); - - set_cmd_completer (c, filename_completer); + set_cmd_completer (directory_cmd, filename_completer); add_setshow_optional_filename_cmd ("directories", class_files, @@ -1821,16 +1958,18 @@ This sets the default address for \"x\" to the line's first instruction\n\ so that \"x/i\" suffices to start examining the machine code.\n\ The address is also stored as the value of \"$_\".")); - add_com ("forward-search", class_files, forward_search_command, _("\ + cmd_list_element *forward_search_cmd + = add_com ("forward-search", class_files, forward_search_command, _("\ Search for regular expression (see regex(3)) from last line listed.\n\ The matching line number is also stored as the value of \"$_\".")); - add_com_alias ("search", "forward-search", class_files, 0); - add_com_alias ("fo", "forward-search", class_files, 1); + add_com_alias ("search", forward_search_cmd, class_files, 0); + add_com_alias ("fo", forward_search_cmd, class_files, 1); - add_com ("reverse-search", class_files, reverse_search_command, _("\ + cmd_list_element *reverse_search_cmd + = add_com ("reverse-search", class_files, reverse_search_command, _("\ Search backward for regular expression (see regex(3)) from last line listed.\n\ The matching line number is also stored as the value of \"$_\".")); - add_com_alias ("rev", "reverse-search", class_files, 1); + add_com_alias ("rev", reverse_search_cmd, class_files, 1); add_setshow_integer_cmd ("listsize", class_support, &lines_to_list, _("\ Set number of source lines gdb will list by default."), _("\ @@ -1843,31 +1982,31 @@ A value of \"unlimited\", or zero, means there's no limit."), &setlist, &showlist); add_cmd ("substitute-path", class_files, set_substitute_path_command, - _("\ + _("\ Add a substitution rule to rewrite the source directories.\n\ Usage: set substitute-path FROM TO\n\ The rule is applied only if the directory name starts with FROM\n\ directly followed by a directory separator.\n\ If a substitution rule was previously set for FROM, the old rule\n\ is replaced by the new one."), - &setlist); + &setlist); add_cmd ("substitute-path", class_files, unset_substitute_path_command, - _("\ + _("\ Delete one or all substitution rules rewriting the source directories.\n\ Usage: unset substitute-path [FROM]\n\ Delete the rule for substituting FROM in source directories. If FROM\n\ is not specified, all substituting rules are deleted.\n\ If the debugger cannot find a rule for FROM, it will display a warning."), - &unsetlist); + &unsetlist); add_cmd ("substitute-path", class_files, show_substitute_path_command, - _("\ + _("\ Show one or all substitution rules rewriting the source directories.\n\ Usage: show substitute-path [FROM]\n\ Print the rule for substituting FROM in source directories. If FROM\n\ is not specified, print all substitution rules."), - &showlist); + &showlist); add_setshow_enum_cmd ("filename-display", class_files, filename_display_kind_names, @@ -1883,4 +2022,25 @@ By default, relative filenames are displayed."), show_filename_display_string, &setlist, &showlist); + add_prefix_cmd ("source", no_class, set_source, + _("Generic command for setting how sources are handled."), + &setsourcelist, 0, &setlist); + + add_prefix_cmd ("source", no_class, show_source, + _("Generic command for showing source settings."), + &showsourcelist, 0, &showlist); + + add_setshow_boolean_cmd ("open", class_files, &source_open, _("\ +Set whether GDB should open source files."), _("\ +Show whether GDB should open source files."), _("\ +When this option is on GDB will open source files and display the\n\ +contents when appropriate, for example, when GDB stops, or the list\n\ +command is used.\n\ +When this option is off GDB will not try to open source files, instead\n\ +GDB will print the file and line number that would have been displayed.\n\ +This can be useful if access to source code files is slow, for example\n\ +due to the source being located over a slow network connection."), + NULL, + show_source_open, + &setsourcelist, &showsourcelist); }