/* List lines of source files for GDB, the GNU debugger.
- Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
- 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008,
- 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1986-2005, 2007-2012 Free Software Foundation, Inc.
This file is part of GDB.
if one exists. */
if (lookup_symbol (main_name (), 0, VAR_DOMAIN, 0))
{
- sals = decode_line_spec (main_name (), 1);
+ sals = decode_line_spec (main_name (), DECODE_LINE_FUNFIRSTLINE);
sal = sals.sals[0];
xfree (sals.sals);
current_source_pspace = sal.pspace;
show_directories_1 (NULL, from_tty);
}
+/* Forget line positions and file names for the symtabs in a
+ particular objfile. */
+
+void
+forget_cached_source_info_for_objfile (struct objfile *objfile)
+{
+ struct symtab *s;
+
+ ALL_OBJFILE_SYMTABS (objfile, s)
+ {
+ if (s->line_charpos != NULL)
+ {
+ xfree (s->line_charpos);
+ s->line_charpos = NULL;
+ }
+ if (s->fullname != NULL)
+ {
+ xfree (s->fullname);
+ s->fullname = NULL;
+ }
+ }
+
+ if (objfile->sf)
+ 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. */
forget_cached_source_info (void)
{
struct program_space *pspace;
- struct symtab *s;
struct objfile *objfile;
ALL_PSPACES (pspace)
ALL_PSPACE_OBJFILES (pspace, objfile)
{
- for (s = objfile->symtabs; s != NULL; s = s->next)
- {
- if (s->line_charpos != NULL)
- {
- xfree (s->line_charpos);
- s->line_charpos = NULL;
- }
- if (s->fullname != NULL)
- {
- xfree (s->fullname);
- s->fullname = NULL;
- }
- }
-
- if (objfile->sf)
- objfile->sf->qf->forget_cached_source_info (objfile);
+ forget_cached_source_info_for_objfile (objfile);
}
last_source_visited = NULL;
{
char *old = *which_path;
int prefix = 0;
- char **argv = NULL;
- char *arg;
- int argv_index = 0;
+ VEC (char_ptr) *dir_vec = NULL;
+ struct cleanup *back_to;
+ int ix;
+ char *name;
if (dirname == 0)
return;
if (parse_separators)
{
+ char **argv, **argvp;
+
/* This will properly parse the space and tab separators
- and any quotes that may exist. DIRNAME_SEPARATOR will
- be dealt with later. */
+ and any quotes that may exist. */
argv = gdb_buildargv (dirname);
- make_cleanup_freeargv (argv);
- arg = argv[0];
+ for (argvp = argv; *argvp; argvp++)
+ dirnames_to_char_ptr_vec_append (&dir_vec, *argvp);
+
+ freeargv (argv);
}
else
- {
- arg = xstrdup (dirname);
- make_cleanup (xfree, arg);
- }
+ VEC_safe_push (char_ptr, dir_vec, xstrdup (dirname));
+ back_to = make_cleanup_free_char_ptr_vec (dir_vec);
- do
+ for (ix = 0; VEC_iterate (char_ptr, dir_vec, ix, name); ++ix)
{
- char *name = arg;
char *p;
struct stat st;
- {
- char *separator = NULL;
-
- /* Spaces and tabs will have been removed by buildargv().
- The directories will there be split into a list but
- each entry may still contain DIRNAME_SEPARATOR. */
- if (parse_separators)
- separator = strchr (name, DIRNAME_SEPARATOR);
-
- if (separator == 0)
- p = arg = name + strlen (name);
- else
- {
- p = separator;
- arg = p + 1;
- while (*arg == DIRNAME_SEPARATOR)
- ++arg;
- }
-
- /* If there are no more directories in this argument then start
- on the next argument next time round the loop (if any). */
- if (*arg == '\0')
- arg = parse_separators ? argv[++argv_index] : NULL;
- }
-
- /* name is the start of the directory.
- p is the separator (or null) following the end. */
+ /* Spaces and tabs will have been removed by buildargv().
+ NAME is the start of the directory.
+ P is the '\0' following the end. */
+ p = name + strlen (name);
while (!(IS_DIR_SEPARATOR (*name) && p <= name + 1) /* "/" */
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
append:
{
unsigned int len = strlen (name);
+ char tinybuf[2];
p = *which_path;
- while (1)
+ /* FIXME: we should use realpath() or its work-alike
+ before comparing. Then all the code above which
+ removes excess slashes and dots could simply go away. */
+ if (!filename_cmp (p, name))
{
- /* FIXME: strncmp loses in interesting ways on MS-DOS and
- MS-Windows because of case-insensitivity and two different
- but functionally identical slash characters. We need a
- special filesystem-dependent file-name comparison function.
-
- Actually, even on Unix I would use realpath() or its work-
- alike before comparing. Then all the code above which
- removes excess slashes and dots could simply go away. */
- if (!strncmp (p, name, len)
- && (p[len] == '\0' || p[len] == DIRNAME_SEPARATOR))
- {
- /* Found it in the search path, remove old copy. */
- if (p > *which_path)
- p--; /* Back over leading separator. */
- if (prefix > p - *which_path)
- goto skip_dup; /* Same dir twice in one cmd. */
- strcpy (p, &p[len + 1]); /* Copy from next \0 or : */
- }
- p = strchr (p, DIRNAME_SEPARATOR);
- if (p != 0)
- ++p;
- else
- break;
+ /* Found it in the search path, remove old copy. */
+ if (p > *which_path)
+ p--; /* Back over leading separator. */
+ if (prefix > p - *which_path)
+ goto skip_dup; /* Same dir twice in one cmd. */
+ memmove (p, &p[len + 1], strlen (&p[len + 1]) + 1); /* Copy from next \0 or : */
}
- if (p == 0)
- {
- char tinybuf[2];
- tinybuf[0] = DIRNAME_SEPARATOR;
- tinybuf[1] = '\0';
+ tinybuf[0] = DIRNAME_SEPARATOR;
+ tinybuf[1] = '\0';
- /* If we have already tacked on a name(s) in this command,
- be sure they stay on the front as we tack on some
- 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);
- }
- else
- {
- *which_path = concat (name, (old[0] ? tinybuf : old),
- old, (char *)NULL);
- prefix = strlen (name);
- }
- xfree (old);
- old = *which_path;
+ /* If we have already tacked on a name(s) in this command,
+ be sure they stay on the front as we tack on some
+ 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);
}
+ else
+ {
+ *which_path = concat (name, (old[0] ? tinybuf : old),
+ old, (char *)NULL);
+ prefix = strlen (name);
+ }
+ xfree (old);
+ old = *which_path;
}
skip_dup:
+ ;
}
- while (arg != NULL);
+
+ do_cleanups (back_to);
}
{
int fd;
char *filename;
- const char *p;
- const char *p1;
- int len;
int alloclen;
+ VEC (char_ptr) *dir_vec;
+ struct cleanup *back_to;
+ int ix;
+ char *dir;
/* The open syscall MODE parameter is not specified. */
gdb_assert ((mode & O_CREAT) == 0);
alloclen = strlen (path) + strlen (string) + 2;
filename = alloca (alloclen);
fd = -1;
- for (p = path; p; p = p1 ? p1 + 1 : 0)
+
+ dir_vec = dirnames_to_char_ptr_vec (path);
+ back_to = make_cleanup_free_char_ptr_vec (dir_vec);
+
+ for (ix = 0; VEC_iterate (char_ptr, dir_vec, ix, dir); ++ix)
{
- p1 = strchr (p, DIRNAME_SEPARATOR);
- if (p1)
- len = p1 - p;
- else
- len = strlen (p);
+ size_t len = strlen (dir);
- if (len == 4 && p[0] == '$' && p[1] == 'c'
- && p[2] == 'w' && p[3] == 'd')
+ if (strcmp (dir, "$cwd") == 0)
{
/* Name is $cwd -- insert current directory name instead. */
int newlen;
}
strcpy (filename, current_directory);
}
+ else if (strchr(dir, '~'))
+ {
+ /* See whether we need to expand the tilde. */
+ int newlen;
+ char *tilde_expanded;
+
+ tilde_expanded = tilde_expand (dir);
+
+ /* First, realloc the filename buffer if too short. */
+ len = strlen (tilde_expanded);
+ newlen = len + strlen (string) + 2;
+ if (newlen > alloclen)
+ {
+ alloclen = newlen;
+ filename = alloca (alloclen);
+ }
+ strcpy (filename, tilde_expanded);
+ xfree (tilde_expanded);
+ }
else
{
/* Normal file name in path -- just use it. */
- strncpy (filename, p, len);
- filename[len] = 0;
+ strcpy (filename, dir);
/* Don't search $cdir. It's also a magic path like $cwd, but we
don't have enough information to expand it. The user *could*
contexts. If the user really has '$cdir' one can use './$cdir'.
We can get $cdir when loading scripts. When loading source files
$cdir must have already been expanded to the correct value. */
- if (strcmp (filename, "$cdir") == 0)
+ if (strcmp (dir, "$cdir") == 0)
continue;
}
}
}
+ do_cleanups (back_to);
+
done:
if (filename_opened)
{
return new_path;
}
-/* This function is capable of finding the absolute path to a
- source file, and opening it, provided you give it a FILENAME. Both the
- DIRNAME and FULLNAME are only added suggestions on where to find the file.
-
- FILENAME should be the filename to open.
- DIRNAME is the compilation directory of a particular source file.
- Only some debug formats provide this info.
- FULLNAME can be the last known absolute path to the file in question.
- Space for the path must have been malloc'd. If a path substitution
- is applied we free the old value and set a new one.
-
- On Success
- A valid file descriptor is returned (the return value is positive).
- FULLNAME is set to the absolute path to the file just opened.
- The caller is responsible for freeing FULLNAME.
-
- On Failure
- An invalid file descriptor is returned (the return value is negative).
- FULLNAME is set to NULL. */
-
int
find_and_open_source (const char *filename,
const char *dirname,
result = open (*fullname, OPEN_MODE);
if (result >= 0)
- return result;
+ {
+ /* Call xfullpath here to be consistent with openp
+ which we use below. */
+ char *lpath = xfullpath (*fullname);
+
+ xfree (*fullname);
+ *fullname = lpath;
+ return result;
+ }
+
/* Didn't work -- free old one, try again. */
xfree (*fullname);
*fullname = NULL;
If this function fails to find the file that this symtab represents,
NULL will be returned and s->fullname will be set to NULL. */
+
char *
symtab_to_fullname (struct symtab *s)
{
if (!s)
return NULL;
- /* Don't check s->fullname here, the file could have been
- deleted/moved/..., look for it again. */
+ /* Use cached copy if we have it.
+ We rely on forget_cached_source_info being called appropriately
+ to handle cases like the file being moved. */
+ if (s->fullname)
+ return s->fullname;
+
r = find_and_open_source (s->filename, s->dirname, &s->fullname);
if (r >= 0)
if (mtime && mtime < st.st_mtime)
warning (_("Source file is more recent than executable."));
-#ifdef LSEEK_NOT_LINEAR
- {
- char c;
-
- /* Have to read it byte by byte to find out where the chars live. */
-
- line_charpos[0] = lseek (desc, 0, SEEK_CUR);
- nlines = 1;
- while (myread (desc, &c, 1) > 0)
- {
- if (c == '\n')
- {
- if (nlines == lines_allocated)
- {
- lines_allocated *= 2;
- line_charpos =
- (int *) xrealloc ((char *) line_charpos,
- sizeof (int) * lines_allocated);
- }
- line_charpos[nlines++] = lseek (desc, 0, SEEK_CUR);
- }
- }
- }
-#else /* lseek linear. */
{
struct cleanup *old_cleanups;
}
do_cleanups (old_cleanups);
}
-#endif /* lseek linear. */
+
s->nlines = nlines;
s->line_charpos =
(int *) xrealloc ((char *) line_charpos, nlines * sizeof (int));
}
-/* Return the character position of a line LINE in symtab S.
- Return 0 if anything is invalid. */
-
-#if 0 /* Currently unused */
-
-int
-source_line_charpos (struct symtab *s, int line)
-{
- if (!s)
- return 0;
- if (!s->line_charpos || line <= 0)
- return 0;
- if (line > s->nlines)
- line = s->nlines;
- return s->line_charpos[line - 1];
-}
-
-/* Return the line number of character position POS in symtab S. */
-
-int
-source_charpos_line (struct symtab *s, int chr)
-{
- int line = 0;
- int *lnp;
-
- if (s == 0 || s->line_charpos == 0)
- return 0;
- lnp = s->line_charpos;
- /* Files are usually short, so sequential search is Ok. */
- while (line < s->nlines && *lnp <= chr)
- {
- line++;
- lnp++;
- }
- if (line >= s->nlines)
- line = s->nlines;
- return line;
-}
-
-#endif /* 0 */
\f
/* Get full pathname and line number positions for a symtab.
FILE *stream;
int nlines = stopline - line;
struct cleanup *cleanup;
+ struct ui_out *uiout = current_uiout;
/* Regardless of whether we can open the file, set current_source_symtab. */
current_source_symtab = s;
print_sys_errmsg (name, errno);
}
else
- ui_out_field_int (uiout, "line", line);
- ui_out_text (uiout, "\tin ");
- ui_out_field_string (uiout, "file", s->filename);
- ui_out_text (uiout, "\n");
+ {
+ ui_out_field_int (uiout, "line", line);
+ ui_out_text (uiout, "\tin ");
+ ui_out_field_string (uiout, "file", s->filename);
+ ui_out_text (uiout, "\n");
+ }
return;
}
struct symtab_and_line sal;
CORE_ADDR start_pc, end_pc;
int i;
+ struct cleanup *cleanups;
init_sal (&sal); /* initialize to zeroes */
if (arg == 0)
{
sal.symtab = current_source_symtab;
+ sal.pspace = current_program_space;
sal.line = last_line_listed;
sals.nelts = 1;
sals.sals = (struct symtab_and_line *)
}
else
{
- sals = decode_line_spec_1 (arg, 0);
+ sals = decode_line_spec_1 (arg, DECODE_LINE_LIST_MODE);
dont_repeat ();
}
+ cleanups = make_cleanup (xfree, sals.sals);
+
/* C++ More than one line may have been specified, as when the user
specifies an overloaded function name. Print info on them all. */
for (i = 0; i < sals.nelts; i++)
{
sal = sals.sals[i];
+ if (sal.pspace != current_program_space)
+ continue;
if (sal.symtab == 0)
{
printf_filtered (_("Line number %d is out of range for \"%s\".\n"),
sal.line, sal.symtab->filename);
}
- xfree (sals.sals);
+ do_cleanups (cleanups);
}
\f
/* Commands to search the source file for a regexp. */