This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch 1/2] build id


Hi Sami,

really forgot these two FIXMEs should be probably dealt with.


On Tue, 23 Nov 2010 17:27:36 +0100, sami wagiaalla wrote:
> +/* Locate NT_GNU_BUILD_ID and return its matching debug filename.
> +   FIXME: NOTE decoding should be unified with the BFD core notes decoding.  */
[...]
> +static void
> +elf_swap_ehdr_in (bfd *abfd,
> +		  const Elf64_External_Ehdr *src64,
> +		  Elf_Internal_Ehdr *dst)
> +{
> +  int is64 = bfd_get_arch_size (abfd) == 64;
> +#define SRC(field) (is64 ? src64->field \
> +			 : ((const Elf32_External_Ehdr *) src64)->field)
> +
> +  int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma;
> +  memcpy (dst->e_ident, SRC (e_ident), EI_NIDENT);
> +  dst->e_type = H_GET_16 (abfd, SRC (e_type));
> +  dst->e_machine = H_GET_16 (abfd, SRC (e_machine));
> +  dst->e_version = H_GET_32 (abfd, SRC (e_version));
> +  if (signed_vma)
> +    dst->e_entry = H_GET_SIGNED_WORD (abfd, SRC (e_entry));
> +  else
> +    dst->e_entry = H_GET_WORD (abfd, SRC (e_entry));
> +  dst->e_phoff = H_GET_WORD (abfd, SRC (e_phoff));
> +  dst->e_shoff = H_GET_WORD (abfd, SRC (e_shoff));
> +  dst->e_flags = H_GET_32 (abfd, SRC (e_flags));
> +  dst->e_ehsize = H_GET_16 (abfd, SRC (e_ehsize));
> +  dst->e_phentsize = H_GET_16 (abfd, SRC (e_phentsize));
> +  dst->e_phnum = H_GET_16 (abfd, SRC (e_phnum));
> +  dst->e_shentsize = H_GET_16 (abfd, SRC (e_shentsize));
> +  dst->e_shnum = H_GET_16 (abfd, SRC (e_shnum));
> +  dst->e_shstrndx = H_GET_16 (abfd, SRC (e_shstrndx));
> +
> +#undef SRC
> +}

The code like this one is copy-pasted from bfd/elfcode.h .  This is apparently
wrong and the FIXME tries to address this.

OTOH I had a first version [attached] which was really trying to apply bfd/ to
any functionality and it was probably also wrong.  ELF is not so complicated
it would always make sense to bend over backwards any piece of bfd/ for any
ELF functionality GDB needs.

I cannot say offhand how much it should be merged with bfd/ but it seems to me
it should be merged a bit more, the copy-pasting is too obvious now.


> +/* BUILD_ID_ADDR_GET gets ADDR located somewhere in the object.
> +   Find the first section before ADDR containing an ELF header.
> +   We rely on the fact the sections from multiple files do not mix.
> +   FIXME: We should check ADDR is contained _inside_ the section with possibly
> +   missing content (P_FILESZ < P_MEMSZ).  These omitted sections are currently
> +   hidden by _BFD_ELF_MAKE_SECTION_FROM_PHDR.  */

When you dump a core each segment can have now three kinds of dump:

/usr/share/doc/kernel-doc-*/Documentation/filesystems/proc.txt
  - (bit 3) file-backed shared memory
  - (bit 4) ELF header pages in file-backed private memory areas (it is
            effective only if the bit 2 is cleared)

echo 0x7f >/proc/self/coredump_filter
Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  LOAD           0x001000 0x0000000000400000 0x0000000000000000 0x0d5000 0x0d5000 R E 0x1000
                                                                ^^^^^^^^
echo 0x00 >/proc/self/coredump_filter
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  LOAD           0x001000 0x0000000000400000 0x0000000000000000 0x000000 0x0d5000 R E 0x1000
                                                                ^^^^^^^^

echo 0x33 >/proc/self/coredump_filter # default
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  LOAD           0x001000 0x0000000000400000 0x0000000000000000 0x001000 0x0d5000 R E 0x1000
                                                                ^^^^^^^^

bfd/ generates virtual sections (asection) from these segments, for some (or
only the last? _bfd_elf_make_section_from_phdr <split != 0>) cases two
sections are generated.

If the code chooses the wrong of two sections covering that same memory range
it may miss the build-id content as it may be in the other section.

Also it may check even < and not just the >= condition to avoid possibly false
build-ids (it may not be needed, but not sure why it is not now).



