diff options
Diffstat (limited to 'bfd/opncls.c')
-rw-r--r-- | bfd/opncls.c | 219 |
1 files changed, 196 insertions, 23 deletions
diff --git a/bfd/opncls.c b/bfd/opncls.c index 4771979..5237190 100644 --- a/bfd/opncls.c +++ b/bfd/opncls.c @@ -716,28 +716,32 @@ bfd_release (abfd, block) 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 *)); +#define GNU_DEBUGLINK ".gnu_debuglink" /* -INTERNAL_FUNCTION - calc_crc32 +FUNCTION + bfd_calc_gnu_debuglink_crc32 SYNOPSIS - unsigned long calc_crc32 (unsigned long crc, const unsigned char *buf, size_t len); + unsigned long bfd_calc_gnu_debuglink_crc32 (unsigned long crc, const unsigned char *buf, bfd_size_type len); DESCRIPTION - Advance the CRC32 given by @var{crc} through @var{len} - bytes of @var{buf}. Return the updated CRC32 value. + Computes a CRC value as used in the .gnu_debuglink section. + Advances the previously computed @var{crc} value by computing + and adding in the crc32 for @var{len} bytes of @var{buf}. + +RETURNS + Return the updated CRC32 value. */ -static unsigned long -calc_crc32 (crc, buf, len) +unsigned long +bfd_calc_gnu_debuglink_crc32 (crc, buf, len) unsigned long crc; const unsigned char *buf; - size_t len; + bfd_size_type len; { static const unsigned long crc32_table[256] = { @@ -808,7 +812,7 @@ INTERNAL_FUNCTION get_debug_link_info SYNOPSIS - char *get_debug_link_info (bfd *abfd, unsigned long *crc32_out) + char * get_debug_link_info (bfd * abfd, unsigned long * crc32_out) DESCRIPTION fetch the filename and CRC32 value for any separate debuginfo @@ -818,8 +822,8 @@ DESCRIPTION static char * get_debug_link_info (abfd, crc32_out) - bfd *abfd; - unsigned long *crc32_out; + bfd * abfd; + unsigned long * crc32_out; { asection * sect; bfd_size_type debuglink_size; @@ -831,14 +835,17 @@ get_debug_link_info (abfd, crc32_out) BFD_ASSERT (abfd); BFD_ASSERT (crc32_out); - sect = bfd_get_section_by_name (abfd, ".gnu_debuglink"); + 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); + contents = malloc (debuglink_size); + if (contents == NULL) + return NULL; + ret = bfd_get_section_contents (abfd, sect, contents, (file_ptr)0, debuglink_size); if (! ret) @@ -877,7 +884,7 @@ separate_debug_file_exists (name, crc) static char buffer [8 * 1024]; unsigned long file_crc = 0; int fd; - int count; + bfd_size_type count; BFD_ASSERT (name); @@ -886,7 +893,7 @@ separate_debug_file_exists (name, crc) return FALSE; while ((count = read (fd, buffer, sizeof (buffer))) > 0) - file_crc = calc_crc32 (file_crc, buffer, count); + file_crc = bfd_calc_gnu_debuglink_crc32 (file_crc, buffer, count); close (fd); @@ -930,16 +937,21 @@ find_separate_debug_file (abfd, debug_file_directory) return NULL; basename = get_debug_link_info (abfd, & crc32); - if (basename == NULL) return NULL; + if (strlen (basename) < 1) { free (basename); return NULL; } - dir = xstrdup (abfd->filename); + dir = strdup (abfd->filename); + if (dir == NULL) + { + free (basename); + return NULL; + } BFD_ASSERT (strlen (dir) != 0); /* Strip off filename part. */ @@ -950,11 +962,17 @@ find_separate_debug_file (abfd, debug_file_directory) 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); + debugfile = malloc (strlen (debug_file_directory) + 1 + + strlen (dir) + + strlen (".debug/") + + strlen (basename) + + 1); + if (debugfile == NULL) + { + free (basename); + free (dir); + return NULL; + } /* First try in the same directory as the original file: */ strcpy (debugfile, dir); @@ -1037,3 +1055,158 @@ bfd_follow_gnu_debuglink (abfd, dir) #endif return find_separate_debug_file (abfd, dir); } + +/* +FUNCTION + bfd_create_gnu_debuglink_section + +SYNOPSIS + struct sec * bfd_create_gnu_debuglink_section (bfd * abfd, const char * filename); + +DESCRIPTION + + Takes a @var{BFD} and adds a .gnu_debuglink section to it. The section is sized + to be big enough to contain a link to the specified @var{filename}. + +RETURNS + A pointer to the new section is returned if all is ok. Otherwise <<NULL>> is + returned and bfd_error is set. +*/ + +asection * +bfd_create_gnu_debuglink_section + (bfd * abfd, + const char * filename) +{ + asection * sect; + bfd_size_type debuglink_size; + + if (abfd == NULL || filename == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return NULL; + } + + /* Strip off any path components in filename. */ + filename = lbasename (filename); + + sect = bfd_get_section_by_name (abfd, GNU_DEBUGLINK); + if (sect) + { + /* Section already exists. */ + bfd_set_error (bfd_error_invalid_operation); + return NULL; + } + + sect = bfd_make_section (abfd, GNU_DEBUGLINK); + if (sect == NULL) + return NULL; + + if (! bfd_set_section_flags (abfd, sect, + SEC_HAS_CONTENTS | SEC_READONLY | SEC_DEBUGGING)) + /* XXX Should we delete the section from the bfd ? */ + return NULL; + + + debuglink_size = strlen (filename) + 1; + debuglink_size += 3; + debuglink_size &= ~3; + debuglink_size += 4; + + if (! bfd_set_section_size (abfd, sect, debuglink_size)) + /* XXX Should we delete the section from the bfd ? */ + return NULL; + + return sect; +} + + +/* +FUNCTION + bfd_fill_in_gnu_debuglink_section + +SYNOPSIS + bfd_boolean bfd_fill_in_gnu_debuglink_section (bfd * abfd, struct sec * sect, const char * filename); + +DESCRIPTION + + Takes a @var{BFD} and containing a .gnu_debuglink section @var{SECT} + and fills in the contents of the section to contain a link to the + specified @var{filename}. The filename should be relative to the + current directory. + +RETURNS + <<TRUE>> is returned if all is ok. Otherwise <<FALSE>> is returned + and bfd_error is set. +*/ + +bfd_boolean +bfd_fill_in_gnu_debuglink_section + (bfd * abfd, + struct sec * sect, + const char * filename) +{ + bfd_size_type debuglink_size; + unsigned long crc32; + char * contents; + bfd_size_type crc_offset; + FILE * handle; + static char buffer[8 * 1024]; + size_t count; + + if (abfd == NULL || sect == NULL || filename == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + /* Make sure that we can read the file. + XXX - Should we attempt to locate the debug info file using the same + algorithm as gdb ? At the moment, since we are creating the + .gnu_debuglink section, we insist upon the user providing us with a + correct-for-section-creation-time path, but this need not conform to + the gdb location algorithm. */ + handle = fopen (filename, FOPEN_RB); + if (handle == NULL) + { + bfd_set_error (bfd_error_system_call); + return FALSE; + } + + crc32 = 0; + while ((count = fread (buffer, 1, sizeof buffer, handle)) > 0) + crc32 = bfd_calc_gnu_debuglink_crc32 (crc32, buffer, count); + fclose (handle); + + /* Strip off any path components in filename, + now that we no longer need them. */ + filename = lbasename (filename); + + debuglink_size = strlen (filename) + 1; + debuglink_size += 3; + debuglink_size &= ~3; + debuglink_size += 4; + + contents = malloc (debuglink_size); + if (contents == NULL) + { + /* XXX Should we delete the section from the bfd ? */ + bfd_set_error (bfd_error_no_memory); + return FALSE; + } + + strcpy (contents, filename); + crc_offset = debuglink_size - 4; + + bfd_put_32 (abfd, crc32, (bfd_byte *) (contents + crc_offset)); + + if (! bfd_set_section_contents (abfd, sect, contents, + (file_ptr)0, debuglink_size)) + { + /* XXX Should we delete the section from the bfd ? */ + free (contents); + return FALSE; + } + + return TRUE; +} |