[PATCH v2] Search for DWZ files in debug-file-directories as well

Sergio Durigan Junior sergiodj@sergiodj.net
Thu Nov 19 02:27:08 GMT 2020


Changes from v1:

- Addressed Simon's comments (new comment explaining how we try to
  match for the current debug-file-directory; properly use
  .erase/.insert methods -- keeping in mind that they modify the
  string in-place).


When Debian (and Ubuntu) builds its binaries, it (still) doesn't use
dwz's "--relative" option.  This causes their debuginfo files to
carry a .gnu_debugaltlink section containing a full pathname to the
DWZ alt debug file, like this:

  $ readelf -wk /usr/bin/cat
  Contents of the .gnu_debugaltlink section:

    Separate debug info file: /usr/lib/debug/.dwz/x86_64-linux-gnu/coreutils.debug
    Build-ID (0x14 bytes):
   ee 76 5d 71 97 37 ce 46 99 44 32 bb e8 a9 1a ef 99 96 88 db

  Contents of the .gnu_debuglink section:

    Separate debug info file: 06d3bee37b8c7e67b31cb2689cb351102ae73b.debug
    CRC value: 0x53267655

This usually works OK, because most of the debuginfo files installed
via apt will be present in /usr/lib/debug anyway.  However, imagine
the following scenario:

- You are using /usr/bin/cat, it crashes on you and generates a
  corefile.

- You don't want/need to "apt install" the debuginfo file for
  coreutils from the repositories.  Instead, you already have the
  debuginfo files in a separate directory (e.g., $HOME/dbgsym).

- You start GDB and "set debug-file-directory $HOME/dbgsym".
  You then get the following message:

  $ gdb -ex 'set debug-file-directory ./dbgsym/usr/lib/debug' -ex 'file /bin/cat' -ex 'core-file ./cat.core'
  GNU gdb (Ubuntu 10.1-0ubuntu1) 10.1
  ...
  Reading symbols from /bin/cat...
  Reading symbols from /home/sergio/gdb/dbgsym/usr/lib/debug/.build-id/bc/06d3bee37b8c7e67b31cb2689cb351102ae73b.debug...
  could not find '.gnu_debugaltlink' file for /home/sergio/gdb/dbgsym/usr/lib/debug/.build-id/bc/06d3bee37b8c7e67b31cb2689cb351102ae73b.debug

This error happens because GDB is trying to locate the build-id
link (inside /home/sergio/gdb/dbgsym/usr/lib/debug/.build-id) for the
DWZ alt debug file, which doesn't exist.  Arguably, this is a problem
with how dh_dwz works in Debian, and it's something I'm also planning
to tackle.  But, back at the problem at hand.

Besides not being able to find the build-id link in the directory
mentioned above, GDB also tried to open the DWZ alt file using its
filename.  The problem here is that, since we don't have the distro's
debuginfo installed, it can't find anything under /usr/lib/debug that
satisfies it.

It occurred to me that a good way to workaround this problem is to
actually try to locate the DWZ alt debug file inside the
debug-file-directories (that were likely provided by the user).  So
this is what the proposed patch does.

The idea here is simple: get the filename extracted from the
.gnu_debugaltlink section, and manipulate it in order to replace the
initial part of the path (everything before "/.dwz/") by whatever
debug-file-directories the user might have provided.

I talked with Mark Wielaard and he agrees this is a sensible approach.
In fact, apparently this is something that eu-readelf also does.

I regtested this code, and no regressions were found.

2020-11-14  Sergio Durigan Junior  <sergiodj@sergiodj.net>

	* dwarf2/read.c (dwarf2_get_dwz_file): Convert 'filename' to a
	std::string.  Implement ability to search for DWZ files in the
	debug-file-directories provided by the user as well.
