+ return false;
+ }
+
+ return true;
+}
+
+/*
+INTERNAL_FUNCTION
+ get_build_id
+
+SYNOPSIS
+ struct bfd_build_id * get_build_id (bfd *abfd);
+
+DESCRIPTION
+ Finds the build-id associated with @var{abfd}. If the build-id is
+ extracted from the note section then a build-id structure is built
+ for it, using memory allocated to @var{abfd}, and this is then
+ attached to the @var{abfd}.
+
+RETURNS
+ Returns a pointer to the build-id structure if a build-id could be
+ found. If no build-id is found NULL is returned and error code is
+ set.
+*/
+
+static struct bfd_build_id *
+get_build_id (bfd *abfd)
+{
+ struct bfd_build_id *build_id;
+ Elf_Internal_Note inote;
+ Elf_External_Note *enote;
+ bfd_byte *contents;
+ asection *sect;
+ bfd_size_type size;
+
+ BFD_ASSERT (abfd);
+
+ if (abfd->build_id && abfd->build_id->size > 0)
+ /* Save some time by using the already computed build-id. */
+ return (struct bfd_build_id *) abfd->build_id;
+
+ sect = bfd_get_section_by_name (abfd, ".note.gnu.build-id");
+ if (sect == NULL)
+ {
+ bfd_set_error (bfd_error_no_debug_section);
+ return NULL;
+ }
+
+ size = bfd_section_size (sect);
+ /* FIXME: Should we support smaller build-id notes ? */
+ if (size < 0x24)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return NULL;
+ }
+
+ if (!bfd_malloc_and_get_section (abfd, sect, & contents))
+ {
+ free (contents);
+ return NULL;
+ }
+
+ /* FIXME: Paranoia - allow for compressed build-id sections.
+ Maybe we should complain if this size is different from
+ the one obtained above... */
+ size = bfd_section_size (sect);
+ if (size < sizeof (Elf_External_Note))
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ free (contents);
+ return NULL;
+ }
+
+ enote = (Elf_External_Note *) contents;
+ inote.type = H_GET_32 (abfd, enote->type);
+ inote.namesz = H_GET_32 (abfd, enote->namesz);
+ inote.namedata = enote->name;
+ inote.descsz = H_GET_32 (abfd, enote->descsz);
+ inote.descdata = inote.namedata + BFD_ALIGN (inote.namesz, 4);
+ /* FIXME: Should we check for extra notes in this section ? */
+
+ if (inote.descsz <= 0
+ || inote.type != NT_GNU_BUILD_ID
+ || inote.namesz != 4 /* sizeof "GNU" */
+ || !startswith (inote.namedata, "GNU")
+ || inote.descsz > 0x7ffffffe
+ || size < (12 + BFD_ALIGN (inote.namesz, 4) + inote.descsz))
+ {
+ free (contents);
+ bfd_set_error (bfd_error_invalid_operation);
+ return NULL;
+ }
+
+ build_id = bfd_alloc (abfd, sizeof (struct bfd_build_id) + inote.descsz);
+ if (build_id == NULL)
+ {
+ free (contents);
+ return NULL;
+ }
+
+ build_id->size = inote.descsz;
+ memcpy (build_id->data, inote.descdata, inote.descsz);
+ abfd->build_id = build_id;
+ free (contents);
+
+ return build_id;
+}
+
+/*
+INTERNAL_FUNCTION
+ get_build_id_name
+
+SYNOPSIS
+ char * get_build_id_name (bfd *abfd, void *build_id_out_p)
+
+DESCRIPTION
+ Searches @var{abfd} for a build-id, and then constructs a pathname
+ from it. The path is computed as .build-id/NN/NN+NN.debug where
+ NNNN+NN is the build-id value as a hexadecimal string.
+
+RETURNS
+ Returns the constructed filename or NULL upon error.
+ It is the caller's responsibility to free the memory used to hold the
+ filename.
+ If a filename is returned then the @var{build_id_out_p}
+ parameter (which points to a @code{struct bfd_build_id}
+ pointer) is set to a pointer to the build_id structure.
+*/
+
+static char *
+get_build_id_name (bfd *abfd, void *build_id_out_p)
+{
+ struct bfd_build_id **build_id_out = build_id_out_p;
+ struct bfd_build_id *build_id;
+ char *name;
+ char *n;
+ bfd_size_type s;
+ bfd_byte *d;
+
+ if (abfd == NULL || bfd_get_filename (abfd) == NULL || build_id_out == NULL)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return NULL;
+ }
+
+ build_id = get_build_id (abfd);
+ if (build_id == NULL)
+ return NULL;
+
+ /* Compute the debug pathname corresponding to the build-id. */
+ name = bfd_malloc (strlen (".build-id/") + build_id->size * 2 + 2 + strlen (".debug"));
+ if (name == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;