bfd_follow_gnu_debuglink: New function. Follow the pointer contained inside a

.gnu_debuglink section.
This commit is contained in:
Nick Clifton 2003-01-31 10:04:16 +00:00
parent 38a94d4494
commit 31f7ba0423
5 changed files with 354 additions and 5 deletions

View file

@ -1,3 +1,14 @@
2003-01-31 Graydon Hoare <graydon@redhat.com>
* Makefile.am (opncls.lo): Add dependency upon libiberty.h.
* Makefile.in: Regenerate.
* opncls.c (calc_crc32, get_debug_link_info,
seperate_debug_file_exists, find_seperate_debug_file): New
internal functions.
(bfd_follow_gnu_debuglink): New function. Follow the pointer
contained inside a .gnu_debuglink section.
* bfd-in2.h: Regenerate.
2003-01-29 Alexandre Oliva <aoliva@redhat.com>
* elfxx-mips.c (mips_elf_got_entry_hash): Don't dereference

View file

@ -877,7 +877,8 @@ corefile.lo: corefile.c $(INCDIR)/filenames.h
format.lo: format.c $(INCDIR)/filenames.h
init.lo: init.c $(INCDIR)/filenames.h
libbfd.lo: libbfd.c $(INCDIR)/filenames.h
opncls.lo: opncls.c $(INCDIR)/filenames.h $(INCDIR)/objalloc.h
opncls.lo: opncls.c $(INCDIR)/filenames.h $(INCDIR)/libiberty.h \
$(INCDIR)/objalloc.h
reloc.lo: reloc.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h
section.lo: section.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h
syms.lo: syms.c $(INCDIR)/filenames.h $(INCDIR)/safe-ctype.h \

View file

@ -1,4 +1,4 @@
# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
@ -799,7 +799,7 @@ configure.in version.h
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar
TAR = gtar
GZIP_ENV = --best
SOURCES = $(libbfd_a_SOURCES) $(libbfd_la_SOURCES)
OBJECTS = $(libbfd_a_OBJECTS) $(libbfd_la_OBJECTS)
@ -1410,7 +1410,8 @@ corefile.lo: corefile.c $(INCDIR)/filenames.h
format.lo: format.c $(INCDIR)/filenames.h
init.lo: init.c $(INCDIR)/filenames.h
libbfd.lo: libbfd.c $(INCDIR)/filenames.h
opncls.lo: opncls.c $(INCDIR)/filenames.h $(INCDIR)/objalloc.h
opncls.lo: opncls.c $(INCDIR)/filenames.h $(INCDIR)/libiberty.h \
$(INCDIR)/objalloc.h
reloc.lo: reloc.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h
section.lo: section.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h
syms.lo: syms.c $(INCDIR)/filenames.h $(INCDIR)/safe-ctype.h \

View file

@ -880,6 +880,9 @@ bfd_make_writable PARAMS ((bfd *abfd));
bfd_boolean
bfd_make_readable PARAMS ((bfd *abfd));
char *
bfd_follow_gnu_debuglink PARAMS ((bfd *abfd, const char *dir));
/* Extracted from libbfd.c. */
/* Byte swapping macros for user section data. */

View file

