/* List lines of source files for GDB, the GNU debugger.
- Copyright (C) 1986-2005, 2007-2012 Free Software Foundation, Inc.
+ Copyright (C) 1986-2013 Free Software Foundation, Inc.
This file is part of GDB.
value);
}
+/* Possible values of 'set filename-display'. */
+static const char filename_display_basename[] = "basename";
+static const char filename_display_relative[] = "relative";
+static const char filename_display_absolute[] = "absolute";
+
+static const char *const filename_display_kind_names[] = {
+ filename_display_basename,
+ filename_display_relative,
+ filename_display_absolute,
+ NULL
+};
+
+static const char *filename_display_string = filename_display_relative;
+
+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);
+}
+
/* Line number of last line printed. Default for various commands.
current_source_line is usually, but not always, the same as this. */
if one exists. */
if (lookup_symbol (main_name (), 0, VAR_DOMAIN, 0))
{
- sals = decode_line_spec (main_name (), DECODE_LINE_FUNFIRSTLINE);
+ sals = decode_line_with_current_source (main_name (),
+ DECODE_LINE_FUNFIRSTLINE);
sal = sals.sals[0];
xfree (sals.sals);
current_source_pspace = sal.pspace;
{
char buf[20];
- sprintf (buf, "$cdir%c$cwd", DIRNAME_SEPARATOR);
+ xsnprintf (buf, sizeof (buf), "$cdir%c$cwd", DIRNAME_SEPARATOR);
source_path = xstrdup (buf);
forget_cached_source_info ();
}
/* Add zero or more directories to the front of the source path. */
-void
+static void
directory_command (char *dirname, int from_tty)
{
dont_repeat ();
{
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: 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_ncmp (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. */
- memmove (p, &p[len + 1], strlen (&p[len + 1]) + 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)
{
- /* If a file was opened, canonicalize its filename. Use xfullpath
- rather than gdb_realpath to avoid resolving the basename part
- of filenames when the associated file is a symbolic link. This
- fixes a potential inconsistency between the filenames known to
- GDB and the filenames it prints in the annotations. */
+ /* If a file was opened, canonicalize its filename. */
if (fd < 0)
*filename_opened = NULL;
else if (IS_ABSOLUTE_PATH (filename))
- *filename_opened = xfullpath (filename);
+ *filename_opened = gdb_realpath (filename);
else
{
/* Beware the // my son, the Emacs barfs, the botch that catch... */
? "" : SLASH_STRING,
filename, (char *)NULL);
- *filename_opened = xfullpath (f);
+ *filename_opened = gdb_realpath (f);
xfree (f);
}
}
Return NULL if no substitution rule was specified by the user,
or if no rule applied to the given PATH. */
-static char *
+char *
rewrite_source_path (const char *path)
{
const struct substitute_path_rule *rule = get_substitute_path_rule (path);
result = open (*fullname, OPEN_MODE);
if (result >= 0)
{
- /* Call xfullpath here to be consistent with openp
- which we use below. */
- char *lpath = xfullpath (*fullname);
+ char *lpath = gdb_realpath (*fullname);
xfree (*fullname);
*fullname = lpath;
/* Finds the fullname that a symtab represents.
- If this functions finds the fullname, it will save it in s->fullname
- and it will also return the value.
+ This functions finds the fullname and saves it in s->fullname.
+ It will also return the value.
If this function fails to find the file that this symtab represents,
- NULL will be returned and s->fullname will be set to NULL. */
+ the expected fullname is used. Therefore the files does not have to
+ exist. */
-char *
+const char *
symtab_to_fullname (struct symtab *s)
{
- int r;
-
- if (!s)
- return NULL;
-
/* 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;
+ if (s->fullname == NULL)
+ {
+ int fd = find_and_open_source (s->filename, s->dirname, &s->fullname);
+
+ if (fd >= 0)
+ close (fd);
+ else
+ {
+ char *fullname;
+ struct cleanup *back_to;
- r = find_and_open_source (s->filename, s->dirname, &s->fullname);
+ /* rewrite_source_path would be applied by find_and_open_source, we
+ should report the pathname where GDB tried to find the file. */
- if (r >= 0)
- {
- close (r);
- return s->fullname;
- }
+ if (s->dirname == NULL || IS_ABSOLUTE_PATH (s->filename))
+ fullname = xstrdup (s->filename);
+ else
+ fullname = concat (s->dirname, SLASH_STRING, s->filename, NULL);
- return NULL;
+ back_to = make_cleanup (xfree, fullname);
+ s->fullname = rewrite_source_path (fullname);
+ if (s->fullname == NULL)
+ s->fullname = xstrdup (fullname);
+ do_cleanups (back_to);
+ }
+ }
+
+ return s->fullname;
+}
+
+/* See commentary in source.h. */
+
+const char *
+symtab_to_filename_for_display (struct symtab *symtab)
+{
+ if (filename_display_string == filename_display_basename)
+ return lbasename (symtab->filename);
+ else if (filename_display_string == filename_display_absolute)
+ return symtab_to_fullname (symtab);
+ else if (filename_display_string == filename_display_relative)
+ return symtab->filename;
+ else
+ internal_error (__FILE__, __LINE__, _("invalid filename_display_string"));
}
\f
/* Create and initialize the table S->line_charpos that records
gdb_assert (s);
line_charpos = (int *) xmalloc (lines_allocated * sizeof (int));
if (fstat (desc, &st) < 0)
- perror_with_name (s->filename);
+ perror_with_name (symtab_to_filename_for_display (s));
if (s->objfile && s->objfile->obfd)
mtime = s->objfile->mtime;
/* Reassign `size' to result of read for systems where \r\n -> \n. */
size = myread (desc, data, size);
if (size < 0)
- perror_with_name (s->filename);
+ perror_with_name (symtab_to_filename_for_display (s));
end = data + size;
p = data;
line_charpos[0] = 0;
/* Print source lines from the file of symtab S,
starting with line number LINE and stopping before line number STOPLINE. */
-static void print_source_lines_base (struct symtab *s, int line, int stopline,
- int noerror);
static void
-print_source_lines_base (struct symtab *s, int line, int stopline, int noerror)
+print_source_lines_base (struct symtab *s, int line, int stopline,
+ enum print_source_lines_flags flags)
{
int c;
int desc;
else
{
desc = last_source_error;
- noerror = 1;
+ flags |= PRINT_SOURCE_LINES_NOERROR;
}
}
else
{
desc = last_source_error;
- noerror = 1;
+ flags |= PRINT_SOURCE_LINES_NOERROR;
noprint = 1;
}
{
last_source_error = desc;
- if (!noerror)
+ if (!(flags & PRINT_SOURCE_LINES_NOERROR))
{
- char *name = alloca (strlen (s->filename) + 100);
- sprintf (name, "%d\t%s", line, s->filename);
+ const char *filename = symtab_to_filename_for_display (s);
+ int len = strlen (filename) + 100;
+ char *name = alloca (len);
+
+ xsnprintf (name, len, "%d\t%s", line, filename);
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);
+
+ /* CLI expects only the "file" field. TUI expects only the
+ "fullname" field (and TUI does break if "file" is printed).
+ MI expects both fields. ui_source_list is set only for CLI,
+ not for TUI. */
+ if (ui_out_is_mi_like_p (uiout)
+ || ui_out_test_flags (uiout, ui_source_list))
+ ui_out_field_string (uiout, "file",
+ symtab_to_filename_for_display (s));
+ if (ui_out_is_mi_like_p (uiout)
+ || !ui_out_test_flags (uiout, ui_source_list))
+ {
+ const char *s_fullname = symtab_to_fullname (s);
+ char *local_fullname;
+
+ /* ui_out_field_string may free S_FULLNAME by calling
+ open_source_file for it again. See e.g.,
+ tui_field_string->tui_show_source. */
+ local_fullname = alloca (strlen (s_fullname) + 1);
+ strcpy (local_fullname, s_fullname);
+
+ ui_out_field_string (uiout, "fullname", local_fullname);
+ }
+
ui_out_text (uiout, "\n");
}
{
close (desc);
error (_("Line number %d out of range; %s has %d lines."),
- line, s->filename, s->nlines);
+ line, symtab_to_filename_for_display (s), s->nlines);
}
if (lseek (desc, s->line_charpos[line - 1], 0) < 0)
{
close (desc);
- perror_with_name (s->filename);
+ perror_with_name (symtab_to_filename_for_display (s));
}
stream = fdopen (desc, FDOPEN_MODE);
if (c == EOF)
break;
last_line_listed = current_source_line;
- sprintf (buf, "%d\t", current_source_line++);
+ if (flags & PRINT_SOURCE_LINES_FILENAME)
+ {
+ ui_out_text (uiout, symtab_to_filename_for_display (s));
+ ui_out_text (uiout, ":");
+ }
+ xsnprintf (buf, sizeof (buf), "%d\t", current_source_line++);
ui_out_text (uiout, buf);
do
{
if (c < 040 && c != '\t' && c != '\n' && c != '\r')
{
- sprintf (buf, "^%c", c + 0100);
+ xsnprintf (buf, sizeof (buf), "^%c", c + 0100);
ui_out_text (uiout, buf);
}
else if (c == 0177)
}
else
{
- sprintf (buf, "%c", c);
+ xsnprintf (buf, sizeof (buf), "%c", c);
ui_out_text (uiout, buf);
}
}
window otherwise it is simply printed. */
void
-print_source_lines (struct symtab *s, int line, int stopline, int noerror)
+print_source_lines (struct symtab *s, int line, int stopline,
+ enum print_source_lines_flags flags)
{
- print_source_lines_base (s, line, stopline, noerror);
+ print_source_lines_base (s, line, stopline, flags);
}
\f
/* Print info on range of pc's in a specified line. */
}
else
{
- sals = decode_line_spec_1 (arg, DECODE_LINE_LIST_MODE);
+ sals = decode_line_with_last_displayed (arg, DECODE_LINE_LIST_MODE);
dont_repeat ();
}
if (start_pc == end_pc)
{
printf_filtered ("Line %d of \"%s\"",
- sal.line, sal.symtab->filename);
+ sal.line,
+ symtab_to_filename_for_display (sal.symtab));
wrap_here (" ");
printf_filtered (" is at address ");
print_address (gdbarch, start_pc, gdb_stdout);
else
{
printf_filtered ("Line %d of \"%s\"",
- sal.line, sal.symtab->filename);
+ sal.line,
+ symtab_to_filename_for_display (sal.symtab));
wrap_here (" ");
printf_filtered (" starts at address ");
print_address (gdbarch, start_pc, gdb_stdout);
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, sal.symtab->filename);
+ sal.line, symtab_to_filename_for_display (sal.symtab));
}
do_cleanups (cleanups);
}
desc = open_source_file (current_source_symtab);
if (desc < 0)
- perror_with_name (current_source_symtab->filename);
+ perror_with_name (symtab_to_filename_for_display (current_source_symtab));
cleanups = make_cleanup_close (desc);
if (current_source_symtab->line_charpos == 0)
error (_("Expression not found"));
if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
- perror_with_name (current_source_symtab->filename);
+ perror_with_name (symtab_to_filename_for_display (current_source_symtab));
discard_cleanups (cleanups);
stream = fdopen (desc, FDOPEN_MODE);
desc = open_source_file (current_source_symtab);
if (desc < 0)
- perror_with_name (current_source_symtab->filename);
+ perror_with_name (symtab_to_filename_for_display (current_source_symtab));
cleanups = make_cleanup_close (desc);
if (current_source_symtab->line_charpos == 0)
error (_("Expression not found"));
if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
- perror_with_name (current_source_symtab->filename);
+ perror_with_name (symtab_to_filename_for_display (current_source_symtab));
discard_cleanups (cleanups);
stream = fdopen (desc, FDOPEN_MODE);
line--;
if (fseek (stream, current_source_symtab->line_charpos[line - 1], 0) < 0)
{
+ const char *filename;
+
do_cleanups (cleanups);
- perror_with_name (current_source_symtab->filename);
+ filename = symtab_to_filename_for_display (current_source_symtab);
+ perror_with_name (filename);
}
}
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 ("reverse-search", class_files, reverse_search_command, _("\
Search backward for regular expression (see regex(3)) from last line listed.\n\
Print the rule for substituting FROM in source file names. If FROM\n\
is not specified, print all substitution rules."),
&showlist);
+
+ add_setshow_enum_cmd ("filename-display", class_files,
+ filename_display_kind_names,
+ &filename_display_string, _("\
+Set how to display filenames."), _("\
+Show how to display filenames."), _("\
+filename-display can be:\n\
+ basename - display only basename of a filename\n\
+ relative - display a filename relative to the compilation directory\n\
+ absolute - display an absolute filename\n\
+By default, relative filenames are displayed."),
+ NULL,
+ show_filename_display_string,
+ &setlist, &showlist);
+
}