Patchwork [RFC] Apply compilation dir to source_path lookup

login
register
mail settings
Submitter Mike Gulick
Date Sept. 5, 2019, 10:40 p.m.
Message ID <8058b501-9020-84f1-ecf4-b46bfe3b86e3@mathworks.com>
Download mbox | patch
Permalink /patch/34405/
State New
Headers show

Comments

Mike Gulick - Sept. 5, 2019, 10:40 p.m.
Hi,

I'm having trouble getting gdb to find the corresponding source for a
binary whose compilation directory was rewritten using
-fdebug-prefix-map.  I am doing this in order to make builds
reproducible.  I am using this gcc switch to remove a portion of the
compile directory, e.g.

$ cd $HOME/test/src/
$ gcc -g -o test -fdebug-prefix-map=$HOME= test.c
$ dwarfdump test
...
                    DW_AT_name                  test.c
                    DW_AT_comp_dir              /test/src
...

When attempting to debug the resulting binary, gdb is unable to find the
source file even if I add the removed path $HOME to the gdb source
path:

$ cd $HOME
$ gdb --nh ~/test/src/test
GNU gdb (GDB) 8.3
...
(gdb) directory /home/mgulick
Source directories searched: /home/mgulick:$cdir:$cwd
(gdb) info sources
Source files for which symbols have been read in:

/test/src/test.c

Source files for which symbols will be read in on demand:


(gdb) b test.c:3
Breakpoint 1 at 0x664: file test.c, line 3.
(gdb) r
Starting program: /mathworks/home/mgulick/test/src/test 

Breakpoint 1, main () at test.c:3
3	test.c: No such file or directory.


It turns out that only the source file, i.e. DW_AT_name, is used when
searching the source path.  This is surprising given the example with
'/usr/src/foo-1.0/lib/foo.c' and '/mnt/cross' in the gdb documentation
here: https://sourceware.org/gdb/onlinedocs/gdb/Source-Path.html.  It
seems uncommon for DW_AT_name to be the full path to the source file in
most programs I have come across.  In that example from the
documentation, it is likely that DW_AT_name would be 'lib/foo.c' and
DW_AT_comp_dir would be '/usr/src/foo-1.0'.

I have implemented two different approaches to handle this, both of
which work, and I wanted feedback on a) whether you think this is a
legitimate bug/feature, and b) which approach you prefer.

Approach 1 is to include another pass in find_and_open_source where the
compilation directory is prepended to the filename before searching for
the file with openp.  This allows the example I provided above to work
as-is.

Approach 2 is to allow '$cdir' to appear as part of an entry in the
source_path.  Currently it is only allowed to exist as a standalone
entry.  This would allow me to say 'directory /home/mgulick/$cdir', and
find_and_open_source would expand the $cdir part of this string to the
compilation directory.

I prefer approach 1 for a couple of reasons:

1) It is simpler for users to understand.  It doesn't really require
understanding the difference between DW_AT_comp_dir and DW_AT_name.  It
will match the source file in /home/mgulick/test.c, /test/src/test.c, or
/home/mgulick/test/src/test.c.  Of course, since '$cdir' is still in
source_path, it will also look in /test/src/test/src/test.c, which is a
little confusing, but shouldn't be a problem (and we could explicitly
remove '$cdir' from the path when doing this search).

2) It seems to match the existing gdb documentation.

I dislike approach 2 because it makes the directory strings more
complicated, and it also means I'm unable to have a directory named
'/home/mgulick/$cdir' (bizarre, I know, but such things are possible).

Here is a preliminary patch for the first approach.  I will go ahead and
add a test-case and re-send a formal patch review request if this seems
like an acceptable solution.

Thanks,
Mike

Patch

diff --git a/gdb/source.c b/gdb/source.c

index b27f210802..b7b5741028 100644

--- a/gdb/source.c

+++ b/gdb/source.c

@@ -1033,7 +1033,35 @@  find_and_open_source (const char *filename,

   openp_flags flags = OPF_SEARCH_IN_PATH;
   if (basenames_may_differ)
     flags |= OPF_RETURN_REALPATH;
+

+  /* Try to locate file using filename */

   result = openp (path, flags, filename, OPEN_MODE, fullname);
+  if (result < 0 && dirname != NULL)

+    {

+      /* Try to locate file using compilation dir + filename.  This is helpful

+	 if part of the compilation directory was removed, e.g. using gcc's

+	 -fdebug-prefix-map, and we have added the missing prefix to

+	 source_path. */

+      /* Allocate space for dirname, possibly an extra slash, the filename,

+	 and terminating null */

+      char * cdir_filename = (char *)

+	alloca (strlen (dirname) + strlen(SLASH_STRING) + strlen (filename) + 1);

+

+      cdir_filename = strcpy (cdir_filename, dirname);

+      int len = strlen (cdir_filename);    /* last char in cdir_filename */

+

+      /* Add directory separator if not provided by dirname or filename */

+      if (!(IS_DIR_SEPARATOR (cdir_filename[len]) ||

+	    IS_DIR_SEPARATOR (filename[0])))

+        strcat (cdir_filename, SLASH_STRING);

+      else if (IS_DIR_SEPARATOR (cdir_filename[len]) &&

+	       IS_DIR_SEPARATOR (filename[0]))

+	/* Both provide a slash, use only one */

+	cdir_filename[len] = '\0';

+      strcat(cdir_filename,filename);

+

+      result = openp(path, flags, cdir_filename, OPEN_MODE, fullname);

+    }

   if (result < 0)
     {
       /* Didn't work.  Try using just the basename.  */