]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Add support for executables whose debug info has been separated jimb-separate-debug-021223-branch
authorJim Blandy <jimb@codesourcery.com>
Mon, 23 Dec 2002 09:22:59 +0000 (09:22 +0000)
committerJim Blandy <jimb@codesourcery.com>
Mon, 23 Dec 2002 09:22:59 +0000 (09:22 +0000)
out into a separate file, leaving only a link behind.
* objfiles.h (struct objfile): New fields: separate_debug_objfile
and separate_debug_objfile_backlink.
(put_objfile_before): New declaration.
* symfile.c: #include "filenames.h".
(symbol_file_add_with_addrs_or_offsets): If this objfile has its
debug info in a separate file, read that, too. Save the addrs
argument, so we can use it again to read the separated debug info;
syms_from_objfile modifies the table we pass it.
(reread_symbols): After re-reading an objfile, call
reread_separate_symbols to refresh its separate debug info
objfile, if it has one.
(reread_separate_symbols, find_separate_debug_file,
get_debug_link_info, separate_debug_file_exists): New functions.
(debug_file_directory): New global var.
(_initialize_symfile): Initialize debug_file_directory, and
provide the new `set debug-file-directory' command to let the user
change it.
* objfiles.c (free_objfile): If this objfile has its debug info in
a separate objfile, free that one too.  If this is itself a
separate debug info objfile, clear our parent's backlink.
(put_objfile_before): New function.
* utils.c (gnu_debuglink_crc32): New function.
* defs.h (gnu_debuglink_crc32): New declaration.
* Makefile.in (symfile.o): Note dependency on "filenames.h".
* configure.in: Handle --with-separate-debug-dir config option.
* acinclude.m4 (AC_DEFINE_DIR): New macro.
* acconfig.h (DEBUGDIR): New macro.
* configure, aclocal.m4, config.in: Regenerated.

gdb/symfile.c

index d7817918d849b31b2cc61b37a1476d7e4c09ac5e..b6529f7994d4b0270e6ce68acba83b1bbcb1e180 100644 (file)
@@ -38,6 +38,7 @@
 #include "complaints.h"
 #include "demangle.h"
 #include "inferior.h"          /* for write_pc */
+#include "filenames.h"         /* for DOSish file names */
 #include "gdb-stabs.h"
 #include "gdb_obstack.h"
 #include "completer.h"
@@ -105,6 +106,8 @@ static void add_symbol_file_command (char *, int);
 
 static void add_shared_symbol_files_command (char *, int);
 
+static void reread_separate_symbols (struct objfile *objfile);
+
 static void cashier_psymtab (struct partial_symtab *);
 
 bfd *symfile_bfd_open (char *);
@@ -149,6 +152,8 @@ static void set_ext_lang_command (char *args, int from_tty);
 
 static void info_ext_lang_command (char *args, int from_tty);
 
+static char *find_separate_debug_file (struct objfile *objfile);
+
 static void init_filename_language_table (void);
 
 void _initialize_symfile (void);
@@ -888,7 +893,12 @@ symbol_file_add_with_addrs_or_offsets (char *name, int from_tty,
 {
   struct objfile *objfile;
   struct partial_symtab *psymtab;
+  char *debugfile;
   bfd *abfd;
+  struct section_addr_info orig_addrs;
+  
+  if (addrs)
+    orig_addrs = *addrs;
 
   /* Open a bfd for the file, and give user a chance to burp if we'd be
      interactively wiping out any existing symbols.  */
@@ -963,6 +973,37 @@ symbol_file_add_with_addrs_or_offsets (char *name, int from_tty,
        }
     }
 
+  debugfile = find_separate_debug_file (objfile);
+  if (debugfile)
+    {
+      if (from_tty || info_verbose)
+        {
+          printf_filtered ("loading separate debug info from '%s'",
+                           debugfile);
+          wrap_here ("");
+          gdb_flush (gdb_stdout);
+        }
+
+      if (addrs != NULL)
+       {
+         objfile->separate_debug_objfile
+            = symbol_file_add (debugfile, from_tty, &orig_addrs, 0, flags);
+       }
+      else
+       {
+         objfile->separate_debug_objfile
+            = symbol_file_add (debugfile, from_tty, NULL, 0, flags);
+       }
+      objfile->separate_debug_objfile->separate_debug_objfile_backlink
+        = objfile;
+      
+      /* Put the separate debug object before the normal one, this is so that
+         usage of the ALL_OBJFILES_SAFE macro will stay safe. */
+      put_objfile_before (objfile->separate_debug_objfile, objfile);
+      
+      xfree (debugfile);
+    }
+  
   if (from_tty || info_verbose)
     {
       if (post_add_symbol_hook)
@@ -1058,6 +1099,141 @@ symbol_file_clear (int from_tty)
 #endif
 }
 
+static char *
+get_debug_link_info (struct objfile *objfile, unsigned long *crc32_out)
+{
+  asection *sect;
+  bfd_size_type debuglink_size;
+  unsigned long crc32;
+  char *contents;
+  int crc_offset;
+  unsigned char *p;
+  
+  sect = bfd_get_section_by_name (objfile->obfd, ".gnu_debuglink");
+
+  if (sect == NULL)
+    return NULL;
+
+  debuglink_size = bfd_section_size (objfile->obfd, sect);
+  
+  contents = xmalloc (debuglink_size);
+  bfd_get_section_contents (objfile->obfd, sect, contents,
+                           (file_ptr)0, (bfd_size_type)debuglink_size);
+
+  /* Crc value is stored after the filename, aligned up to 4 bytes. */
+  crc_offset = strlen (contents) + 1;
+  crc_offset = (crc_offset + 3) & ~3;
+
+  crc32 = bfd_get_32 (objfile->obfd, (bfd_byte *) (contents + crc_offset));
+  
+  *crc32_out = crc32;
+  return contents;
+}
+
+static int
+separate_debug_file_exists (const char *name, unsigned long crc)
+{
+  unsigned long file_crc = 0;
+  int fd;
+  char buffer[8*1024];
+  int count;
+
+  fd = open (name, O_RDONLY | O_BINARY);
+  if (fd < 0)
+    return 0;
+
+  while ((count = read (fd, buffer, sizeof (buffer))) > 0)
+    file_crc = gnu_debuglink_crc32 (file_crc, buffer, count);
+
+  close (fd);
+
+  return crc == file_crc;
+}
+
+static char *debug_file_directory = NULL;
+
+#if ! defined (DEBUG_SUBDIRECTORY)
+#define DEBUG_SUBDIRECTORY ".debug"
+#endif
+
+static char *
+find_separate_debug_file (struct objfile *objfile)
+{
+  asection *sect;
+  char *basename;
+  char *dir;
+  char *debugfile;
+  char *name_copy;
+  bfd_size_type debuglink_size;
+  unsigned long crc32;
+  int i;
+
+  basename = get_debug_link_info (objfile, &crc32);
+
+  if (basename == NULL)
+    return NULL;
+  
+  dir = xstrdup (objfile->name);
+
+  /* Strip off filename part */
+  for (i = strlen(dir) - 1; i >= 0; i--)
+    {
+      if (IS_DIR_SEPARATOR (dir[i]))
+       break;
+    }
+  dir[i+1] = '\0';
+  
+  debugfile = alloca (strlen (debug_file_directory) + 1
+                      + strlen (dir)
+                      + strlen (DEBUG_SUBDIRECTORY)
+                      + strlen ("/")
+                      + strlen (basename) 
+                      + 1);
+
+  /* First try in the same directory as the original file.  */
+  strcpy (debugfile, dir);
+  strcat (debugfile, basename);
+
+  if (separate_debug_file_exists (debugfile, crc32))
+    {
+      xfree (basename);
+      xfree (dir);
+      return xstrdup (debugfile);
+    }
+  
+  /* Then try in the subdirectory named DEBUG_SUBDIRECTORY.  */
+  strcpy (debugfile, dir);
+  strcat (debugfile, DEBUG_SUBDIRECTORY);
+  strcat (debugfile, "/");
+  strcat (debugfile, basename);
+
+  if (separate_debug_file_exists (debugfile, crc32))
+    {
+      xfree (basename);
+      xfree (dir);
+      return xstrdup (debugfile);
+    }
+  
+  /* Then try in the global debugfile directory.  */
+  strcpy (debugfile, debug_file_directory);
+  strcat (debugfile, "/");
+  strcat (debugfile, dir);
+  strcat (debugfile, "/");
+  strcat (debugfile, basename);
+
+  if (separate_debug_file_exists (debugfile, crc32))
+    {
+      xfree (basename);
+      xfree (dir);
+      return xstrdup (debugfile);
+    }
+  
+  xfree (basename);
+  xfree (dir);
+  return NULL;
+}
+
+
 /* This is the symbol-file command.  Read the file, analyze its
    symbols, and add a struct symtab to a symtab list.  The syntax of
    the command is rather bizarre--(1) buildargv implements various
@@ -1903,6 +2079,8 @@ reread_symbols (void)
                 needs to keep track of (such as _sigtramp, or whatever).  */
 
              TARGET_SYMFILE_POSTREAD (objfile);
+
+              reread_separate_symbols (objfile);
            }
        }
     }
@@ -1910,6 +2088,73 @@ reread_symbols (void)
   if (reread_one)
     clear_symtab_users ();
 }
+
+
+/* Handle separate debug info for OBJFILE, which has just been
+   re-read:
+   - If we had separate debug info before, but now we don't, get rid
+     of the separated objfile.
+   - If we didn't have separated debug info before, but now we do,
+     read in the new separated debug info file.
+   - If the debug link points to a different file, toss the old one
+     and read the new one.
+   This function does *not* handle the case where objfile is still
+   using the same separate debug info file, but that file's timestamp
+   has changed.  That case should be handled by the loop in
+   reread_symbols already.  */
+static void
+reread_separate_symbols (struct objfile *objfile)
+{
+  char *debug_file;
+  unsigned long crc32;
+
+  /* Does the updated objfile's debug info live in a
+     separate file?  */
+  debug_file = find_separate_debug_file (objfile);
+
+  if (objfile->separate_debug_objfile)
+    {
+      /* There are two cases where we need to get rid of
+         the old separated debug info objfile:
+         - if the new primary objfile doesn't have
+         separated debug info, or
+         - if the new primary objfile has separate debug
+         info, but it's under a different filename.
+         If the old and new objfiles both have separate
+         debug info, under the same filename, then we're
+         okay --- if the separated file's contents have
+         changed, we will have caught that when we
+         visited it in this function's outermost
+         loop.  */
+      if (! debug_file
+          || strcmp (debug_file, objfile->separate_debug_objfile->name) != 0)
+        free_objfile (objfile->separate_debug_objfile);
+    }
+
+  /* If the new objfile has separate debug info, and we
+     haven't loaded it already, do so now.  */
+  if (debug_file
+      && ! objfile->separate_debug_objfile)
+    {
+      /* Use the same section offset table as objfile itself.
+         Preserve the flags from objfile that make sense.  */
+      objfile->separate_debug_objfile
+        = (symbol_file_add_with_addrs_or_offsets
+           (debug_file,
+            info_verbose, /* from_tty: Don't override the default. */
+            0, /* No addr table.  */
+            objfile->section_offsets, objfile->num_sections,
+            0, /* Not mainline.  See comments about this above.  */
+            objfile->flags & (OBJF_MAPPED | OBJF_REORDERED
+                              | OBJF_SHARED | OBJF_READNOW
+                              | OBJF_USERLOADED)));
+      objfile->separate_debug_objfile->separate_debug_objfile_backlink
+        = objfile;
+    }
+}
+
+
 \f
 
 
@@ -3418,4 +3663,19 @@ Usage: set extension-language .foo bar",
                  "cache.\n",
                  &setlist),
      &showlist);
+
+  debug_file_directory = xstrdup (DEBUGDIR);
+  c = (add_set_cmd
+       ("debug-file-directory", class_support, var_string,
+        (char *) &debug_file_directory,
+        "Set the directory where separate debug symbols are searched for.\n"
+        "Separate debug symbols are first searched for in the same\n"
+        "directory as the binary, then in the `" DEBUG_SUBDIRECTORY 
+        "' subdirectory,\n"
+        "and lastly at the path of the directory of the binary with\n"
+        "the global debug-file directory prepended\n",
+        &setlist));
+  add_show_from_set (c, &showlist);
+  set_cmd_completer (c, filename_completer);
+
 }