Re: [RFC] new substitute path when loading feature

Daniel Jacobowitz
2008-05-15T16:06:27Z

On Tue, May 13, 2008 at 03:20:41PM -0400, Daniel Jacobowitz wrote:
> On Tue, May 13, 2008 at 03:11:22PM -0400, Aleksandar Ristovski wrote:
> > No, this particular issue is not because of the slashes, but rather
> > due to IS_ABSOLUTE_PATH returning false on a path like "c:/Temp...".
>
> OK. I think I "fixed" FILENAME_CMP and not IS_ABSOLUTE_PATH, but it
> would not be hard to do both.
>
> I'll try to post something tonight.

Sorry, my existing patch was a mess so I had to rewrite it. I haven't
really tested this; it doesn't break a native Linux GDB in any case
that I consider significant. See the comments in defs.h and utils.c
for the details.

Does this fix the same problem you're working on? Does anyone see a
problem with the compromises I made here? Eli, I'd appreciate your
opinion.

--
Daniel Jacobowitz
CodeSourcery

2008-05-15 Daniel Jacobowitz <dan@codesourcery.com>

* defs.h (GDB_IS_DIR_SEPARATOR, GDB_IS_ABSOLUTE_PATH)
(GDB_FILENAME_CMP): New macros.
(gdb_filename_cmp): Declare.
* buildsym.c, dwarf2read.c, solib.c, source.c, symtab.c: Use the
new macros.
* utils.c (ldirname): Likewise.
(gdb_filename_cmp): New function.