Thanks,
Jan
Index: bfd/elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.400
diff -u -p -r1.400 elf.c
--- bfd/elf.c	24 Jul 2007 08:09:20 -0000	1.400
+++ bfd/elf.c	25 Jul 2007 01:00:39 -0000
@@ -2225,6 +2225,11 @@ _bfd_elf_new_section_hook (bfd *abfd, as
    by the difference between the two sizes.  In effect, the segment is split
    into it's initialized and uninitialized parts.
 
+   Meaning of files size different than the memory size is different for core
+   files by Linux kernel with its fs.binfmt_elf.core_dump_elf_headers = 1.
+   Missing memory data should be fetched there from the readonly segments of
+   the executable file.
+
  */
 
 bfd_boolean
@@ -2239,8 +2244,8 @@ _bfd_elf_make_section_from_phdr (bfd *ab
   size_t len;
   int split;
 
-  split = ((hdr->p_memsz > 0)
-	    && (hdr->p_filesz > 0)
+  split = (abfd->format != bfd_core
+	    && (hdr->p_memsz > 0) && (hdr->p_filesz > 0)
 	    && (hdr->p_memsz > hdr->p_filesz));
   sprintf (namebuf, "%s%d%s", typename, index, split ? "a" : "");
   len = strlen (namebuf) + 1;
Index: bfd/elfcode.h
===================================================================
RCS file: /cvs/src/src/bfd/elfcode.h,v
retrieving revision 1.84
diff -u -p -r1.84 elfcode.h
--- bfd/elfcode.h	9 Jul 2007 21:23:37 -0000	1.84
+++ bfd/elfcode.h	25 Jul 2007 01:00:39 -0000
@@ -1635,6 +1635,7 @@ NAME(_bfd_elf,bfd_from_remote_memory)
   int err;
   unsigned int i;
   bfd_vma loadbase;
+  int loadbase_set;
 
   /* Read in the ELF header in external format.  */
   err = target_read_memory (ehdr_vma, (bfd_byte *) &x_ehdr, sizeof x_ehdr);
@@ -1711,6 +1712,7 @@ NAME(_bfd_elf,bfd_from_remote_memory)
   contents_size = 0;
   last_phdr = NULL;
   loadbase = ehdr_vma;
+  loadbase_set = 0;
   for (i = 0; i < i_ehdr.e_phnum; ++i)
     {
       elf_swap_phdr_in (templ, &x_phdrs[i], &i_phdrs[i]);
@@ -1725,8 +1727,13 @@ NAME(_bfd_elf,bfd_from_remote_memory)
 	  if (segment_end > (bfd_vma) contents_size)
 	    contents_size = segment_end;
 
-	  if ((i_phdrs[i].p_offset & -i_phdrs[i].p_align) == 0)
-	    loadbase = ehdr_vma - (i_phdrs[i].p_vaddr & -i_phdrs[i].p_align);
+	  if (!loadbase_set && (i_phdrs[i].p_offset & -i_phdrs[i].p_align) == 0)
+	    {
+	      loadbase = ehdr_vma - (i_phdrs[i].p_vaddr & -i_phdrs[i].p_align);
+	      /* Only the first segment indicates the file bias.
+	         DATA sections may have P_VADDR arbitrarily higher.  */
+	      loadbase_set = 1;
+	    }
 
 	  last_phdr = &i_phdrs[i];
 	}
@@ -1775,7 +1782,7 @@ NAME(_bfd_elf,bfd_from_remote_memory)
 	if (end > (bfd_vma) contents_size)
 	  end = contents_size;
 	err = target_read_memory ((loadbase + i_phdrs[i].p_vaddr)
-				  & -i_phdrs[i].p_align,
+				  /* & -i_phdrs[i].p_align */,
 				  contents + start, end - start);
 	if (err)
 	  {
Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.923
diff -u -p -r1.923 Makefile.in
--- gdb/Makefile.in	3 Jul 2007 12:14:43 -0000	1.923
+++ gdb/Makefile.in	25 Jul 2007 01:00:40 -0000
@@ -1888,7 +1888,7 @@ corelow.o: corelow.c $(defs_h) $(arch_ut
 	$(inferior_h) $(symtab_h) $(command_h) $(bfd_h) $(target_h) \
 	$(gdbcore_h) $(gdbthread_h) $(regcache_h) $(regset_h) $(symfile_h) \
 	$(exec_h) $(readline_h) $(gdb_assert_h) \
-	$(exceptions_h) $(solib_h)
+	$(exceptions_h) $(solib_h) $(auxv_h) $(elf_common_h)
 core-regset.o: core-regset.c $(defs_h) $(command_h) $(gdbcore_h) \
 	$(inferior_h) $(target_h) $(regcache_h) $(gdb_string_h) $(gregset_h)
 cp-abi.o: cp-abi.c $(defs_h) $(value_h) $(cp_abi_h) $(command_h) $(gdbcmd_h) \
@@ -2709,7 +2709,7 @@ symfile.o: symfile.c $(defs_h) $(bfdlink
 	$(gdb_stabs_h) $(gdb_obstack_h) $(completer_h) $(bcache_h) \
 	$(hashtab_h) $(readline_h) $(gdb_assert_h) $(block_h) \
 	$(gdb_string_h) $(gdb_stat_h) $(observer_h) $(exec_h) \
-	$(parser_defs_h) $(varobj_h)
+	$(parser_defs_h) $(varobj_h) $(gdb_stdint_h) $(libbfd_h) $(elf_bfd_h)
 symfile-mem.o: symfile-mem.c $(defs_h) $(symtab_h) $(gdbcore_h) \
 	$(objfiles_h) $(exceptions_h) $(gdbcmd_h) $(target_h) $(value_h) \
 	$(symfile_h) $(observer_h) $(auxv_h) $(elf_common_h)
Index: gdb/corelow.c
===================================================================
RCS file: /cvs/src/src/gdb/corelow.c,v
retrieving revision 1.63
diff -u -p -r1.63 corelow.c
--- gdb/corelow.c	16 Jun 2007 17:16:25 -0000	1.63
+++ gdb/corelow.c	25 Jul 2007 01:00:41 -0000
@@ -46,6 +46,8 @@
 #include "gdb_assert.h"
 #include "exceptions.h"
 #include "solib.h"
+#include "auxv.h"
+#include "elf/common.h"
 
 
 #ifndef O_LARGEFILE
@@ -253,6 +255,50 @@ add_to_thread_list (bfd *abfd, asection 
     inferior_ptid = pid_to_ptid (thread_id);	/* Yes, make it current */
 }
 
+static void 
+build_id_locate_exec (int from_tty)
+{
+  CORE_ADDR at_entry;
+  struct build_id *build_id;
+  char *exec_filename, *debug_filename;
+
+  if (exec_bfd != NULL)
+    return;
+
+  if (target_auxv_search (&current_target, AT_ENTRY, &at_entry) <= 0)
+    return;
+
+  build_id = build_id_addr_get (at_entry);
+  if (build_id == NULL)
+    return;
+
+  exec_filename = build_id_to_filename (build_id, debug_file_directory, 0);
+  if (exec_filename != NULL)
+    exec_file_attach (exec_filename, from_tty);
+
+  /* `.note.gnu.build-id' section exists even for files without a separate
+     debuginfo.  */
+  debug_filename = build_id_to_filename (build_id, debug_file_directory, 1);
+  if (debug_filename != NULL)
+    {
+      symbol_file_add_main (debug_filename, from_tty);
+      xfree (debug_filename);
+    }
+  else if (exec_filename != NULL)
+    symbol_file_add_main (exec_filename, from_tty);
+
+  xfree (exec_filename);
+
+  if (exec_filename != NULL)
+    {
+#ifdef SOLIB_ADD
+      SOLIB_ADD (NULL, 0, &current_target, auto_solib_add);
+#else
+      solib_add (NULL, 0, &current_target, auto_solib_add);
+#endif
+    }
+}
+
 /* This routine opens and sets up the core file bfd.  */
 
 static void
@@ -377,6 +423,9 @@ core_open (char *filename, int from_tty)
       /* Fetch all registers from core file.  */
       target_fetch_registers (get_current_regcache (), -1);
 
+      /* Find build_id identifiers.  */
+      build_id_locate_exec (from_tty);
+
       /* Now, set up the frame cache, and print the top of stack.  */
       reinit_frame_cache ();
       print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
Index: gdb/solib-svr4.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-svr4.c,v
retrieving revision 1.70
diff -u -p -r1.70 solib-svr4.c
--- gdb/solib-svr4.c	12 Jul 2007 20:15:24 -0000	1.70
+++ gdb/solib-svr4.c	25 Jul 2007 01:00:42 -0000
@@ -749,10 +749,29 @@ svr4_current_sos (void)
 		     safe_strerror (errcode));
 	  else
 	    {
-	      strncpy (new->so_name, buffer, SO_NAME_MAX_PATH_SIZE - 1);
-	      new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+	      struct build_id *build_id;
+
+	      strncpy (new->so_original_name, buffer, SO_NAME_MAX_PATH_SIZE - 1);
+	      new->so_original_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
 	      xfree (buffer);
-	      strcpy (new->so_original_name, new->so_name);
+	      /* May get overwritten below.  */
+	      strcpy (new->so_name, new->so_original_name);
+
+	      build_id = build_id_addr_get (LM_DYNAMIC_FROM_LINK_MAP (new));
+	      if (build_id != NULL)
+	        {
+		  char *name;
+
+		  name = build_id_to_filename (build_id, debug_file_directory,
+					       0);
+		  if (name != NULL)
+		    {
+		      strncpy (new->so_name, name, SO_NAME_MAX_PATH_SIZE - 1);
+		      new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+		      xfree (name);
+		    }
+		  xfree (build_id);
+		}
 	    }
 
 	  /* If this entry has no name, or its name matches the name
Index: gdb/symfile.c
===================================================================
RCS file: /cvs/src/src/gdb/symfile.c,v
retrieving revision 1.188
diff -u -p -r1.188 symfile.c
--- gdb/symfile.c	3 Jul 2007 15:32:20 -0000	1.188
+++ gdb/symfile.c	25 Jul 2007 01:00:42 -0000
@@ -53,6 +53,9 @@
 #include "exec.h"
 #include "parser-defs.h"
 #include "varobj.h"
+#include "gdb_stdint.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
 
 #include <sys/types.h>
 #include <fcntl.h>
@@ -61,6 +64,7 @@
 #include <ctype.h>
 #include <time.h>
 #include <sys/time.h>
+#include <sys/param.h>
 
 
 int (*deprecated_ui_load_progress_hook) (const char *section, unsigned long num);
@@ -1084,7 +1088,7 @@ symbol_file_add_with_addrs_or_offsets (b
     }
 
   debugfile = find_separate_debug_file (objfile);
-  if (debugfile)
+  if (debugfile && strcmp (debugfile, objfile->name) != 0)
     {
       if (addrs != NULL)
 	{
@@ -1225,15 +1229,346 @@ symbol_file_clear (int from_tty)
       printf_unfiltered (_("No symbol file now.\n"));
 }
 
+/* Locate NT_GNU_BUILD_ID and return its matching debug filename.
+   FIXME: NOTE decoding should be unified with the BFD core notes decoding.  */
+
+struct build_id *
+build_id_buf_get (bfd *abfd, gdb_byte *buf, bfd_size_type size)
+{
+  bfd_byte *p;
+
+  p = buf;
+  while (p < buf + size)
+    {
+      /* FIXME: bad alignment assumption.  */
+      Elf_External_Note *xnp = (Elf_External_Note *) p;
+      size_t namesz = H_GET_32 (abfd, xnp->namesz);
+      size_t descsz = H_GET_32 (abfd, xnp->descsz);
+      bfd_byte *descdata = xnp->name + BFD_ALIGN (namesz, 4);
+
+      if (H_GET_32 (abfd, xnp->type) == NT_GNU_BUILD_ID
+	  && namesz == sizeof "GNU"
+	  && memcmp (xnp->name, "GNU", sizeof "GNU") == 0)
+	{
+	  size_t size = descsz;
+	  gdb_byte *data = (void *) descdata;
+	  struct build_id *retval;
+
+	  retval = xmalloc (sizeof *retval - 1 + size);
+	  retval->size = size;
+	  memcpy (retval->data, data, size);
+
+	  return retval;
+	}
+      p = descdata + BFD_ALIGN (descsz, 4);
+    }
+  return NULL;
+}
+
+struct build_id *
+build_id_bfd_get (bfd *abfd)
+{
+  Elf_Internal_Ehdr *ehdr;
+  Elf_Internal_Phdr *phdr;
+  int i;
+
+  if (!bfd_check_format (abfd, bfd_object)
+      || bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+    return NULL;
+
+  ehdr = elf_tdata (abfd)->elf_header;
+
+  if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
+    return NULL;
+
+  phdr = elf_tdata (abfd)->phdr;
+
+  for (i = 0; i < ehdr->e_phnum; i++)
+    if (phdr[i].p_type == PT_NOTE && phdr[i].p_filesz > 0)
+      {
+	Elf_Internal_Phdr *hdr = &phdr[i];
+	struct build_id *retval;
+	gdb_byte *buf;
+
+	if (bfd_seek (abfd, hdr->p_offset, SEEK_SET) != 0)
+	  return NULL;
+
+	buf = xmalloc (hdr->p_filesz);
+
+	if (bfd_bread (buf, hdr->p_filesz, abfd) != hdr->p_filesz)
+	  {
+	    xfree (buf);
+	    return NULL;
+	  }
+
+	retval = build_id_buf_get (abfd, buf, hdr->p_filesz);
+	if (retval != NULL)
+	  {
+	    xfree (buf);
+	    return retval;
+	  }
+      }
+  return NULL;
+}
+
+/* Transfer memory without any failures on the parts missing in the core file.
+   FIXME: Avoid BFD warnings:
+   BFD: <in-memory>: invalid string offset 27 >= 0 for section `'  */
+
+static asection *build_id_read_memory_sect;
+
+static int
+build_id_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
+{
+  bfd_size_type size, transfer;
+  bfd_vma vma = bfd_section_vma (build_id_read_memory_sect->owner,
+				 build_id_read_memory_sect);
+
+  if (memaddr >= vma)
+    memaddr -= vma;
+  else
+    {
+      /* Not cleared.  Should not happen.  */
+      myaddr += vma - memaddr;
+      if (len >= vma - memaddr)
+	len -= vma - memaddr;
+      else
+        len = 0;
+      memaddr = 0;
+    }
+
+  size = bfd_get_section_size (build_id_read_memory_sect);
+  transfer = len;
+  if (memaddr >= size)
+    transfer = 0;
+  else if (memaddr + len >= size)
+    transfer = size - memaddr;
+  else
+    transfer = len;
+  if (transfer > 0
+      && !bfd_get_section_contents (build_id_read_memory_sect->owner,
+				    build_id_read_memory_sect,
+				    myaddr, memaddr, transfer))
+    return EIO;
+  /* BFD tries to read from arbitrary memory - far VMA areas.
+     Do not: memset (myaddr + transfer, 0, len - transfer);
+     It would overwrite the first page content.
+     FIXME: Fix BFD, it may leave unitialized memory here.  */
+  return 0;
+}
+
+static struct build_id *
+build_id_try_sect (asection *sect)
+{
+  bfd *frag_bfd;
+  bfd_vma sect_vma = bfd_section_vma (core_bfd, sect);
+  bfd_vma loadbase;
+  struct build_id *retval;
+
+  build_id_read_memory_sect = sect;
+  frag_bfd = bfd_elf_bfd_from_remote_memory (core_bfd, sect_vma, &loadbase,
+					     build_id_read_memory);
+  if (frag_bfd == NULL)
+    return NULL;
+
+  retval = build_id_bfd_get (frag_bfd);
+
+  if (!bfd_close (frag_bfd))
+    warning (_("cannot close \"%s\": %s"), bfd_get_filename (frag_bfd),
+	     bfd_errmsg (bfd_get_error ()));
+
+  return retval;
+}
+
+/* BUILD_ID_ADDR_GET gets ADDR located somewhere in the object.
+   Find the first section before ADDR containing an ELF header.
+   We rely on the fact the sections from multiple files do not mix.
+   FIXME: We should check ADDR is contained _inside_ the section with possibly
+   missing content (P_FILESZ < P_MEMSZ).  These omitted sections are currently
+   hidden by _BFD_ELF_MAKE_SECTION_FROM_PHDR.  */
+
+static CORE_ADDR build_id_addr;
+struct build_id_addr_sect
+  {
+    struct build_id_addr_sect *next;
+    asection *sect;
+  };
+static struct build_id_addr_sect *build_id_addr_sect;
+
+static void build_id_addr_candidate (bfd *abfd, asection *sect, void *obj)
+{
+  bfd_vma sect_vma = bfd_section_vma (abfd, sect);
+
+  if (build_id_addr >= bfd_section_vma (abfd, sect))
+    {
+      struct build_id_addr_sect *candidate;
+
+      candidate = xmalloc (sizeof *candidate);
+      candidate->next = build_id_addr_sect;
+      build_id_addr_sect = candidate;
+      candidate->sect = sect;
+    }
+}
+
+struct build_id *
+build_id_addr_get (CORE_ADDR addr)
+{
+  struct build_id_addr_sect *candidate;
+  struct build_id *retval = NULL;
+
+  if (core_bfd == NULL)
+    return NULL;
+
+  build_id_addr = addr;
+  gdb_assert (build_id_addr_sect == NULL);
+  bfd_map_over_sections (core_bfd, build_id_addr_candidate, NULL);
+
+  /* Sections are sorted in the high-to-low VMAs order.  */
+  for (candidate = build_id_addr_sect; candidate != NULL;
+       candidate = candidate->next)
+    {
+      retval = build_id_try_sect (build_id_addr_sect->sect);
+      if (retval != NULL)
+        break;
+    }
+
+  while (build_id_addr_sect != NULL)
+    {
+      candidate = build_id_addr_sect;
+      build_id_addr_sect = candidate->next;
+      xfree (candidate);
+    }
+
+  return retval;
+}
+
+/* Try to resolve symlinks in `/usr/lib/debug/.build-id/' for the user.  */
+
 static char *
-get_debug_link_info (struct objfile *objfile, unsigned long *crc32_out)
+build_id_resolve (char *filename)
+{
+  char dest[MAXPATHLEN];
+  ssize_t dest_len;
+
+  dest_len = readlink (filename, dest, sizeof dest - 1);
+  if (dest_len >= 0)
+    {
+      dest[dest_len] = 0;
+      return xstrdup (dest);
+    }
+  else if (errno == ENOENT)
+    return NULL;
+
+  return filename;
+}
+
+static int
+build_id_verify (const char *filename, struct build_id *check, int is_debug)
+{
+  bfd *abfd;
+  struct build_id *found = NULL;
+  int retval = 0;
+
+  abfd = bfd_openr (filename, gnutarget);
+  if (abfd == NULL)
+    {
+      warning (_("cannot open \"%s\" to verify its build-id: %s"),
+	       filename, bfd_errmsg (bfd_get_error ()));
+      return 0;
+    }
+
+  /* Separate debuginfo files have corrupted PHDR but SHDR is correct there.
+     Core files may have missing (corrupt) SHDR but PDHR is correct there.  */
+  if (!is_debug)
+    found = build_id_bfd_get (abfd);
+  else if (bfd_check_format (abfd, bfd_object)
+	   && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+    {
+      asection *sect = NULL;
+      bfd_byte *buf;
+
+      sect = bfd_get_section_by_name (abfd, ".note.gnu.build-id");
+      if (sect != NULL && bfd_malloc_and_get_section (abfd, sect, &buf))
+        {
+          found = build_id_buf_get (abfd, buf,
+				    bfd_get_section_limit (abfd, sect));
+	  xfree (buf);
+	}
+    }
+
+  if (found == NULL)
+    warning (_("File \"%s\" has no build-id, file skipped"), filename);
+  else if (found->size != check->size
+           || memcmp (found->data, check->data, found->size) != 0)
+    warning (_("File \"%s\" has a different build-id, file skipped"), filename);
+  else
+    retval = 1;
+
+  if (!bfd_close (abfd))
+    warning (_("cannot close \"%s\": %s"), filename,
+	     bfd_errmsg (bfd_get_error ()));
+  return retval;
+}
+
+char *
+build_id_to_filename (struct build_id *build_id, const char *prefix,
+		      int add_debug_suffix)
+{
+  char *link, *s, *retval;
+  gdb_byte *data = build_id->data;
+  size_t size = build_id->size;
+
+  /* DEBUG_FILE_DIRECTORY/.build-id/ab/cdef */
+  link = xmalloc (strlen (prefix) + strlen ("/.build-id/") + 1
+		  + 2 * size
+		  + (add_debug_suffix ? sizeof ".debug" - 1 : 0)
+		  + 1);
+  s = link + sprintf (link, "%s/.build-id/", prefix);
+  if (size > 0)
+    {
+      size--;
+      s += sprintf (s, "%02x", (unsigned) *data++);
+    }
+  if (size > 0)
+    *s++ = '/';
+  while (size-- > 0)
+    s += sprintf (s, "%02x", (unsigned) *data++);
+  if (add_debug_suffix)
+    strcpy (s, ".debug");
+  else
+    *s = 0;
+
+  retval = build_id_resolve (link);
+  /* BUILD_ID_RESOLVE may return the original parameter not duplicated.  */
+  if (retval == NULL || retval != link)
+    xfree (link);
+
+  if (retval != NULL && !build_id_verify (retval, build_id, add_debug_suffix))
+    {
+      xfree (retval);
+      retval = NULL;
+    }
+
+  return retval;
+}
+
+struct debug_link_info
+  {
+    uint32_t crc32;
+    char basename_debug[1];
+  };
+
+/* Read the `.gnu_debuglink' section.  */
+
+static struct debug_link_info *
+get_debug_link_info (struct objfile *objfile)
 {
   asection *sect;
   bfd_size_type debuglink_size;
-  unsigned long crc32;
   char *contents;
   int crc_offset;
   unsigned char *p;
+  struct debug_link_info *retval;
 
   sect = bfd_get_section_by_name (objfile->obfd, ".gnu_debuglink");
 
@@ -1242,7 +1577,8 @@ get_debug_link_info (struct objfile *obj
 
   debuglink_size = bfd_section_size (objfile->obfd, sect);
 
-  contents = xmalloc (debuglink_size);
+  retval = xmalloc (sizeof *retval - 1 + debuglink_size);
+  contents = retval->basename_debug;
   bfd_get_section_contents (objfile->obfd, sect, contents,
 			    (file_ptr)0, (bfd_size_type)debuglink_size);
 
@@ -1250,30 +1586,101 @@ get_debug_link_info (struct objfile *obj
   crc_offset = strlen (contents) + 1;
   crc_offset = (crc_offset + 3) & ~3;
 
-  crc32 = bfd_get_32 (objfile->obfd, (bfd_byte *) (contents + crc_offset));
+  retval->crc32 = bfd_get_32 (objfile->obfd,
+			      (bfd_byte *) (contents + crc_offset));
 
-  *crc32_out = crc32;
-  return contents;
+  return retval;
 }
 
+struct debug_info
+  {
+    /* Both pointers may be NULL if the section is not present.  */
+    struct debug_link_info *debug_link;
+    struct build_id *build_id;
+    /* Never NULL, to be freed if DEBUG_LINK is NULL.  */
+    char *basename_debug;
+  };
+
+/* Returns TRUE if a separate debug file may exist.
+   If FALSE is returned FREE_DEBUG_INFO must not be called.  */
+
 static int
-separate_debug_file_exists (const char *name, unsigned long crc)
+get_debug_info (struct objfile *objfile, struct debug_info *debug_info)
 {
-  unsigned long file_crc = 0;
-  int fd;
-  gdb_byte buffer[8*1024];
-  int count;
+  debug_info->debug_link = get_debug_link_info (objfile);
+  debug_info->build_id = build_id_bfd_get (objfile->obfd);
 
-  fd = open (name, O_RDONLY | O_BINARY);
-  if (fd < 0)
+  if (debug_info->debug_link == NULL && debug_info->build_id == NULL)
     return 0;
 
-  while ((count = read (fd, buffer, sizeof (buffer))) > 0)
-    file_crc = gnu_debuglink_crc32 (file_crc, buffer, count);
+  if (debug_info->debug_link != NULL)
+    debug_info->basename_debug = debug_info->debug_link->basename_debug;
+  else
+    xasprintf (&debug_info->basename_debug, "%s.debug",
+	       lbasename (objfile->name));
+
+  return 1;
+}
+
+static void
+free_debug_info (struct debug_info *debug_info)
+{
+  if (debug_info->debug_link != NULL)
+    xfree (debug_info->debug_link);
+  else
+    xfree (debug_info->basename_debug);
+  xfree (debug_info->build_id);
+}
+
+static char *
+separate_debug_file_exists (const char *path_debug, const char *path_build_id,
+			    struct debug_info *info)
+{
+  char *name_debug;
+
+  xasprintf (&name_debug, "%s/%s", path_debug, info->basename_debug);
+
+  /* On missing `.gnu_debuglink' but with existing `.note.gnu.build_id'
+     try just the `BASENAME.debug' existence without checking its CRC.  */
+
+  if (info->debug_link == NULL && access (name_debug, R_OK) == 0)
+    return name_debug;
+
+  if (info->build_id != NULL)
+    {
+      char *build_id_name;
+
+      build_id_name = build_id_to_filename (info->build_id, path_build_id, 1);
+      if (build_id_name != NULL)
+        {
+	  xfree (name_debug);
+	  return build_id_name;
+	}
+    }
+
+  if (info->debug_link != NULL)
+    {
+      int fd;
+
+      fd = open (name_debug, O_RDONLY | O_BINARY);
+      if (fd >= 0)
+        {
+	  unsigned long file_crc = 0;
+	  gdb_byte buffer[8*1024];
+	  int count;
+
+	  while ((count = read (fd, buffer, sizeof (buffer))) > 0)
+	    file_crc = gnu_debuglink_crc32 (file_crc, buffer, count);
 
-  close (fd);
+	  close (fd);
 
-  return crc == file_crc;
+	  if (info->debug_link->crc32 == file_crc)
+	    return name_debug;
+	}
+    }
+
+  xfree (name_debug);
+  return NULL;
 }
 
 char *debug_file_directory = NULL;
@@ -1294,18 +1701,16 @@ static char *
 find_separate_debug_file (struct objfile *objfile)
 {
   asection *sect;
-  char *basename;
   char *dir;
   char *debugfile;
   char *name_copy;
   char *canon_name;
   bfd_size_type debuglink_size;
-  unsigned long crc32;
   int i;
+  struct debug_info info;
+  char *retval;
 
-  basename = get_debug_link_info (objfile, &crc32);
-
-  if (basename == NULL)
+  if (! get_debug_info (objfile, &info))
     return NULL;
 
   dir = xstrdup (objfile->name);
@@ -1320,77 +1725,73 @@ find_separate_debug_file (struct objfile
 	break;
     }
   gdb_assert (i >= 0 && IS_DIR_SEPARATOR (dir[i]));
-  dir[i+1] = '\0';
-
-  debugfile = alloca (strlen (debug_file_directory) + 1
-                      + strlen (dir)
-                      + strlen (DEBUG_SUBDIRECTORY)
-                      + strlen ("/")
-                      + strlen (basename)
-                      + 1);
+  dir[i] = '\0';
 
   /* First try in the same directory as the original file.  */
-  strcpy (debugfile, dir);
-  strcat (debugfile, basename);
-
-  if (separate_debug_file_exists (debugfile, crc32))
+  retval = separate_debug_file_exists (dir, dir, &info);
+  if (retval != NULL)
     {
-      xfree (basename);
+      free_debug_info (&info);
       xfree (dir);
-      return xstrdup (debugfile);
+      return retval;
     }
 
+  debugfile = alloca (strlen (debug_file_directory) + 1
+                      + strlen (dir)
+		      + strlen ("/")
+                      + strlen (DEBUG_SUBDIRECTORY)
+                      + 1);
+
   /* Then try in the subdirectory named DEBUG_SUBDIRECTORY.  */
   strcpy (debugfile, dir);
-  strcat (debugfile, DEBUG_SUBDIRECTORY);
   strcat (debugfile, "/");
-  strcat (debugfile, basename);
+  strcat (debugfile, DEBUG_SUBDIRECTORY);
 
-  if (separate_debug_file_exists (debugfile, crc32))
+  retval = separate_debug_file_exists (debugfile, debugfile, &info);
+  if (retval != NULL)
     {
-      xfree (basename);
+      free_debug_info (&info);
       xfree (dir);
-      return xstrdup (debugfile);
+      return retval;
     }
 
-  /* Then try in the global debugfile directory.  */
+  /* Then try in the global debugfile directory.
+     DIR needs to be prosent for `.gnu_debuglink' but it must not be present
+     for `.note.gnu.build_id'.  */
   strcpy (debugfile, debug_file_directory);
   strcat (debugfile, "/");
   strcat (debugfile, dir);
-  strcat (debugfile, basename);
 
-  if (separate_debug_file_exists (debugfile, crc32))
+  retval = separate_debug_file_exists (debugfile, debug_file_directory, &info);
+  if (retval != NULL)
     {
-      xfree (basename);
+      free_debug_info (&info);
       xfree (dir);
-      return xstrdup (debugfile);
+      return retval;
     }
 
   /* If the file is in the sysroot, try using its base path in the
      global debugfile directory.  */
   canon_name = lrealpath (dir);
-  if (canon_name
-      && strncmp (canon_name, gdb_sysroot, strlen (gdb_sysroot)) == 0
-      && IS_DIR_SEPARATOR (canon_name[strlen (gdb_sysroot)]))
+  if (canon_name && strcmp (canon_name, gdb_sysroot) == 0)
     {
       strcpy (debugfile, debug_file_directory);
       strcat (debugfile, canon_name + strlen (gdb_sysroot));
-      strcat (debugfile, "/");
-      strcat (debugfile, basename);
 
-      if (separate_debug_file_exists (debugfile, crc32))
+      retval = separate_debug_file_exists (debugfile, debugfile, &info);
+      if (retval != NULL)
 	{
 	  xfree (canon_name);
-	  xfree (basename);
+	  free_debug_info (&info);
 	  xfree (dir);
-	  return xstrdup (debugfile);
+	  return retval;
 	}
     }
   
   if (canon_name)
     xfree (canon_name);
 
-  xfree (basename);
+  free_debug_info (&info);
   xfree (dir);
   return NULL;
 }
Index: gdb/symfile.h
===================================================================
RCS file: /cvs/src/src/gdb/symfile.h,v
retrieving revision 1.39
diff -u -p -r1.39 symfile.h
--- gdb/symfile.h	18 Jun 2007 15:46:38 -0000	1.39
+++ gdb/symfile.h	25 Jul 2007 01:00:43 -0000
@@ -352,6 +352,18 @@ extern int symfile_map_offsets_to_segmen
 struct symfile_segment_data *get_symfile_segment_data (bfd *abfd);
 void free_symfile_segment_data (struct symfile_segment_data *data);
 
+/* build-id support.  */
+struct build_id
+  {
+    size_t size;
+    gdb_byte data[1];
+  };
+
+extern struct build_id *build_id_addr_get (CORE_ADDR addr);
+extern struct build_id *build_id_bfd_get (bfd *abfd);
+extern char *build_id_to_filename (struct build_id *build_id,
+				   const char *prefix, int add_debug_suffix);
+
 /* From dwarf2read.c */
 
 extern int dwarf2_has_info (struct objfile *);

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]