Re: [RFA] New substitute-path commands

Joel Brobecker
2006-07-07T19:12:11Z

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

Hi Eli,

> Thanks. My comments are below.

Thanks for your review (and also the effort you made in providing a
description of what a substitution rule is, much appreciated). I have
updated the source as per your comments, as well as reworked the
documentation to include your ideas. I also took the time to include a
small explaination of how this new functionality differs slightly from
the "dir" command. It's not necessary since the explaination can be
deduced from the rest of the documentation, but might make it easier to
figure this out.

2006-07-07 Joel Brobecker <brobecker@adacore.com

* source.c (substitute_path_from): New static variable.
(substitute_path_to): Likewise.
(xrewrite_source_path): New function.
(find_and_open_source): Add source path rewriting support.
(show_substitute_path_command): New function.
(unset_substitute_path_command): New function.
(set_substitute_path_command): New function.
(_initialize_source): Add new substitute-path commands.

Documentation ChangeLog entry:

2006-07-07 Joel Brobecker <brobecker@adacore.com

* gdb.texinfo (Source Path): Add documentation for new
substitute-path commands.

Tested on x86-linux. I forgot to mention that this patch will
also require a small adjustment in the "help unset" test of help.exp.
Will do so immediately.

--
Joel

[-- Attachment #2: subst.diff --]
[-- Type: text/plain, Size: 6915 bytes --]

Index: source.c
===================================================================
RCS file: /cvs/src/src/gdb/source.c,v
retrieving revision 1.75
diff -u -p -r1.75 source.c
--- source.c 15 May 2006 15:50:13 -0000 1.75
+++ source.c 7 Jul 2006 19:02:04 -0000
@@ -73,6 +73,11 @@ static void show_directories (char *, in

char *source_path;

+/* Support for source path substitution commands. */
+
+static char *substitute_path_from = NULL;
+static char *substitute_path_to = NULL;
+
/* Symtab of default file for listing lines of. */

static struct symtab *current_source_symtab;
@@ -828,6 +833,47 @@ source_full_path_of (char *filename, cha
return 1;
}

+/* If the user specified a source path substitution rule, then
+ try applying it on PATH, and return the new path. This new
+ path must be deallocated afterwards.
+
+ Return NULL if no substitution rule was specified by the user,
+ or of this rule didn't apply to the given PATH. */
+
+static char *
+xrewrite_source_path (const char *path)
+{
+ char *from_start;
+ char *new_path;
+
+ /* If no path substitution rule was specified, then no rewrite
+ is actually needed. */
+
+ if (substitute_path_from == NULL)
+ return NULL;
+
+ /* Search for the first occurence of SUBSTITUTE_PATH_FROM.
+ No substitution needed of not found. */
+
+ from_start = strstr (path, substitute_path_from);
+
+ if (from_start == NULL)
+ return NULL;
+
+ /* Compute the rewritten path and return it. */
+
+ new_path = (char *) xmalloc (strlen (path) + 1
+ + strlen (substitute_path_to)
+ - strlen (substitute_path_from));
+ strncpy (new_path, path, from_start - path);
+ strcpy (new_path + (from_start - path),
+ substitute_path_to);
+ strcat (new_path,
+ from_start + strlen (substitute_path_from));
+
+ return new_path;
+}
+
/* This function is capable of finding the absolute path to a
source file, and opening it, provided you give it an
OBJFILE and FILENAME. Both the DIRNAME and FULLNAME are only
@@ -844,7 +890,7 @@ source_full_path_of (char *filename, cha
FULLNAME is set to the absolute path to the file just opened.

On Failure
- A non valid file descriptor is returned. ( the return value is negitive )
+ An invalid file descriptor is returned. ( the return value is negative )
FULLNAME is set to NULL. */
int
find_and_open_source (struct objfile *objfile,
@@ -857,8 +903,22 @@ find_and_open_source (struct objfile *ob
int result;

/* Quick way out if we already know its full name */
+
if (*fullname)
{
+ {
+ /* The user may have requested that source paths be rewritten
+ according to a substitution rule he provided. Check if
+ this is the case, and do the rewrite if appropriate. */
+ char *rewritten_fullname = xrewrite_source_path (*fullname);
+
+ if (rewritten_fullname != NULL)
+ {
+ xfree (*fullname);
+ *fullname = rewritten_fullname;
+ }
+ }
+
result = open (*fullname, OPEN_MODE);
if (result >= 0)
return result;
@@ -869,6 +929,27 @@ find_and_open_source (struct objfile *ob

if (dirname != NULL)
{
+ /* If necessary, rewrite the compilation directory name according
+ to the source path substitution rules specified by the user.
+
+ Normally, we should really try to do the rewrite on the entire
+ path as opposed to just the directory name, but that's making
+ things much more complicated since we now have to concat the
+ dirname and filename, apply the substitution rule, and then do
+ [...] ??? How do we split the path back into dirname and filename?
+ In practice, the source path substitution feature should be used
+ when the entire tree has been moved, in which case only the root
+ part of the tree path will need to be rewritten. So this should
+ not be a problem in practice. */
+
+ char *rewritten_dirname = xrewrite_source_path (dirname);
+
+ if (rewritten_dirname != NULL)
+ {
+ make_cleanup (xfree, rewritten_dirname);
+ dirname = rewritten_dirname;
+ }
+
/* Replace a path entry of $cdir with the compilation directory name */
#define cdir_len 5
/* We cast strstr's result in case an ANSIhole has made it const,
@@ -1587,6 +1668,65 @@ reverse_search_command (char *regex, int
fclose (stream);
return;
}
+
+/* Print the current source path substitution rule. */
+
+static void
+show_substitute_path_command (char *args, int from_tty)
+{
+ if (substitute_path_from == NULL)
+ printf_filtered (_("No source path substitution rule specified.\n"));
+ else
+ printf_filtered (_("`%s' in source paths now substituted with `%s'.\n"),
+ substitute_path_from, substitute_path_to);
+}
+
+/* Delete the current source path substitution rule. */
+
+static void
+unset_substitute_path_command (char *args, int from_tty)
+{
+ if (substitute_path_from != NULL)
+ {
+ xfree (substitute_path_from);
+ substitute_path_from = NULL;
+ }
+
+ if (substitute_path_to != NULL)
+ {
+ xfree (substitute_path_to);
+ substitute_path_to = NULL;
+ }
+}
+
+/* Add a new source path substitution rule. */
+
+static void
+set_substitute_path_command (char *args, int from_tty)
+{
+ char *from_path, *to_path;
+ char **argv = buildargv (args);
+
+ if (argv == NULL || argv[0] == NULL || argv [1] == NULL)
+ error (_("Incorrect usage, too few arguments in command"));
+
+ if (argv[2] != NULL)
+ error (_("Incorrect usage, too many arguments in command"));
+
+ /* Remove any previous substitution rule. */
+
+ unset_substitute_path_command (NULL, from_tty);
+
+ /* Insert the new substitution rule, and print a confirmation message
+ to the user. */
+
+ substitute_path_from = xstrdup (argv[0]);
+ substitute_path_to = xstrdup (argv[1]);
+ freeargv (argv);
+
+ show_substitute_path_command (NULL, from_tty);
+}
+
\f
void
_initialize_source (void)
@@ -1666,4 +1806,19 @@ Show number of source lines gdb will lis
NULL,
show_lines_to_list,
&setlist, &showlist);
+
+ add_cmd ("substitute-path", class_files, set_substitute_path_command,
+ _("\
+Add a source path substitution rule. If a substitution rule was previously\n\
+set, it is overridden."), &setlist);
+
+ add_cmd ("substitute-path", class_files, unset_substitute_path_command,
+ _("\
+Remove the current source path substitution rule. This has no effect\n\
+if no path substitution rule was previously specified."),
+ &unsetlist);
+
+ add_cmd ("substitute-path", class_files, show_substitute_path_command,
+ _("Show the current source path substitution rule."),
+ &showlist);
}

[-- Attachment #3: subst-doc.diff --]
[-- Type: text/plain, Size: 3744 bytes --]

Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.340
diff -u -p -r1.340 gdb.texinfo
--- doc/gdb.texinfo 21 Jun 2006 13:57:21 -0000 1.340
+++ doc/gdb.texinfo 7 Jul 2006 19:02:26 -0000
@@ -5033,6 +5033,40 @@ To add other directories, use the @code{
The search path is used to find both program source files and @value{GDBN}
script files (read using the @samp{-command} option and @samp{source} command).

+In addition to the source path, @value{GDBN} provides a set of commands
+that manage a source path substitution rule. A @dfn{substitution rule}
+specifies how to rewrite source directories stored in the program's
+debug information in case the sources were moved to a different
+directory between compilation and debugging. @value{GDBN} does a simple
+string replacement of the first occurrence of @var{from} with @var{to}
+in the directory part of the source file name, and uses the result
+instead of the original file name to look up the sources.
+
+Using the previous example, suppose the @file{foo-1.0} tree has been
+moved from @file{/usr/src} to @file{/mnt/cross}, then you can tell
+GDB to replace @file{/usr/src} in all source path names with
+@file{/mnt/cross}. The first lookup will then be
+@file{/mnt/cross/foo-1.0/lib/foo.c} in place of the original location
+of @file{/usr/src/foo-1.0/lib/foo.c}. To define a source path
+substitution rule, use the @ref{set substitute-path} command.
+
+In many cases, you can achieve the same result using the @code{directory}
+command. However, @code{set substitute-path} can be more efficient in
+the case where the sources are organized in a complex tree with multiple
+subdirectories. With the @code{directory} command, you need to add each
+subdirectory of your project. If you moved the entire tree while
+preserving its internal organization, then @code{set substitute-path}
+allows you to direct the debugger to all the sources with one single
+command.
+
+However, @code{set substitute-path} is also more than just a shortcut
+command. The source path is only used if the file at the original
+location no longer exists. On the other hand, @code{set substitute-path}
+modifies the debugger behavior to look at the rewritten location
+instead. So, if for any reason a source file that is not relevant to
+your executable is located at the original location, the substitution
+rule is the only method available to point GDB at the new location.
+
@table @code
@item directory @var{dirname} @dots{}
@item dir @var{dirname} @dots{}
@@ -5068,6 +5102,34 @@ Reset the source path to its default val
@item show directories
@kindex show directories
Print the source path: show which directories it contains.
+
+@anchor{set substitute-path}
+@item set substitute-path @var{FROM} @var{TO}
+@kindex set substitute-path
+Define a source path substitution rule. The new substitution rule
+replaces any rule previously defined.
+
+For example, if the file @file{/foo/bar/baz.c} was moved to
+@file{/mnt/cross/baz.c}, then the command
+
+@smallexample
+(@value{GDBP}) set substitute-path /usr/src /mnt/cross
+@end smallexample
+
+@noindent
+will tell @value{GDBN} to replace @samp{/usr/src} with
+@samp{/mnt/cross}, which will allow @value{GDBN} to find the file
+@file{baz.c} even though it was moved.
+
+@item unset substitute-path
+@kindex unset substitute-path
+If a source path substitution rule is active, then cancel it.
+This command has no effect otherwise.
+
+@item show substitute-path
+@kindex show substitute-path
+Print the source path substitution rule if defined.
+
@end table

If your source path is cluttered with directories that are no longer of