gdb/ChangeLog:

2003-01-23  Alexander Larsson <alexl@redhat.com>
	    Jim Blandy  <jimb@redhat.com>

	Add support for executables whose debug info has been separated
	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/doc/ChangeLog:
2003-01-23  Jim Blandy  <jimb@redhat.com>

	* gdb.texinfo (Separate Debug Files): New section.
This commit is contained in:
Jim Blandy
2003-01-23 23:03:32 +00:00
parent 2e9d253267
commit 5b5d99cf4d
14 changed files with 1249 additions and 580 deletions

View 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;
}
}
@@ -3411,4 +3656,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);
}