/* List lines of source files for GDB, the GNU debugger.
- Copyright (C) 1986-2018 Free Software Foundation, Inc.
+ Copyright (C) 1986-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include "common/scoped_fd.h"
#include <algorithm>
#include "common/pathstuff.h"
+#include "source-cache.h"
#define OPEN_MODE (O_RDONLY | O_BINARY)
#define FDOPEN_MODE FOPEN_RB
current_source_line = 0;
}
-/* Set the source file default for the "list" command to be S.
-
- If S is NULL, and we don't have a default, find one. This
- should only be called when the user actually tries to use the
- default, since we produce an error if we can't find a reasonable
- default. Also, since this can cause symbols to be read, doing it
- before we need to would make things slower than necessary. */
+/* See source.h. */
void
select_source_symtab (struct symtab *s)
{
- struct objfile *ofp;
- struct compunit_symtab *cu;
-
if (s)
{
current_source_symtab = s;
current_source_line = 1;
- ALL_FILETABS (ofp, cu, s)
+ for (objfile *ofp : current_program_space->objfiles ())
{
- const char *name = s->filename;
- int len = strlen (name);
-
- if (!(len > 2 && (strcmp (&name[len - 2], ".h") == 0
- || strcmp (name, "<<C++-namespaces>>") == 0)))
+ for (compunit_symtab *cu : ofp->compunits ())
{
- current_source_pspace = current_program_space;
- current_source_symtab = s;
+ for (symtab *symtab : compunit_filetabs (cu))
+ {
+ const char *name = symtab->filename;
+ int len = strlen (name);
+
+ if (!(len > 2 && (strcmp (&name[len - 2], ".h") == 0
+ || strcmp (name, "<<C++-namespaces>>") == 0)))
+ {
+ current_source_pspace = current_program_space;
+ current_source_symtab = symtab;
+ }
+ }
}
}
if (current_source_symtab)
return;
- ALL_OBJFILES (ofp)
- {
- if (ofp->sf)
- s = ofp->sf->qf->find_last_source_symtab (ofp);
- if (s)
- current_source_symtab = s;
- }
+ 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;
+ }
if (current_source_symtab)
return;
show_directories_1 (NULL, from_tty);
}
-/* Forget line positions and file names for the symtabs in a
- particular objfile. */
+/* See source.h. */
void
forget_cached_source_info_for_objfile (struct objfile *objfile)
{
- struct compunit_symtab *cu;
- struct symtab *s;
-
- ALL_OBJFILE_FILETABS (objfile, cu, s)
+ for (compunit_symtab *cu : objfile->compunits ())
{
- if (s->line_charpos != NULL)
- {
- xfree (s->line_charpos);
- s->line_charpos = NULL;
- }
- if (s->fullname != NULL)
+ for (symtab *s : compunit_filetabs (cu))
{
- xfree (s->fullname);
- s->fullname = NULL;
+ if (s->line_charpos != NULL)
+ {
+ xfree (s->line_charpos);
+ s->line_charpos = NULL;
+ }
+ if (s->fullname != NULL)
+ {
+ xfree (s->fullname);
+ s->fullname = NULL;
+ }
}
}
objfile->sf->qf->forget_cached_source_info (objfile);
}
-/* Forget what we learned about line positions in source files, and
- which directories contain them; must check again now since files
- may be found in a different directory now. */
+/* See source.h. */
void
forget_cached_source_info (void)
{
struct program_space *pspace;
- struct objfile *objfile;
ALL_PSPACES (pspace)
- ALL_PSPACE_OBJFILES (pspace, objfile)
- {
- forget_cached_source_info_for_objfile (objfile);
- }
+ for (objfile *objfile : pspace->objfiles ())
+ {
+ forget_cached_source_info_for_objfile (objfile);
+ }
+ g_source_cache.clear ();
last_source_visited = NULL;
}
find_source_lines (s, desc.get ());
}
-/* Print text describing the full name of the source file S
- and the line number LINE and its corresponding character position.
- The text starts with two Ctrl-z so that the Emacs-GDB interface
- can easily find it.
-
- MID_STATEMENT is nonzero if the PC is not at the beginning of that line.
-
- Return 1 if successful, 0 if could not find the file. */
+/* See source.h. */
int
identify_source_line (struct symtab *s, int line, int mid_statement,
MI expects both fields. ui_source_list is set only for CLI,
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));
+ uiout->field_string ("file", symtab_to_filename_for_display (s),
+ ui_out_style_kind::FILE);
if (uiout->is_mi_like_p () || !uiout->test_flags (ui_source_list))
{
const char *s_fullname = symtab_to_fullname (s);
last_source_error = 0;
- if (s->line_charpos == 0)
- find_source_lines (s, desc.get ());
+ /* 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)
+ return;
- if (line < 1 || line > s->nlines)
+ 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);
- if (lseek (desc.get (), s->line_charpos[line - 1], 0) < 0)
- perror_with_name (symtab_to_filename_for_display (s));
-
- gdb_file_up stream = desc.to_file (FDOPEN_MODE);
- clearerr (stream.get ());
-
+ const char *iter = lines.c_str ();
while (nlines-- > 0)
{
char buf[20];
- c = fgetc (stream.get ());
- if (c == EOF)
+ c = *iter++;
+ if (c == '\0')
break;
last_line_listed = current_source_line;
if (flags & PRINT_SOURCE_LINES_FILENAME)
uiout->text (buf);
do
{
- if (c < 040 && c != '\t' && c != '\n' && c != '\r')
+ if (c < 040 && c != '\t' && c != '\n' && c != '\r' && c != '\033')
{
xsnprintf (buf, sizeof (buf), "^%c", c + 0100);
uiout->text (buf);
else if (c == '\r')
{
/* Skip a \r character, but only before a \n. */
- int c1 = fgetc (stream.get ());
-
- if (c1 != '\n')
+ if (*iter != '\n')
printf_filtered ("^%c", c + 0100);
- if (c1 != EOF)
- ungetc (c1, stream.get ());
}
else
{
uiout->text (buf);
}
}
- while (c != '\n' && (c = fgetc (stream.get ())) >= 0);
+ while (c != '\n' && (c = *iter++) != '\0');
+ if (c == '\0')
+ break;
}
+ if (!lines.empty() && lines.back () != '\n')
+ uiout->text ("\n");
}
\f
-/* Show source lines from the file of symtab S, starting with line
- number LINE and stopping before line number STOPLINE. If this is
- not the command line version, then the source is shown in the source
- window otherwise it is simply printed. */
+
+/* See source.h. */
void
print_source_lines (struct symtab *s, int line, int stopline,
{
print_source_lines_base (s, line, stopline, flags);
}
+
+/* See source.h. */
+
+void
+print_source_lines (struct symtab *s, source_lines_range line_range,
+ print_source_lines_flags flags)
+{
+ print_source_lines_base (s, line_range.startline (),
+ line_range.stopline (), flags);
+}
+
+
\f
/* Print info on range of pc's in a specified line. */
\f
/* Commands to search the source file for a regexp. */
+/* Helper for forward_search_command/reverse_search_command. FORWARD
+ indicates direction: true for forward, false for
+ backward/reverse. */
+
static void
-forward_search_command (const char *regex, int from_tty)
+search_command_helper (const char *regex, int from_tty, bool forward)
{
- int c;
- int line;
- char *msg;
-
- line = last_line_listed + 1;
-
- msg = (char *) re_comp (regex);
+ const char *msg = re_comp (regex);
if (msg)
error (("%s"), msg);
if (current_source_symtab->line_charpos == 0)
find_source_lines (current_source_symtab, desc.get ());
+ int line = (forward
+ ? last_line_listed + 1
+ : last_line_listed - 1);
+
if (line < 1 || line > current_source_symtab->nlines)
error (_("Expression not found"));
gdb_file_up stream = desc.to_file (FDOPEN_MODE);
clearerr (stream.get ());
+
+ gdb::def_vector<char> buf;
+ buf.reserve (256);
+
while (1)
{
- static char *buf = NULL;
- char *p;
- int cursize, newsize;
-
- cursize = 256;
- buf = (char *) xmalloc (cursize);
- p = buf;
+ buf.resize (0);
- c = fgetc (stream.get ());
+ int c = fgetc (stream.get ());
if (c == EOF)
break;
do
{
- *p++ = c;
- if (p - buf == cursize)
- {
- newsize = cursize + cursize / 2;
- buf = (char *) xrealloc (buf, newsize);
- p = buf + cursize;
- cursize = newsize;
- }
+ buf.push_back (c);
}
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. */
- if (p - buf > 1 && p[-2] == '\r')
+ size_t sz = buf.size ();
+ if (sz >= 2 && buf[sz - 2] == '\r')
{
- p--;
- p[-1] = '\n';
+ buf[sz - 2] = '\n';
+ buf.resize (sz - 1);
}
/* We now have a source line in buf, null terminate and match. */
- *p = 0;
- if (re_exec (buf) > 0)
+ buf.push_back ('\0');
+ if (re_exec (buf.data ()) > 0)
{
/* Match! */
print_source_lines (current_source_symtab, line, line + 1, 0);
current_source_line = std::max (line - lines_to_list / 2, 1);
return;
}
- line++;
+
+ if (forward)
+ line++;
+ else
+ {
+ line--;
+ if (line < 1)
+ break;
+ if (fseek (stream.get (),
+ current_source_symtab->line_charpos[line - 1], 0) < 0)
+ {
+ const char *filename
+ = symtab_to_filename_for_display (current_source_symtab);
+ perror_with_name (filename);
+ }
+ }
}
printf_filtered (_("Expression not found\n"));
}
static void
-reverse_search_command (const char *regex, int from_tty)
+forward_search_command (const char *regex, int from_tty)
{
- int c;
- int line;
- char *msg;
-
- line = last_line_listed - 1;
-
- msg = (char *) re_comp (regex);
- if (msg)
- error (("%s"), msg);
-
- if (current_source_symtab == 0)
- select_source_symtab (0);
-
- scoped_fd desc = open_source_file (current_source_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 ());
-
- if (line < 1 || line > current_source_symtab->nlines)
- 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));
-
- gdb_file_up stream = desc.to_file (FDOPEN_MODE);
- clearerr (stream.get ());
- while (line > 1)
- {
-/* FIXME!!! We walk right off the end of buf if we get a long line!!! */
- char buf[4096]; /* Should be reasonable??? */
- char *p = buf;
-
- c = fgetc (stream.get ());
- if (c == EOF)
- break;
- do
- {
- *p++ = c;
- }
- 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. */
- if (p - buf > 1 && p[-2] == '\r')
- {
- p--;
- p[-1] = '\n';
- }
-
- /* We now have a source line in buf; null terminate and match. */
- *p = 0;
- if (re_exec (buf) > 0)
- {
- /* Match! */
- print_source_lines (current_source_symtab, line, line + 1, 0);
- set_internalvar_integer (lookup_internalvar ("_"), line);
- current_source_line = std::max (line - lines_to_list / 2, 1);
- return;
- }
- line--;
- if (fseek (stream.get (),
- current_source_symtab->line_charpos[line - 1], 0) < 0)
- {
- const char *filename;
-
- filename = symtab_to_filename_for_display (current_source_symtab);
- perror_with_name (filename);
- }
- }
+ search_command_helper (regex, from_tty, true);
+}
- printf_filtered (_("Expression not found\n"));
- return;
+static void
+reverse_search_command (const char *regex, int from_tty)
+{
+ search_command_helper (regex, from_tty, false);
}
/* If the last character of PATH is a directory separator, then strip it. */
forget_cached_source_info ();
}
+/* See source.h. */
+
+source_lines_range::source_lines_range (int startline,
+ source_lines_range::direction dir)
+{
+ if (dir == source_lines_range::FORWARD)
+ {
+ LONGEST end = static_cast <LONGEST> (startline) + get_lines_to_list ();
+
+ if (end > INT_MAX)
+ end = INT_MAX;
+
+ m_startline = startline;
+ m_stopline = static_cast <int> (end);
+ }
+ else
+ {
+ LONGEST start = static_cast <LONGEST> (startline) - get_lines_to_list ();
+
+ if (start < 1)
+ start = 1;
+
+ m_startline = static_cast <int> (start);
+ m_stopline = startline;
+ }
+}
+
\f
void
_initialize_source (void)