@ -1,6 +1,6 @@
/* opncls.c -- open and close a BFD.
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000,
2001, 2002
2001, 2002, 2003
Free Software Foundation, Inc.
Written by Cygnus Support.
@ -25,6 +25,7 @@
#include "sysdep.h"
#include "objalloc.h"
#include "libbfd.h"
#include "libiberty.h"
#ifndef S_IXUSR
#define S_IXUSR 0100 /* Execute by owner. */
@ -699,3 +700,335 @@ bfd_release (abfd, block)
{
objalloc_free_block ((struct objalloc *) abfd->memory, block);
}
/*
GNU Extension: separate debug-info files
The idea here is that a special section called .gnu_debuglink might be
embedded in a binary file, which indicates that some *other* file
contains the real debugging information. This special section contains a
filename and CRC32 checksum, which we read and resolve to another file,
if it exists.
This facilitates "optional" provision of debugging information, without
having to provide two complete copies of every binary object (with and
without debug symbols).
*/
static unsigned long calc_crc32 PARAMS ((unsigned long, const unsigned char *, size_t));
static char * get_debug_link_info PARAMS ((bfd *, unsigned long *));
static bfd_boolean separate_debug_file_exists PARAMS ((const char *, const unsigned long));
static char * find_separate_debug_file PARAMS ((bfd *, const char *));
/*
INTERNAL_FUNCTION
calc_crc32
SYNOPSIS
unsigned long calc_crc32 (unsigned long crc, const unsigned char *buf, size_t len);
DESCRIPTION
Advance the CRC32 given by @var{crc} through @var{len}
bytes of @var{buf}. Return the updated CRC32 value.
*/
static unsigned long
calc_crc32 (crc, buf, len)
unsigned long crc;
const unsigned char *buf;
size_t len;
{
static const unsigned long crc32_table[256] =
{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
0x2d02ef8d
};
const unsigned char *end;
crc = ~crc & 0xffffffff;
for (end = buf + len; buf < end; ++ buf)
crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
return ~crc & 0xffffffff;;
}
/*
INTERNAL_FUNCTION
get_debug_link_info
SYNOPSIS
char *get_debug_link_info (bfd *abfd, unsigned long *crc32_out)
DESCRIPTION
fetch the filename and CRC32 value for any separate debuginfo
associated with @var{abfd}. Return NULL if no such info found,
otherwise return filename and update @var{crc32_out}.
*/
static char *
get_debug_link_info (abfd, crc32_out)
bfd *abfd;
unsigned long *crc32_out;
{
asection * sect;
bfd_size_type debuglink_size;
unsigned long crc32;
char * contents;
int crc_offset;
bfd_boolean ret;
BFD_ASSERT (abfd);
BFD_ASSERT (crc32_out);
sect = bfd_get_section_by_name (abfd, ".gnu_debuglink");
if (sect == NULL)
return NULL;
debuglink_size = bfd_section_size (abfd, sect);
contents = xmalloc (debuglink_size);
ret = bfd_get_section_contents (abfd, sect, contents,
(file_ptr)0, debuglink_size);
if (! ret)
{
free (contents);
return NULL;
}
/* 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 (abfd, (bfd_byte *) (contents + crc_offset));
*crc32_out = crc32;
return contents;
}
/*
INTERNAL_FUNCTION
separate_debug_file_exists
SYNOPSIS
bfd_boolean separate_debug_file_exists (char * name, unsigned long crc32)
DESCRIPTION
Checks to see if @var{name} is a file and if its contents
match @var{crc32}.
*/
static bfd_boolean
separate_debug_file_exists (name, crc)
const char *name;
const unsigned long crc;
{
static char buffer [8 * 1024];
unsigned long file_crc = 0;
int fd;
int count;
BFD_ASSERT (name);
fd = open (name, O_RDONLY);
if (fd < 0)
return FALSE;
while ((count = read (fd, buffer, sizeof (buffer))) > 0)
file_crc = calc_crc32 (file_crc, buffer, count);
close (fd);
return crc == file_crc;
}
/*
INTERNAL_FUNCTION
find_separate_debug_file
SYNOPSIS
char * find_separate_debug_file (bfd *abfd)
DESCRIPTION
Searches @var{abfd} for a reference to separate debugging
information, scans various locations in the filesystem, including
the file tree rooted at @var{debug_file_directory}, and returns a
filename of such debugging information if the file is found and has
matching CRC32. Returns NULL if no reference to debugging file
exists, or file cannot be found.
*/
static char *
find_separate_debug_file (abfd, debug_file_directory)
bfd *abfd;
const char *debug_file_directory;
{
char *basename;
char *dir;
char *debugfile;
unsigned long crc32;
int i;
BFD_ASSERT (abfd);
if (debug_file_directory == NULL)
debug_file_directory = ".";
/* BFD may have been opened from a stream. */
if (! abfd->filename)
return NULL;
basename = get_debug_link_info (abfd, & crc32);
if (basename == NULL || strlen (basename) < 1)
return NULL;
dir = xstrdup (abfd->filename);
BFD_ASSERT (strlen (dir) != 0);
/* Strip off filename part. */
for (i = strlen (dir) - 1; i >= 0; i--)
if (IS_DIR_SEPARATOR (dir[i]))
break;
dir[i + 1] = '\0';
BFD_ASSERT (dir[i] == '/' || dir[0] == '\0')
debugfile = xmalloc (strlen (debug_file_directory) + 1
+ strlen (dir)
+ strlen (".debug/")
+ 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))
{
free (basename);
free (dir);
return debugfile;
}
/* Then try in a subdirectory called .debug. */
strcpy (debugfile, dir);
strcat (debugfile, ".debug/");
strcat (debugfile, basename);
if (separate_debug_file_exists (debugfile, crc32))
{
free (basename);
free (dir);
return debugfile;
}
/* Then try in the global debugfile directory. */
strcpy (debugfile, debug_file_directory);
i = strlen (debug_file_directory) - 1;
if (i > 0
&& debug_file_directory[i] != '/'
&& dir[0] != '/')
strcat (debugfile, "/");
strcat (debugfile, dir);
strcat (debugfile, basename);
if (separate_debug_file_exists (debugfile, crc32))
{
free (basename);
free (dir);
return debugfile;
}
free (debugfile);
free (basename);
free (dir);
return NULL;
}
/*
FUNCTION
bfd_follow_gnu_debuglink
SYNOPSIS
char * bfd_follow_gnu_debuglink(bfd *abfd, const char *dir);
DESCRIPTION
Takes a BFD and searches it for a .gnu_debuglink section. If this
section is found, examines the section for the name and checksum of
a '.debug' file containing auxiliary debugging
information. Searches filesystem for .debug file in some standard
locations, including the directory tree rooted at @var{dir}, and if
found returns the full filename. If @var{dir} is NULL, will search
default path configured into libbfd at build time.
RETURNS
<<NULL>> on any errors or failure to locate the .debug file,
otherwise a pointer to a heap-allocated string containing the
filename. The caller is responsible for freeing this string.
*/
char *
bfd_follow_gnu_debuglink (abfd, dir)
bfd *abfd;
const char * dir;
{
#if 0 /* Disabled until DEBUGDIR can be defined by configure.in */
if (dir == NULL)
dir = DEBUGDIR;
#endif
return find_separate_debug_file (abfd, dir);
}