Index: buildsym.c
===================================================================
RCS file: /cvs/src/src/gdb/buildsym.c,v
retrieving revision 1.60
diff -u -p -r1.60 buildsym.c
--- buildsym.c 17 Apr 2008 17:54:04 -0000 1.60
+++ buildsym.c 15 May 2008 15:41:01 -0000
@@ -593,15 +593,15 @@ start_subfile (char *name, char *dirname

/* If NAME is an absolute path, and this subfile is not, then
attempt to create an absolute path to compare. */
- if (IS_ABSOLUTE_PATH (name)
- && !IS_ABSOLUTE_PATH (subfile->name)
+ if (GDB_IS_ABSOLUTE_PATH (name)
+ && !GDB_IS_ABSOLUTE_PATH (subfile->name)
&& subfile->dirname != NULL)
subfile_name = concat (subfile->dirname, SLASH_STRING,
subfile->name, NULL);
else
subfile_name = subfile->name;

- if (FILENAME_CMP (subfile_name, name) == 0)
+ if (GDB_FILENAME_CMP (subfile_name, name) == 0)
{
current_subfile = subfile;
if (subfile_name != subfile->name)
Index: defs.h
===================================================================
RCS file: /cvs/src/src/gdb/defs.h,v
retrieving revision 1.223
diff -u -p -r1.223 defs.h
--- defs.h 3 May 2008 22:20:13 -0000 1.223
+++ defs.h 15 May 2008 15:41:02 -0000
@@ -374,6 +374,24 @@ ULONGEST strtoulst (const char *num, con

char *ldirname (const char *filename);

+/* Versions of the filenames.h macros to use with filenames from debug
+ information, when the program may have been compiled on a DOS
+ filesystem even if GDB is running on a POSIX host. */
+
+/* Recognizing backslashes as directory separators has a low false
+ positive rate, because POSIX filenames rarely include them. They
+ are likely to appear in full paths in debug information. */
+#define GDB_IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == '\\')
+
+/* Recognizing drive letters as absolute path prefixes has a low false
+ positive rate, because POSIX directories are rarely named "c:". We
+ must not prepend a directory prefix to drive letters. */
+#define GDB_IS_ABSOLUTE_PATH(f) \
+ (GDB_IS_DIR_SEPARATOR ((f)[0]) || (((f)[0]) && ((f)[1] == ':')))
+
+#define GDB_FILENAME_CMP(lhs, rhs) gdb_filename_cmp (lhs, rhs)
+int gdb_filename_cmp (const char *lhs, const char *rhs);
+
/* From demangle.c */

extern void set_demangling_style (char *);
Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.263
diff -u -p -r1.263 dwarf2read.c
--- dwarf2read.c 5 May 2008 14:37:32 -0000 1.263
+++ dwarf2read.c 15 May 2008 15:41:02 -0000
@@ -2832,7 +2832,7 @@ read_file_scope (struct die_info *die, s
attr = dwarf2_attr (die, DW_AT_comp_dir, cu);
if (attr)
comp_dir = DW_STRING (attr);
- else if (name != NULL && IS_ABSOLUTE_PATH (name))
+ else if (name != NULL && GDB_IS_ABSOLUTE_PATH (name))
{
comp_dir = ldirname (name);
if (comp_dir != NULL)
@@ -7186,14 +7186,14 @@ dwarf_decode_lines (struct line_header *
if (fe.dir_index)
dir_name = lh->include_dirs[fe.dir_index - 1];

- if (!IS_ABSOLUTE_PATH (include_name) && dir_name != NULL)
+ if (!GDB_IS_ABSOLUTE_PATH (include_name) && dir_name != NULL)
{
include_name = concat (dir_name, SLASH_STRING,
include_name, (char *)NULL);
make_cleanup (xfree, include_name);
}

- if (!IS_ABSOLUTE_PATH (pst_filename) && pst->dirname != NULL)
+ if (!GDB_IS_ABSOLUTE_PATH (pst_filename) && pst->dirname != NULL)
{
pst_filename = concat (pst->dirname, SLASH_STRING,
pst_filename, (char *)NULL);
@@ -7274,7 +7274,7 @@ dwarf2_start_subfile (char *filename, ch
that represent full path names''. Thus ignoring dirname in the
`else' branch below isn't an issue. */

- if (!IS_ABSOLUTE_PATH (filename) && dirname != NULL)
+ if (!GDB_IS_ABSOLUTE_PATH (filename) && dirname != NULL)
fullname = concat (dirname, SLASH_STRING, filename, (char *)NULL);
else
fullname = filename;
@@ -9502,7 +9502,7 @@ file_full_name (int file, struct line_he
{
struct file_entry *fe = &lh->file_names[file - 1];

- if (IS_ABSOLUTE_PATH (fe->name))
+ if (GDB_IS_ABSOLUTE_PATH (fe->name))
return xstrdup (fe->name);
else
{
Index: solib.c
===================================================================
RCS file: /cvs/src/src/gdb/solib.c,v
retrieving revision 1.101
diff -u -p -r1.101 solib.c
--- solib.c 7 Jan 2008 15:19:58 -0000 1.101
+++ solib.c 15 May 2008 15:41:02 -0000
@@ -150,7 +150,7 @@ solib_open (char *in_pathname, char **fo

gdb_sysroot_is_empty = (gdb_sysroot == NULL || *gdb_sysroot == 0);

- if (! IS_ABSOLUTE_PATH (in_pathname) || gdb_sysroot_is_empty)
+ if (! GDB_IS_ABSOLUTE_PATH (in_pathname) || gdb_sysroot_is_empty)
temp_pathname = in_pathname;
else
{
@@ -186,14 +186,14 @@ solib_open (char *in_pathname, char **fo
absolute at this point, make it relative. (openp will try and open the
file according to its absolute path otherwise, which is not what we want.)
Affects subsequent searches for this solib. */
- if (found_file < 0 && IS_ABSOLUTE_PATH (in_pathname))
+ if (found_file < 0 && GDB_IS_ABSOLUTE_PATH (in_pathname))
{
/* First, get rid of any drive letters etc. */
- while (!IS_DIR_SEPARATOR (*in_pathname))
+ while (!GDB_IS_DIR_SEPARATOR (*in_pathname))
in_pathname++;

/* Next, get rid of all leading dir separators. */
- while (IS_DIR_SEPARATOR (*in_pathname))
+ while (GDB_IS_DIR_SEPARATOR (*in_pathname))
in_pathname++;
}

Index: source.c
===================================================================
RCS file: /cvs/src/src/gdb/source.c,v
retrieving revision 1.88
diff -u -p -r1.88 source.c
--- source.c 3 May 2008 06:13:21 -0000 1.88
+++ source.c 15 May 2008 15:41:03 -0000
@@ -700,7 +700,7 @@ openp (const char *path, int opts, const

mode |= O_BINARY;

- if ((opts & OPF_TRY_CWD_FIRST) || IS_ABSOLUTE_PATH (string))
+ if ((opts & OPF_TRY_CWD_FIRST) || GDB_IS_ABSOLUTE_PATH (string))
{
int i;

@@ -720,16 +720,16 @@ openp (const char *path, int opts, const

if (!(opts & OPF_SEARCH_IN_PATH))
for (i = 0; string[i]; i++)
- if (IS_DIR_SEPARATOR (string[i]))
+ if (GDB_IS_DIR_SEPARATOR (string[i]))
goto done;
}

/* /foo => foo, to avoid multiple slashes that Emacs doesn't like. */
- while (IS_DIR_SEPARATOR(string[0]))
+ while (GDB_IS_DIR_SEPARATOR(string[0]))
string++;

/* ./foo => foo */
- while (string[0] == '.' && IS_DIR_SEPARATOR (string[1]))
+ while (string[0] == '.' && GDB_IS_DIR_SEPARATOR (string[1]))
string += 2;

alloclen = strlen (path) + strlen (string) + 2;
@@ -861,14 +861,14 @@ substitute_path_rule_matches (const stru
strncpy (path_start, path, from_len);
path_start[from_len] = '\0';

- if (FILENAME_CMP (path_start, rule->from) != 0)
+ if (GDB_FILENAME_CMP (path_start, rule->from) != 0)
return 0;

/* Make sure that the region in the path that matches the substitution
rule is immediately followed by a directory separator (or the end of
string character). */

- if (path[from_len] != '\0' && !IS_DIR_SEPARATOR (path[from_len]))
+ if (path[from_len] != '\0' && !GDB_IS_DIR_SEPARATOR (path[from_len]))
return 0;

return 1;
@@ -1004,7 +1004,7 @@ find_and_open_source (struct objfile *ob
}
}

- if (IS_ABSOLUTE_PATH (filename))
+ if (GDB_IS_ABSOLUTE_PATH (filename))
{
/* If filename is absolute path, try the source path
substitution on it. */
@@ -1721,7 +1721,7 @@ strip_trailing_directory_separator (char
if (last < 0)
return; /* No stripping is needed if PATH is the empty string. */

- if (IS_DIR_SEPARATOR (path[last]))
+ if (GDB_IS_DIR_SEPARATOR (path[last]))
path[last] = '\0';
}

@@ -1735,7 +1735,7 @@ find_substitute_path_rule (const char *f

while (rule != NULL)
{
- if (FILENAME_CMP (rule->from, from) == 0)
+ if (GDB_FILENAME_CMP (rule->from, from) == 0)
return rule;
rule = rule->next;
}
@@ -1831,7 +1831,7 @@ show_substitute_path_command (char *args

while (rule != NULL)
{
- if (from == NULL || FILENAME_CMP (rule->from, from) == 0)
+ if (from == NULL || GDB_FILENAME_CMP (rule->from, from) == 0)
printf_filtered (" `%s' -> `%s'.\n", rule->from, rule->to);
rule = rule->next;
}
@@ -1871,7 +1871,7 @@ unset_substitute_path_command (char *arg
{
struct substitute_path_rule *next = rule->next;

- if (from == NULL || FILENAME_CMP (from, rule->from) == 0)
+ if (from == NULL || GDB_FILENAME_CMP (from, rule->from) == 0)
{
delete_substitute_path_rule (rule);
rule_found = 1;
Index: symtab.c
===================================================================
RCS file: /cvs/src/src/gdb/symtab.c,v
retrieving revision 1.181
diff -u -p -r1.181 symtab.c
--- symtab.c 5 May 2008 14:37:32 -0000 1.181
+++ symtab.c 15 May 2008 15:41:03 -0000
@@ -187,7 +187,7 @@ got_symtab:

ALL_SYMTABS (objfile, s)
{
- if (FILENAME_CMP (name, s->filename) == 0)
+ if (GDB_FILENAME_CMP (name, s->filename) == 0)
{
return s;
}
@@ -198,7 +198,7 @@ got_symtab:
if (full_path != NULL)
{
const char *fp = symtab_to_fullname (s);
- if (fp != NULL && FILENAME_CMP (full_path, fp) == 0)
+ if (fp != NULL && GDB_FILENAME_CMP (full_path, fp) == 0)
{
return s;
}
@@ -211,7 +211,7 @@ got_symtab:
{
char *rp = gdb_realpath (fullname);
make_cleanup (xfree, rp);
- if (FILENAME_CMP (real_path, rp) == 0)
+ if (GDB_FILENAME_CMP (real_path, rp) == 0)
{
return s;
}
@@ -224,7 +224,7 @@ got_symtab:
if (lbasename (name) == name)
ALL_SYMTABS (objfile, s)
{
- if (FILENAME_CMP (lbasename (s->filename), name) == 0)
+ if (GDB_FILENAME_CMP (lbasename (s->filename), name) == 0)
return s;
}

@@ -279,7 +279,7 @@ lookup_partial_symtab (const char *name)

ALL_PSYMTABS (objfile, pst)
{
- if (FILENAME_CMP (name, pst->filename) == 0)
+ if (GDB_FILENAME_CMP (name, pst->filename) == 0)
{
return (pst);
}
@@ -290,7 +290,7 @@ lookup_partial_symtab (const char *name)
{
psymtab_to_fullname (pst);
if (pst->fullname != NULL
- && FILENAME_CMP (full_path, pst->fullname) == 0)
+ && GDB_FILENAME_CMP (full_path, pst->fullname) == 0)
{
return pst;
}
@@ -305,7 +305,7 @@ lookup_partial_symtab (const char *name)
rp = gdb_realpath (pst->fullname);
make_cleanup (xfree, rp);
}
- if (rp != NULL && FILENAME_CMP (real_path, rp) == 0)
+ if (rp != NULL && GDB_FILENAME_CMP (real_path, rp) == 0)
{
return pst;
}
@@ -317,7 +317,7 @@ lookup_partial_symtab (const char *name)
if (lbasename (name) == name)
ALL_PSYMTABS (objfile, pst)
{
- if (FILENAME_CMP (lbasename (pst->filename), name) == 0)
+ if (GDB_FILENAME_CMP (lbasename (pst->filename), name) == 0)
return (pst);
}

Index: utils.c
===================================================================
RCS file: /cvs/src/src/gdb/utils.c,v
retrieving revision 1.187
diff -u -p -r1.187 utils.c
--- utils.c 24 Apr 2008 11:13:44 -0000 1.187
+++ utils.c 15 May 2008 15:41:03 -0000
@@ -3205,7 +3205,7 @@ ldirname (const char *filename)
const char *base = lbasename (filename);
char *dirname;

- while (base > filename && IS_DIR_SEPARATOR (base[-1]))
+ while (base > filename && GDB_IS_DIR_SEPARATOR (base[-1]))
--base;

if (base == filename)
@@ -3214,12 +3214,43 @@ ldirname (const char *filename)
dirname = xmalloc (base - filename + 2);
memcpy (dirname, filename, base - filename);

- /* On DOS based file systems, convert "d:foo" to "d:.", so that we
+ /* For DOS based file systems, convert "d:foo" to "d:.", so that we
create "d:./bar" later instead of the (different) "d:/bar". */
- if (base - filename == 2 && IS_ABSOLUTE_PATH (base)
- && !IS_DIR_SEPARATOR (filename[0]))
+ if (base - filename == 2 && GDB_IS_ABSOLUTE_PATH (base)
+ && !GDB_IS_DIR_SEPARATOR (filename[0]))
dirname[base++ - filename] = '.';

dirname[base - filename] = '\0';
return dirname;
}
+
+/* Compare two filenames. This version should be used instead of
+ FILENAME_CMP for filenames from debug information; it recognizes
+ equivalences from compiling on a DOS filesystem even if the
+ debugger is running on a POSIX host. */
+
+int
+gdb_filename_cmp (const char *lhs, const char *rhs)
+{
+ for (; *lhs || *rhs; lhs++, rhs++)
+ {
+#ifndef HAVE_DOS_BASED_FILE_SYSTEM
+ /* When debugging on a POSIX host, assume that each filename was
+ recorded with a single consistent capitalization during
+ compilation. Source trees are too likely to contain both
+ main.c and Main.c. */
+ if (*lhs == *rhs)
+ continue;
+#else
+ if (tolower (*lhs) == tolower (*rhs))
+ continue;
+#endif
+
+ if (*lhs == '/' && *rhs == '\\')
+ continue;
+ if (*lhs == '\\' && *rhs == '/')
+ continue;
+ return (int) *lhs - (int) *rhs;
+ }
+ return 0;
+}