Re: gdb_realpath: dealing with ./ and ../

Doug Evans
2008-01-04T21:40:33Z

[-- Attachment #1: Type: text/plain, Size: 604 bytes --]

The use of #line in the testcases in the appended patch is
questionable, but as a data point the testcases fail without the patch
and pass with the patch. These versions of the testcases have been
amended to use substitute-path.

ref: pr 2360
http://sourceware.org/ml/gdb/2007-11/msg00138.html
http://sourceware.org/ml/gdb-patches/2007-11/msg00314.html

Maybe #line + substitute-path fixup isn't supported.
Again, this patch is just a data point.

Note: This patch contains the rewrite_subfile_path suggestion of my
previous email. I don't know whether it helps or hurts the case
you're trying to fix.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: rewrite-path-3.patch --]
[-- Type: text/x-patch; name=rewrite-path-3.patch, Size: 12986 bytes --]

Index: buildsym.c
===================================================================
RCS file: /cvs/src/src/gdb/buildsym.c,v
retrieving revision 1.59
diff -u -p -u -p -r1.59 buildsym.c
--- buildsym.c 1 Jan 2008 22:53:09 -0000 1.59
+++ buildsym.c 4 Jan 2008 21:26:11 -0000
@@ -44,6 +44,7 @@
#include "cp-support.h"
#include "dictionary.h"
#include "addrmap.h"
+#include "source.h"

/* Ask buildsym.h to define the vars it normally declares `extern'. */
#define EXTERN
@@ -86,6 +87,7 @@ static struct obstack pending_addrmap_ob
static int pending_addrmap_interesting;

\f
+static char *rewrite_subfile_path (char *name, char* dirname);
static int compare_line_numbers (const void *ln1p, const void *ln2p);
\f

@@ -574,6 +576,20 @@ make_blockvector (struct objfile *objfil
return (blockvector);
}
\f
+
+/* Workaround for IS_ABSOLUTE_PATH issue. When gdb is configured for
+ *ix, and we are debugging binary cross-compiled on windows, the original
+ IS_ABSOLUTE_PATH will always return 0. This is not good. */
+#undef IS_ABSOLUTE_PATH
+#undef IS_DIR_SEPARATOR
+
+#define IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == '\\')
+/* Note that IS_ABSOLUTE_PATH accepts d:foo as well, although it is
+ only semi-absolute. This is because the users of IS_ABSOLUTE_PATH
+ want to know whether to prepend the current working directory to
+ a file name, which should not be done with a name like d:foo. */
+#define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0]) || (((f)[0]) && ((f)[1] == ':')))
+
/* Start recording information about source code that came from an
included (or otherwise merged-in) source file with a different
name. NAME is the name of the file (cannot be NULL), DIRNAME is
@@ -583,35 +599,32 @@ void
start_subfile (char *name, char *dirname)
{
struct subfile *subfile;
+ /* Rewritten NAME, typically an absolute path, that is used to detect
+ identical subfiles. */
+ char *comparable_name;
+
+ comparable_name = rewrite_subfile_path (name, dirname);

/* See if this subfile is already known as a subfile of the current
main source file. */

for (subfile = subfiles; subfile; subfile = subfile->next)
{
- char *subfile_name;
-
- /* 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)
- && subfile->dirname != NULL)
- subfile_name = concat (subfile->dirname, SLASH_STRING,
- subfile->name, NULL);
- else
- subfile_name = subfile->name;
+ char *subfile_name = rewrite_subfile_path (subfile->name,
+ subfile->dirname);

- if (FILENAME_CMP (subfile_name, name) == 0)
+ if (FILENAME_CMP (subfile_name, comparable_name) == 0)
{
current_subfile = subfile;
- if (subfile_name != subfile->name)
- xfree (subfile_name);
+ xfree (comparable_name);
+ xfree (subfile_name);
return;
}
- if (subfile_name != subfile->name)
- xfree (subfile_name);
+ xfree (subfile_name);
}

+ xfree (comparable_name);
+
/* This subfile is not known. Add an entry for it. Make an entry
for this subfile in the list of all subfiles of the current main
source file. */
@@ -681,6 +694,34 @@ start_subfile (char *name, char *dirname
}
}

+/* Subroutine of start_subfile to simplify it.
+ Convert NAME, DIRNAME to a form that can be used to watch for
+ identical subfiles.
+ Space for the result is malloc'd, caller must free. */
+
+static char *
+rewrite_subfile_path (char *name, char *dirname)
+{
+ char *p = name;
+ char *rwname;
+
+ if (! IS_ABSOLUTE_PATH (name)
+ && dirname != NULL)
+ p = concat (dirname, SLASH_STRING, name, NULL);
+
+ rwname = rewrite_source_path (p);
+
+ if (rwname != NULL)
+ {
+ if (p != name)
+ xfree (p);
+ return rwname;
+ }
+ if (p != name)
+ return p;
+ return xstrdup (name);
+}
+
/* For stabs readers, the first N_SO symbol is assumed to be the
source file name, and the subfile struct is initialized using that
assumption. If another N_SO symbol is later seen, immediately
Index: source.c
===================================================================
RCS file: /cvs/src/src/gdb/source.c,v
retrieving revision 1.83
diff -u -p -u -p -r1.83 source.c
--- source.c 1 Jan 2008 22:53:13 -0000 1.83
+++ source.c 4 Jan 2008 21:26:11 -0000
@@ -895,10 +895,12 @@ get_substitute_path_rule (const char *pa
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);
+ const struct substitute_path_rule *rule = (path != NULL) ?
+ get_substitute_path_rule (path):
+ NULL;
char *new_path;
int from_len;

@@ -999,10 +1001,11 @@ find_and_open_source (struct objfile *ob
strcat (path + len, source_path + len + cdir_len); /* After $cdir */
}
}
- else
+
+ if (IS_ABSOLUTE_PATH (filename))
{
- /* If dirname is NULL, chances are the path is embedded in
- the filename. Try the source path substitution on it. */
+ /* If filename is absolute path, try the source path
+ substitution on it. */
char *rewritten_filename = rewrite_source_path (filename);

if (rewritten_filename != NULL)
Index: source.h
===================================================================
RCS file: /cvs/src/src/gdb/source.h,v
retrieving revision 1.9
diff -u -p -u -p -r1.9 source.h
--- source.h 1 Jan 2008 22:53:13 -0000 1.9
+++ source.h 4 Jan 2008 21:26:11 -0000
@@ -66,4 +66,14 @@ extern struct symtab_and_line set_curren

/* Reset any information stored about a default file and line to print. */
extern void clear_current_source_symtab_and_line (void);
+
+/* If the user specified a source path substitution rule that applies
+ to PATH, then apply it and return the new path. This new path must
+ be deallocated afterwards.
+
+ Return NULL if no substitution rule was specified by the user,
+ or if no rule applied to the given PATH. */
+
+extern char *rewrite_source_path (const char *path);
+
#endif
Index: testsuite/gdb.base/hashline1.exp
===================================================================
RCS file: testsuite/gdb.base/hashline1.exp
diff -N testsuite/gdb.base/hashline1.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/hashline1.exp 4 Jan 2008 21:26:18 -0000
@@ -0,0 +1,60 @@
+# Copyright 2007 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the gdb testsuite.
+
+# Test loading of line number information with absolute path in #line, bug 2360.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+set prms_id 2360
+set bug_id 0
+
+# srcfile is in objdir because we need to machine generate it in order
+# to get correct the correct path in the #line directive.
+
+set testfile "hashline1"
+set srcfile "${testfile}.c"
+set binfile "${objdir}/${subdir}/${testfile}"
+
+set fd [open ${objdir}/${subdir}/${srcfile} w]
+puts $fd "#line 2 \"[pwd]/${subdir}/${srcfile}\""
+puts $fd "int main () { return 0; } /* set breakpoint here */"
+close $fd
+
+# The choice of path name for the source file is important in order to
+# trigger the bug. Using ${objdir}/${subdir}/${srcfile} here won't trigger
+# the bug.
+if { [gdb_compile "./${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested hashline1.exp
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+set bp_location [gdb_get_line_number "set breakpoint here" ${objdir}/${subdir}/${srcfile}]
+
+# Try to set a breakpoint on the specified file location.
+
+gdb_test "set substitute-path [pwd]/. [pwd]" "" ""
+
+gdb_test "break $srcfile:$bp_location" \
+ "Breakpoint.*at.* file .*$srcfile, line.*" \
+ "set breakpoint"
Index: testsuite/gdb.base/hashline2.exp
===================================================================
RCS file: testsuite/gdb.base/hashline2.exp
diff -N testsuite/gdb.base/hashline2.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/hashline2.exp 4 Jan 2008 21:26:18 -0000
@@ -0,0 +1,58 @@
+# Copyright 2007 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the gdb testsuite.
+
+# Test loading of line number information with an absolute path with extra
+# /'s in #line, bug 2360.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+set prms_id 2360
+set bug_id 0
+
+# srcfile is in objdir because we need to machine generate it in order
+# to get correct the correct path in the #line directive.
+
+set testfile "hashline2"
+set srcfile "${testfile}.c"
+set binfile "${objdir}/${subdir}/${testfile}"
+
+set fd [open ${objdir}/${subdir}/${srcfile} w]
+puts $fd "#line 2 \"///[pwd]/${subdir}/${srcfile}\""
+puts $fd "int main () { return 0; } /* set breakpoint here */"
+close $fd
+
+if { [gdb_compile "${objdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested hashline1.exp
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+set bp_location [gdb_get_line_number "set breakpoint here" ${objdir}/${subdir}/${srcfile}]
+
+# Try to set a breakpoint on the specified file location.
+
+gdb_test "set substitute-path ///[pwd] [pwd]" "" ""
+
+gdb_test "break $srcfile:$bp_location" \
+ "Breakpoint.*at.* file .*$srcfile, line.*" \
+ "set breakpoint"
Index: testsuite/gdb.base/hashline3.exp
===================================================================
RCS file: testsuite/gdb.base/hashline3.exp
diff -N testsuite/gdb.base/hashline3.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/hashline3.exp 4 Jan 2008 21:26:18 -0000
@@ -0,0 +1,57 @@
+# Copyright 2007 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the gdb testsuite.
+
+# Test loading of line number information with relative path in #line, bug 2360.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+set prms_id 2360
+set bug_id 0
+
+# srcfile is in objdir because we need to machine generate it in order
+# to get correct the correct path in the #line directive.
+
+set testfile "hashline3"
+set srcfile "${testfile}.c"
+set binfile "${objdir}/${subdir}/${testfile}"
+
+set fd [open ${objdir}/${subdir}/${srcfile} w]
+puts $fd "#line 2 \"./${subdir}/${srcfile}\""
+puts $fd "int main () { return 0; } /* set breakpoint here */"
+close $fd
+
+if { [gdb_compile "${objdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested hashline1.exp
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+set bp_location [gdb_get_line_number "set breakpoint here" ${objdir}/${subdir}/${srcfile}]
+
+# Try to set a breakpoint on the specified file location.
+
+gdb_test "set substitute-path ${objdir}/. ${objdir}" "" ""
+
+gdb_test "break $srcfile:$bp_location" \
+ "Breakpoint.*at.* file .*$srcfile, line.*" \
+ "set breakpoint"