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 (¤t_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, ¤t_target, auto_solib_add); +#else + solib_add (NULL, 0, ¤t_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 #include @@ -61,6 +64,7 @@ #include #include #include +#include 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: : 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 *);