---
 gdb/dwarf2/read.c | 73 +++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 67 insertions(+), 6 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 3c59826291..c462b9bb2c 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -2190,7 +2190,7 @@ locate_dwz_sections (bfd *abfd, asection *sectp, dwz_file *dwz_file)
 struct dwz_file *
 dwarf2_get_dwz_file (dwarf2_per_bfd *per_bfd)
 {
-  const char *filename;
+  std::string filename;
   bfd_size_type buildid_len_arg;
   size_t buildid_len;
   bfd_byte *buildid;
@@ -2216,19 +2216,17 @@ dwarf2_get_dwz_file (dwarf2_per_bfd *per_bfd)
 
   filename = data.get ();
 
-  std::string abs_storage;
-  if (!IS_ABSOLUTE_PATH (filename))
+  if (!IS_ABSOLUTE_PATH (filename.c_str ()))
     {
       gdb::unique_xmalloc_ptr<char> abs
 	= gdb_realpath (bfd_get_filename (per_bfd->obfd));
 
-      abs_storage = ldirname (abs.get ()) + SLASH_STRING + filename;
-      filename = abs_storage.c_str ();
+      filename = ldirname (abs.get ()) + SLASH_STRING + filename;
     }
 
   /* First try the file name given in the section.  If that doesn't
      work, try to use the build-id instead.  */
-  gdb_bfd_ref_ptr dwz_bfd (gdb_bfd_open (filename, gnutarget));
+  gdb_bfd_ref_ptr dwz_bfd (gdb_bfd_open (filename.c_str (), gnutarget));
   if (dwz_bfd != NULL)
     {
       if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
@@ -2238,6 +2236,69 @@ dwarf2_get_dwz_file (dwarf2_per_bfd *per_bfd)
   if (dwz_bfd == NULL)
     dwz_bfd = build_id_to_debug_bfd (buildid_len, buildid);
 
+  if (dwz_bfd == nullptr)
+    {
+      /* If the user has provided us with different
+	 debug-file-directories, we can try them in order.  */
+      size_t dwz_pos = filename.find ("/.dwz/");
+
+      if (dwz_pos != std::string::npos)
+	{
+	  std::vector<gdb::unique_xmalloc_ptr<char>> debugdir_vec
+	    = dirnames_to_char_ptr_vec (debug_file_directory);
+
+	  for (const gdb::unique_xmalloc_ptr<char> &debugdir : debugdir_vec)
+	    {
+	      /* The idea is to iterate over the
+		 debug-file-directories provided by the user and
+		 replace the hard-coded path in the "filename" by each
+		 debug-file-directory.
+
+		 For example, suppose that filename is:
+
+		   /usr/lib/debug/.dwz/foo.dwz
+
+		 And suppose that we have "$HOME/bar" as the
+		 debug-file-directory.  We would then adjust filename
+		 to look like:
+
+		   $HOME/bar/.dwz/foo.dwz
+
+		 which would hopefully allow us to find the alt debug
+		 file.  */
+	      std::string ddir = debugdir.get ();
+
+	      /* Check whether the beginning of FILENAME is DDIR.  If
+		 it is, then we are dealing with a file which we
+		 already attempted to open before, so we just skip it
+		 and continue processing the reamining
+		 debug-file-directories.  */
+	      if (filename.size () > ddir.size ()
+		  && filename.compare (0, ddir.size (), ddir) == 0)
+		continue;
+
+	      /* Replace FILENAME's default debug-file-directory with
+		 DDIR.  */
+	      std::string new_filename = filename;
+	      new_filename.erase (0, dwz_pos);
+	      new_filename.insert (0, ddir);
+
+	      dwz_bfd = gdb_bfd_open (new_filename.c_str (), gnutarget);
+
+	      if (dwz_bfd != nullptr)
+		{
+		  if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
+		    {
+		      dwz_bfd.reset (nullptr);
+		      continue;
+		    }
+		  /* Found it.  */
+		  break;
+		}
+	    }
+	}
+    }
+
   if (dwz_bfd == nullptr)
     {
       gdb::unique_xmalloc_ptr<char> alt_filename;
-- 
2.28.0



More information about the Gdb-patches mailing list