+
+/*
+FUNCTION
+ bfd_create_gnu_debuglink_section
+
+SYNOPSIS
+ struct bfd_section *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 bfd_section *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 bfd_section *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, contents + crc_offset);
+
+ if (! bfd_set_section_contents (abfd, sect, contents, 0, debuglink_size))
+ {
+ /* XXX Should we delete the section from the bfd ? */
+ free (contents);
+ return FALSE;
+ }
+
+ return TRUE;
+}