/* List lines of source files for GDB, the GNU debugger.
- Copyright (C) 1986-2019 Free Software Foundation, Inc.
+ Copyright (C) 1986-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include "gdbcmd.h"
#include "frame.h"
#include "value.h"
-#include "common/filestuff.h"
+#include "gdbsupport/filestuff.h"
#include <sys/types.h>
#include <fcntl.h>
#include "filenames.h" /* for DOSish file names */
#include "completer.h"
#include "ui-out.h"
-#include "readline/readline.h"
-#include "common/enum-flags.h"
-#include "common/scoped_fd.h"
+#include "readline/tilde.h"
+#include "gdbsupport/enum-flags.h"
+#include "gdbsupport/scoped_fd.h"
#include <algorithm>
-#include "common/pathstuff.h"
+#include "gdbsupport/pathstuff.h"
#include "source-cache.h"
+#include "cli/cli-style.h"
+#include "observable.h"
#define OPEN_MODE (O_RDONLY | O_BINARY)
#define FDOPEN_MODE FOPEN_RB
static struct substitute_path_rule *substitute_path_rules = NULL;
-/* 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;
+ }
+
+private:
+
+ /* Symtab of default file for listing lines of. */
+
+ struct symtab *m_symtab = nullptr;
-/* Default next line to list. */
+ /* Default next line to list. */
-static int current_source_line;
+ int m_line = 0;
+};
-static struct program_space *current_source_pspace;
+static program_space_key<current_source_location> 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
Used to prevent repeating annoying "No such file or directories" msgs. */
static struct symtab *last_source_visited = NULL;
-static int last_source_error = 0;
+static bool last_source_error = false;
\f
/* Return the first line listed by print_source_lines.
Used by command interpreters to request listing from
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. */
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;
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);
}
{
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 ();
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. */
{
if (s)
{
- current_source_symtab = s;
- current_source_line = 1;
- current_source_pspace = SYMTAB_PSPACE (s);
+ current_source_location *loc
+ = get_source_location (SYMTAB_PSPACE (s));
+ 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 && SYMBOL_CLASS (bsym.symbol) == LOC_BLOCK)
{
- std::vector<symtab_and_line> 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);
+ 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 ())
{
if (!(len > 2 && (strcmp (&name[len - 2], ".h") == 0
|| strcmp (name, "<<C++-namespaces>>") == 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);
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"));
}
{
for (symtab *s : compunit_filetabs (cu))
{
- if (s->line_charpos != NULL)
- {
- xfree (s->line_charpos);
- s->line_charpos = NULL;
- }
if (s->fullname != NULL)
{
xfree (s->fullname);
new_name_holder.reset (concat (name, ".", (char *) NULL));
#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 ();
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 (_("Compilation directory is %s\n"), SYMTAB_DIRNAME (s));
if (s->fullname)
printf_filtered (_("Located in %s\n"), s->fullname);
- if (s->nlines)
- printf_filtered (_("Contains %d line%s.\n"), s->nlines,
- s->nlines == 1 ? "" : "s");
+ const std::vector<off_t> *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"),
}
\f
+/* 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).
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);
result = gdb_open_cloexec (fullname->get (), OPEN_MODE, 0);
if (result >= 0)
{
- *fullname = gdb_realpath (fullname->get ());
+ if (basenames_may_differ)
+ *fullname = gdb_realpath (fullname->get ());
+ else
+ *fullname = gdb_abspath (fullname->get ());
return scoped_fd (result);
}
/* Replace a path entry of $cdir with the compilation directory
name. */
#define cdir_len 5
- /* We cast strstr's result in case an ANSIhole has made it const,
- which produces a "required warning" when assigned to a nonconst. */
- p = (char *) strstr (source_path, "$cdir");
+ p = strstr (source_path, "$cdir");
if (p && (p == path || p[-1] == DIRNAME_SEPARATOR)
&& (p[cdir_len] == DIRNAME_SEPARATOR || p[cdir_len] == '\0'))
{
}
}
- gdb::unique_xmalloc_ptr<char> rewritten_filename;
- if (IS_ABSOLUTE_PATH (filename))
- {
- /* If filename is absolute path, try the source path
- substitution on it. */
- rewritten_filename = rewrite_source_path (filename);
+ gdb::unique_xmalloc_ptr<char> rewritten_filename
+ = rewrite_source_path (filename);
- if (rewritten_filename != NULL)
- filename = rewritten_filename.get ();
- }
+ if (rewritten_filename != NULL)
+ filename = rewritten_filename.get ();
- result = openp (path, OPF_SEARCH_IN_PATH | OPF_RETURN_REALPATH, filename,
- OPEN_MODE, fullname);
+ openp_flags flags = OPF_SEARCH_IN_PATH;
+ if (basenames_may_differ)
+ flags |= OPF_RETURN_REALPATH;
+
+ /* Try to locate file using filename. */
+ result = openp (path, flags, 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 (dirname);
+
+ /* Remove any trailing directory separators. */
+ while (IS_DIR_SEPARATOR (cdir_filename.back ()))
+ cdir_filename.pop_back ();
+
+ /* Add our own directory separator. */
+ cdir_filename.append (SLASH_STRING);
+ cdir_filename.append (filename_start);
+
+ result = openp (path, flags, 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, OPF_SEARCH_IN_PATH | OPF_RETURN_REALPATH, p,
- OPEN_MODE, fullname);
+ result = openp (path, flags, p, OPEN_MODE, fullname);
}
return scoped_fd (result);
/* 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)
else
internal_error (__FILE__, __LINE__, _("invalid filename_display_string"));
}
-\f
-/* Create and initialize the table S->line_charpos that records
- the positions of the lines in the source file, which is assumed
- to be open on descriptor DESC.
- All set S->nlines to the number of such lines. */
-
-void
-find_source_lines (struct symtab *s, int desc)
-{
- struct stat st;
- char *p, *end;
- int nlines = 0;
- int lines_allocated = 1000;
- int *line_charpos;
- long mtime = 0;
- int size;
-
- gdb_assert (s);
- line_charpos = XNEWVEC (int, lines_allocated);
- if (fstat (desc, &st) < 0)
- perror_with_name (symtab_to_filename_for_display (s));
-
- if (SYMTAB_OBJFILE (s) != NULL && SYMTAB_OBJFILE (s)->obfd != NULL)
- mtime = SYMTAB_OBJFILE (s)->mtime;
- else if (exec_bfd)
- mtime = exec_bfd_mtime;
-
- if (mtime && mtime < st.st_mtime)
- warning (_("Source file is more recent than executable."));
- {
- /* st_size might be a large type, but we only support source files whose
- size fits in an int. */
- size = (int) st.st_size;
-
- /* Use the heap, not the stack, because this may be pretty large,
- and we may run into various kinds of limits on stack size. */
- gdb::def_vector<char> data (size);
-
- /* Reassign `size' to result of read for systems where \r\n -> \n. */
- size = myread (desc, data.data (), size);
- if (size < 0)
- perror_with_name (symtab_to_filename_for_display (s));
- end = data.data () + size;
- p = &data[0];
- line_charpos[0] = 0;
- nlines = 1;
- while (p != end)
- {
- if (*p++ == '\n'
- /* A newline at the end does not start a new line. */
- && p != end)
- {
- if (nlines == lines_allocated)
- {
- lines_allocated *= 2;
- line_charpos =
- (int *) xrealloc ((char *) line_charpos,
- sizeof (int) * lines_allocated);
- }
- line_charpos[nlines++] = p - data.data ();
- }
- }
- }
-
- s->nlines = nlines;
- s->line_charpos =
- (int *) xrealloc ((char *) line_charpos, nlines * sizeof (int));
-
-}
-
-\f
-
-/* Get full pathname and line number positions for a symtab.
- Set *FULLNAME to actual name of the file as found by `openp',
- or to 0 if the file is not found. */
-
-static void
-get_filename_and_charpos (struct symtab *s, char **fullname)
-{
- scoped_fd desc = open_source_file (s);
- if (desc.get () < 0)
- {
- if (fullname)
- *fullname = NULL;
- return;
- }
- if (fullname)
- *fullname = s->fullname;
- if (s->line_charpos == 0)
- find_source_lines (s, desc.get ());
-}
-
-/* See source.h. */
-
-int
-identify_source_line (struct symtab *s, int line, int mid_statement,
- CORE_ADDR pc)
-{
- if (s->line_charpos == 0)
- get_filename_and_charpos (s, (char **) NULL);
- if (s->fullname == 0)
- return 0;
- if (line > s->nlines)
- /* Don't index off the end of the line_charpos array. */
- return 0;
- annotate_source (s->fullname, line, s->line_charpos[line - 1],
- mid_statement, get_objfile_arch (SYMTAB_OBJFILE (s)), pc);
-
- current_source_line = line;
- current_source_symtab = s;
- clear_lines_listed_range ();
- return 1;
-}
\f
/* Print source lines from the file of symtab S,
print_source_lines_base (struct symtab *s, int line, int stopline,
print_source_lines_flags flags)
{
- int c;
- scoped_fd desc;
- int noprint = 0;
+ bool noprint = false;
int nlines = stopline - line;
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))
{
/* Only prints "No such file or directory" once. */
- if ((s != last_source_visited) || (!last_source_error))
+ if (s == last_source_visited)
{
- last_source_visited = s;
- desc = open_source_file (s);
- if (desc.get () < 0)
+ if (last_source_error)
{
- last_source_error = desc.get ();
- noprint = 1;
+ flags |= PRINT_SOURCE_LINES_NOERROR;
+ noprint = true;
}
}
else
{
- flags |= PRINT_SOURCE_LINES_NOERROR;
- noprint = 1;
+ last_source_visited = s;
+ scoped_fd desc = open_source_file (s);
+ last_source_error = desc.get () < 0;
+ if (last_source_error)
+ noprint = true;
}
}
else
{
flags |= PRINT_SOURCE_LINES_NOERROR;
- noprint = 1;
+ noprint = true;
}
if (noprint)
}
else
{
- uiout->field_int ("line", line);
+ uiout->field_signed ("line", line);
uiout->text ("\tin ");
/* CLI expects only the "file" field. TUI expects only the
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);
return;
}
- last_source_error = 0;
-
/* If the user requested a sequence of lines that seems to go backward
(from high to low line numbers) then we don't print anything. */
if (stopline <= line)
std::string lines;
if (!g_source_cache.get_source_lines (s, line, stopline - 1, &lines))
- error (_("Line number %d out of range; %s has %d lines."),
- line, symtab_to_filename_for_display (s), s->nlines);
+ {
+ const std::vector<off_t> *offsets = nullptr;
+ g_source_cache.get_line_charpos (s, &offsets);
+ error (_("Line number %d out of range; %s has %d lines."),
+ line, symtab_to_filename_for_display (s),
+ offsets == nullptr ? 0 : (int) offsets->size ());
+ }
const char *iter = lines.c_str ();
- while (nlines-- > 0)
+ int new_lineno = loc->line ();
+ while (nlines-- > 0 && *iter != '\0')
{
char buf[20];
- c = *iter++;
- if (c == '\0')
- break;
- 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++);
+ xsnprintf (buf, sizeof (buf), "%d\t", new_lineno++);
uiout->text (buf);
- do
+
+ while (*iter != '\0')
{
- if (c < 040 && c != '\t' && c != '\n' && c != '\r' && c != '\033')
+ /* Find a run of characters that can be emitted at once.
+ This is done so that escape sequences are kept
+ together. */
+ const char *start = iter;
+ while (true)
{
- xsnprintf (buf, sizeof (buf), "^%c", c + 0100);
- uiout->text (buf);
+ int skip_bytes;
+
+ char c = *iter;
+ if (c == '\033' && skip_ansi_escape (iter, &skip_bytes))
+ iter += skip_bytes;
+ else if (c >= 0 && c < 040 && c != '\t')
+ break;
+ else if (c == 0177)
+ break;
+ else
+ ++iter;
}
- else if (c == 0177)
- uiout->text ("^?");
- else if (c == '\r')
+ if (iter > start)
{
- /* Skip a \r character, but only before a \n. */
- if (*iter != '\n')
- printf_filtered ("^%c", c + 0100);
+ std::string text (start, iter);
+ uiout->text (text.c_str ());
}
- else
+ if (*iter == '\r')
{
- xsnprintf (buf, sizeof (buf), "%c", c);
+ /* Treat either \r or \r\n as a single newline. */
+ ++iter;
+ if (*iter == '\n')
+ ++iter;
+ break;
+ }
+ else if (*iter == '\n')
+ {
+ ++iter;
+ break;
+ }
+ else if (*iter > 0 && *iter < 040)
+ {
+ xsnprintf (buf, sizeof (buf), "^%c", *iter + 0100);
uiout->text (buf);
+ ++iter;
+ }
+ else if (*iter == 0177)
+ {
+ uiout->text ("^?");
+ ++iter;
}
}
- while (c != '\n' && (c = *iter++) != '\0');
- if (c == '\0')
- break;
+ uiout->text ("\n");
}
- if (!lines.empty() && lines.back () != '\n')
- uiout->text ("\n");
+
+ loc->set (loc->symtab (), new_lineno);
}
\f
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;
}
/* If this is the only line, show the source code. If it could
not find the file, don't do anything special. */
- if (annotation_level && sals.size () == 1)
- identify_source_line (sal.symtab, sal.line, 0, start_pc);
+ if (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
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);
+ scoped_fd desc (open_source_file (loc->symtab ()));
if (desc.get () < 0)
- perror_with_name (symtab_to_filename_for_display (current_source_symtab));
-
- if (current_source_symtab->line_charpos == 0)
- find_source_lines (current_source_symtab, desc.get ());
+ perror_with_name (symtab_to_filename_for_display (loc->symtab ()));
int line = (forward
? last_line_listed + 1
: last_line_listed - 1);
- if (line < 1 || line > current_source_symtab->nlines)
+ const std::vector<off_t> *offsets;
+ if (line < 1
+ || !g_source_cache.get_line_charpos (loc->symtab (), &offsets)
+ || line > offsets->size ())
error (_("Expression not found"));
- if (lseek (desc.get (), current_source_symtab->line_charpos[line - 1], 0)
- < 0)
- perror_with_name (symtab_to_filename_for_display (current_source_symtab));
+ if (lseek (desc.get (), (*offsets)[line - 1], 0) < 0)
+ perror_with_name (symtab_to_filename_for_display (loc->symtab ()));
gdb_file_up stream = desc.to_file (FDOPEN_MODE);
clearerr (stream.get ());
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;
}
line--;
if (line < 1)
break;
- if (fseek (stream.get (),
- current_source_symtab->line_charpos[line - 1], 0) < 0)
+ 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);
}
}
{
struct cmd_list_element *c;
- current_source_symtab = 0;
init_source_path ();
/* The intention is to use POSIX Basic Regular Expressions.
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\
-Add a substitution rule replacing FROM into TO in source file names.\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);
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 file names. If 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);
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 file names. If FROM\n\
+Print the rule for substituting FROM in source directories. If FROM\n\
is not specified, print all substitution rules."),
&showlist);