diff --git a/gdb-6.6-buildid-locate.patch b/gdb-6.6-buildid-locate.patch new file mode 100644 index 0000000..6307c33 --- /dev/null +++ b/gdb-6.6-buildid-locate.patch @@ -0,0 +1,781 @@ +diff -u -rup gdb-6.6-orig/gdb/Makefile.in gdb-6.6/gdb/Makefile.in +--- gdb-6.6-orig/gdb/Makefile.in 2007-08-28 15:31:19.000000000 +0200 ++++ gdb-6.6/gdb/Makefile.in 2007-08-28 15:32:40.000000000 +0200 +@@ -1917,7 +1917,8 @@ 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) $(objfiles_h) \ ++ $(gdbcmd_h) + core-regset.o: core-regset.c $(defs_h) $(command_h) $(gdbcore_h) \ + $(inferior_h) $(target_h) $(gdb_string_h) $(gregset_h) + cp-abi.o: cp-abi.c $(defs_h) $(value_h) $(cp_abi_h) $(command_h) $(gdbcmd_h) \ +@@ -2785,7 +2786,8 @@ 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) $(elf_bfd_h) ++ $(parser_defs_h) $(elf_bfd_h) $(gdb_stdint_h) $(libbfd_h) $(elf_bfd_h) \ ++ $(elf_external_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) +diff -u -rup gdb-6.6-orig/gdb/corelow.c gdb-6.6/gdb/corelow.c +--- gdb-6.6-orig/gdb/corelow.c 2006-04-18 21:20:06.000000000 +0200 ++++ gdb-6.6/gdb/corelow.c 2007-08-28 15:31:56.000000000 +0200 +@@ -46,6 +46,10 @@ + #include "gdb_assert.h" + #include "exceptions.h" + #include "solib.h" ++#include "auxv.h" ++#include "elf/common.h" ++#include "objfiles.h" ++#include "gdbcmd.h" + + + #ifndef O_LARGEFILE +@@ -253,6 +257,70 @@ add_to_thread_list (bfd *abfd, asection + inferior_ptid = pid_to_ptid (thread_id); /* Yes, make it current */ + } + ++static int build_id_core_loads = 1; ++static void ++show_build_id_core_loads (struct ui_file *file, int from_tty, ++ struct cmd_list_element *c, const char *value) ++{ ++ fprintf_filtered (file, _("Automatic loading of the matching binaries " ++ "for core files is %s.\n"), value); ++} ++ ++static void ++build_id_locate_exec (int from_tty) ++{ ++ CORE_ADDR at_entry; ++ struct build_id *build_id; ++ char *exec_filename, *debug_filename; ++ char *build_id_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, &build_id_filename, 0); ++ if (exec_filename != NULL) ++ exec_file_attach (exec_filename, from_tty); ++ else ++ warning (_("Missing the matching executable file: %s"), build_id_filename); ++ xfree (build_id_filename); ++ ++ /* `.note.gnu.build-id' section exists even for files without a separate ++ debuginfo. */ ++ debug_filename = build_id_to_filename (build_id, &build_id_filename, 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); ++ if (symfile_objfile == NULL) ++ warning (_("Missing the matching executable's debug info file: %s"), ++ build_id_filename); ++ } ++ xfree (build_id_filename); ++ ++ 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 +445,10 @@ core_open (char *filename, int from_tty) + /* Fetch all registers from core file. */ + target_fetch_registers (-1); + ++ /* Find build_id identifiers. */ ++ if (build_id_core_loads != 0) ++ build_id_locate_exec (from_tty); ++ + /* Now, set up the frame cache, and print the top of stack. */ + flush_cached_frames (); + select_frame (get_current_frame ()); +@@ -662,4 +734,13 @@ _initialize_corelow (void) + + if (!coreops_suppress_target) + add_target (&core_ops); ++ ++ add_setshow_zinteger_cmd ("build-id-core-loads", class_files, ++ &build_id_core_loads, _("\ ++Set debugging of the build-id locator."), _("\ ++Show debugging of the build-id locator."), _("\ ++Enables printf debugging output."), ++ NULL, ++ show_build_id_core_loads, ++ &setlist, &showlist); + } +diff -u -rup gdb-6.6-orig/gdb/solib-svr4.c gdb-6.6/gdb/solib-svr4.c +--- gdb-6.6-orig/gdb/solib-svr4.c 2007-08-28 15:31:19.000000000 +0200 ++++ gdb-6.6/gdb/solib-svr4.c 2007-08-28 15:34:02.000000000 +0200 +@@ -943,10 +943,34 @@ svr4_current_sos (void) + } + else + { +- strncpy (new->so_name, buffer, SO_NAME_MAX_PATH_SIZE - 1); +- new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; +- xfree (buffer); +- strcpy (new->so_original_name, new->so_name); ++ 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'; ++ /* 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, *build_id_filename; ++ ++ /* Missing the build-id matching separate debug info file ++ would be handled while SO_NAME gets loaded. */ ++ name = build_id_to_filename (build_id, &build_id_filename, 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); ++ } ++ else ++ warning (_("Missing the matching library file: %s"), ++ build_id_filename); ++ xfree (build_id_filename); ++ xfree (build_id); ++ } ++ + if (debug_solib) + { + fprintf_unfiltered (gdb_stdlog, +diff -u -rup gdb-6.6-orig/gdb/symfile.c gdb-6.6/gdb/symfile.c +--- gdb-6.6-orig/gdb/symfile.c 2007-08-28 15:31:19.000000000 +0200 ++++ gdb-6.6/gdb/symfile.c 2007-08-28 15:36:22.000000000 +0200 +@@ -54,6 +54,9 @@ + #include "exec.h" + #include "parser-defs.h" + #include "elf-bfd.h" ++#include "gdb_stdint.h" ++#include "libbfd.h" ++#include "elf/external.h" + + #include + #include +@@ -62,6 +65,7 @@ + #include + #include + #include ++#include + + + int (*deprecated_ui_load_progress_hook) (const char *section, unsigned long num); +@@ -1120,16 +1124,62 @@ 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. */ ++ ++static int build_id_debug; ++static void ++show_build_id_debug (struct ui_file *file, int from_tty, ++ struct cmd_list_element *c, const char *value) ++{ ++ fprintf_filtered (file, _("Debugging of the build-id locator is %s.\n"), ++ value); ++} ++ + struct build_id + { + size_t size; + gdb_byte data[1]; + }; + +-/* Locate NT_GNU_BUILD_ID from ABFD and return its content. */ ++struct build_id * ++build_id_buf_get (bfd *templ, 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 (templ, xnp->namesz); ++ size_t descsz = H_GET_32 (templ, xnp->descsz); ++ bfd_byte *descdata = xnp->name + BFD_ALIGN (namesz, 4); ++ ++ if (H_GET_32 (templ, 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; ++} ++ ++/* Separate debuginfo files have corrupted PHDR but SHDR is correct there. ++ Locate NT_GNU_BUILD_ID from ABFD and return its content. */ + + static struct build_id * +-build_id_bfd_get (bfd *abfd) ++build_id_bfd_shdr_get (bfd *abfd) + { + struct build_id *retval; + +@@ -1145,6 +1195,348 @@ build_id_bfd_get (bfd *abfd) + return retval; + } + ++/* Core files may have missing (corrupt) SHDR but PDHR is correct there. ++ bfd_elf_bfd_from_remote_memory () has too much overhead by ++ allocating/reading all the available ELF PT_LOADs. */ ++ ++static struct build_id * ++build_id_phdr_get (bfd *templ, bfd_vma loadbase, unsigned e_phnum, ++ Elf_Internal_Phdr *i_phdr) ++{ ++ int i; ++ struct build_id *retval = NULL; ++ ++ for (i = 0; i < e_phnum; i++) ++ if (i_phdr[i].p_type == PT_NOTE && i_phdr[i].p_filesz > 0) ++ { ++ Elf_Internal_Phdr *hdr = &i_phdr[i]; ++ gdb_byte *buf; ++ int err; ++ ++ buf = xmalloc (hdr->p_filesz); ++ err = target_read_memory (loadbase + i_phdr[i].p_vaddr, buf, ++ hdr->p_filesz); ++ if (err == 0) ++ retval = build_id_buf_get (templ, buf, hdr->p_filesz); ++ else ++ retval = NULL; ++ xfree (buf); ++ if (retval != NULL) ++ break; ++ } ++ return retval; ++} ++ ++/* First we validate the file by reading in the ELF header and checking ++ the magic number. */ ++ ++static inline bfd_boolean ++elf_file_p (Elf64_External_Ehdr *x_ehdrp64) ++{ ++ gdb_assert (sizeof (Elf64_External_Ehdr) >= sizeof (Elf32_External_Ehdr)); ++ gdb_assert (offsetof (Elf64_External_Ehdr, e_ident) ++ == offsetof (Elf32_External_Ehdr, e_ident)); ++ gdb_assert (sizeof (((Elf64_External_Ehdr *) 0)->e_ident) ++ == sizeof (((Elf32_External_Ehdr *) 0)->e_ident)); ++ ++ return ((x_ehdrp64->e_ident[EI_MAG0] == ELFMAG0) ++ && (x_ehdrp64->e_ident[EI_MAG1] == ELFMAG1) ++ && (x_ehdrp64->e_ident[EI_MAG2] == ELFMAG2) ++ && (x_ehdrp64->e_ident[EI_MAG3] == ELFMAG3)); ++} ++ ++/* Translate an ELF file header in external format into an ELF file header in ++ internal format. */ ++ ++#define H_GET_WORD(bfd, ptr) (is64 ? H_GET_64 (bfd, (ptr)) \ ++ : H_GET_32 (bfd, (ptr))) ++#define H_GET_SIGNED_WORD(bfd, ptr) (is64 ? H_GET_S64 (bfd, (ptr)) \ ++ : H_GET_S32 (bfd, (ptr))) ++ ++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 ++} ++ ++/* Translate an ELF program header table entry in external format into an ++ ELF program header table entry in internal format. */ ++ ++void ++elf_swap_phdr_in (bfd *abfd, ++ const Elf64_External_Phdr *src64, ++ Elf_Internal_Phdr *dst) ++{ ++ int is64 = bfd_get_arch_size (abfd) == 64; ++#define SRC(field) (is64 ? src64->field \ ++ : ((const Elf32_External_Phdr *) src64)->field) ++ ++ int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma; ++ ++ dst->p_type = H_GET_32 (abfd, SRC (p_type)); ++ dst->p_flags = H_GET_32 (abfd, SRC (p_flags)); ++ dst->p_offset = H_GET_WORD (abfd, SRC (p_offset)); ++ if (signed_vma) ++ { ++ dst->p_vaddr = H_GET_SIGNED_WORD (abfd, SRC (p_vaddr)); ++ dst->p_paddr = H_GET_SIGNED_WORD (abfd, SRC (p_paddr)); ++ } ++ else ++ { ++ dst->p_vaddr = H_GET_WORD (abfd, SRC (p_vaddr)); ++ dst->p_paddr = H_GET_WORD (abfd, SRC (p_paddr)); ++ } ++ dst->p_filesz = H_GET_WORD (abfd, SRC (p_filesz)); ++ dst->p_memsz = H_GET_WORD (abfd, SRC (p_memsz)); ++ dst->p_align = H_GET_WORD (abfd, SRC (p_align)); ++ ++#undef SRC ++} ++ ++#undef H_GET_SIGNED_WORD ++#undef H_GET_WORD ++ ++static Elf_Internal_Phdr * ++elf_get_phdr (bfd *templ, bfd_vma ehdr_vma, unsigned *e_phnum_pointer, ++ bfd_vma *loadbase_pointer) ++{ ++ /* sizeof (Elf64_External_Ehdr) >= sizeof (Elf32_External_Ehdr) */ ++ Elf64_External_Ehdr x_ehdr64; /* Elf file header, external form */ ++ Elf_Internal_Ehdr i_ehdr; /* Elf file header, internal form */ ++ bfd_size_type x_phdrs_size; ++ gdb_byte *x_phdrs_ptr; ++ Elf_Internal_Phdr *i_phdrs; ++ int err; ++ unsigned int i; ++ bfd_vma loadbase; ++ int loadbase_set; ++ ++ gdb_assert (templ != NULL); ++ gdb_assert (sizeof (Elf64_External_Ehdr) >= sizeof (Elf32_External_Ehdr)); ++ ++ /* Read in the ELF header in external format. */ ++ err = target_read_memory (ehdr_vma, (bfd_byte *) &x_ehdr64, sizeof x_ehdr64); ++ if (err) ++ { ++ if (build_id_debug) ++ warning (_("build-id: Error reading ELF header at address 0x%lx"), ++ (unsigned long) ehdr_vma); ++ return NULL; ++ } ++ ++ /* Now check to see if we have a valid ELF file, and one that BFD can ++ make use of. The magic number must match, the address size ('class') ++ and byte-swapping must match our XVEC entry. */ ++ ++ if (! elf_file_p (&x_ehdr64) ++ || x_ehdr64.e_ident[EI_VERSION] != EV_CURRENT ++ || !((bfd_get_arch_size (templ) == 64 ++ && x_ehdr64.e_ident[EI_CLASS] == ELFCLASS64) ++ || (bfd_get_arch_size (templ) == 32 ++ && x_ehdr64.e_ident[EI_CLASS] == ELFCLASS32))) ++ { ++ if (build_id_debug) ++ warning (_("build-id: Unrecognized ELF header at address 0x%lx"), ++ (unsigned long) ehdr_vma); ++ return NULL; ++ } ++ ++ /* Check that file's byte order matches xvec's */ ++ switch (x_ehdr64.e_ident[EI_DATA]) ++ { ++ case ELFDATA2MSB: /* Big-endian */ ++ if (! bfd_header_big_endian (templ)) ++ { ++ if (build_id_debug) ++ warning (_("build-id: Unrecognized " ++ "big-endian ELF header at address 0x%lx"), ++ (unsigned long) ehdr_vma); ++ return NULL; ++ } ++ break; ++ case ELFDATA2LSB: /* Little-endian */ ++ if (! bfd_header_little_endian (templ)) ++ { ++ if (build_id_debug) ++ warning (_("build-id: Unrecognized " ++ "little-endian ELF header at address 0x%lx"), ++ (unsigned long) ehdr_vma); ++ return NULL; ++ } ++ break; ++ case ELFDATANONE: /* No data encoding specified */ ++ default: /* Unknown data encoding specified */ ++ if (build_id_debug) ++ warning (_("build-id: Unrecognized " ++ "ELF header endianity at address 0x%lx"), ++ (unsigned long) ehdr_vma); ++ return NULL; ++ } ++ ++ elf_swap_ehdr_in (templ, &x_ehdr64, &i_ehdr); ++ ++ /* The file header tells where to find the program headers. ++ These are what we use to actually choose what to read. */ ++ ++ if (i_ehdr.e_phentsize != (bfd_get_arch_size (templ) == 64 ++ ? sizeof (Elf64_External_Phdr) ++ : sizeof (Elf32_External_Phdr)) ++ || i_ehdr.e_phnum == 0) ++ { ++ if (build_id_debug) ++ warning (_("build-id: Invalid ELF program headers from the ELF header " ++ "at address 0x%lx"), (unsigned long) ehdr_vma); ++ return NULL; ++ } ++ ++ x_phdrs_size = (bfd_get_arch_size (templ) == 64 ? sizeof (Elf64_External_Phdr) ++ : sizeof (Elf32_External_Phdr)); ++ ++ i_phdrs = xmalloc (i_ehdr.e_phnum * (sizeof *i_phdrs + x_phdrs_size)); ++ x_phdrs_ptr = (void *) &i_phdrs[i_ehdr.e_phnum]; ++ err = target_read_memory (ehdr_vma + i_ehdr.e_phoff, (bfd_byte *) x_phdrs_ptr, ++ i_ehdr.e_phnum * x_phdrs_size); ++ if (err) ++ { ++ free (i_phdrs); ++ if (build_id_debug) ++ warning (_("build-id: Error reading " ++ "ELF program headers at address 0x%lx"), ++ (unsigned long) ehdr_vma + i_ehdr.e_phoff); ++ return NULL; ++ } ++ ++ loadbase = ehdr_vma; ++ loadbase_set = 0; ++ for (i = 0; i < i_ehdr.e_phnum; ++i) ++ { ++ elf_swap_phdr_in (templ, (Elf64_External_Phdr *) ++ (x_phdrs_ptr + i * x_phdrs_size), &i_phdrs[i]); ++ /* IA-64 vDSO may have two mappings for one segment, where one mapping ++ is executable only, and one is read only. We must not use the ++ executable one (PF_R is the first one, PF_X the second one). */ ++ if (i_phdrs[i].p_type == PT_LOAD && (i_phdrs[i].p_flags & PF_R)) ++ { ++ /* Only the first PT_LOAD segment indicates the file bias. ++ Next segments may have P_VADDR arbitrarily higher. ++ If the first segment has P_VADDR zero any next segment must not ++ confuse us, the first one sets LOADBASE certainly enough. */ ++ if (!loadbase_set && i_phdrs[i].p_offset == 0) ++ { ++ loadbase = ehdr_vma - i_phdrs[i].p_vaddr; ++ loadbase_set = 1; ++ } ++ } ++ } ++ ++ if (build_id_debug) ++ warning (_("build-id: Found ELF header at address 0x%lx, loadbase 0x%lx"), ++ (unsigned long) ehdr_vma, (unsigned long) loadbase); ++ ++ *e_phnum_pointer = i_ehdr.e_phnum; ++ *loadbase_pointer = loadbase; ++ return i_phdrs; ++} ++ ++/* 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) ++{ ++ 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; ++ Elf_Internal_Phdr *i_phdr = NULL; ++ bfd_vma loadbase = 0; ++ unsigned e_phnum = 0; ++ ++ 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. ++ Stop the search on the first ELF header we find. ++ Do not continue the search even if it does not contain NT_GNU_BUILD_ID. */ ++ ++ for (candidate = build_id_addr_sect; candidate != NULL; ++ candidate = candidate->next) ++ { ++ i_phdr = elf_get_phdr (core_bfd, ++ bfd_section_vma (core_bfd, candidate->sect), ++ &e_phnum, &loadbase); ++ if (i_phdr != NULL) ++ break; ++ } ++ ++ if (i_phdr != NULL) ++ { ++ retval = build_id_phdr_get (core_bfd, loadbase, e_phnum, i_phdr); ++ xfree (i_phdr); ++ } ++ ++ while (build_id_addr_sect != NULL) ++ { ++ candidate = build_id_addr_sect; ++ build_id_addr_sect = candidate->next; ++ xfree (candidate); ++ } ++ ++ return retval; ++} ++ + /* Return if FILENAME has NT_GNU_BUILD_ID matching the CHECK value. */ + + static int +@@ -1159,7 +1551,7 @@ build_id_verify (const char *filename, s + if (abfd == NULL) + return 0; + +- found = build_id_bfd_get (abfd); ++ found = build_id_bfd_shdr_get (abfd); + + if (found == NULL) + warning (_("File \"%s\" has no build-id, file skipped"), filename); +@@ -1177,8 +1569,9 @@ build_id_verify (const char *filename, s + + static char *debug_file_directory = NULL; + +-static char * +-build_id_to_debug_filename (struct build_id *build_id) ++char * ++build_id_to_filename (struct build_id *build_id, char **link_return, ++ int add_debug_suffix) + { + char *link, *s, *retval = NULL; + gdb_byte *data = build_id->data; +@@ -1186,7 +1579,9 @@ build_id_to_debug_filename (struct build + + /* DEBUG_FILE_DIRECTORY/.build-id/ab/cdef */ + link = xmalloc (strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1 +- + 2 * size + (sizeof ".debug" - 1) + 1); ++ + 2 * size ++ + (add_debug_suffix ? sizeof ".debug" - 1 : 0) ++ + 1); + s = link + sprintf (link, "%s/.build-id/", debug_file_directory); + if (size > 0) + { +@@ -1197,12 +1592,14 @@ build_id_to_debug_filename (struct build + *s++ = '/'; + while (size-- > 0) + s += sprintf (s, "%02x", (unsigned) *data++); +- strcpy (s, ".debug"); ++ if (add_debug_suffix) ++ strcpy (s, ".debug"); ++ else ++ *s = 0; + + /* lrealpath() is expensive even for the usually non-existent files. */ + if (access (link, F_OK) == 0) + retval = lrealpath (link); +- xfree (link); + + if (retval != NULL && !build_id_verify (retval, build_id)) + { +@@ -1210,6 +1607,11 @@ build_id_to_debug_filename (struct build + retval = NULL; + } + ++ if (link_return != NULL) ++ *link_return = link; ++ else ++ xfree (link); ++ + return retval; + } + +@@ -1305,23 +1707,27 @@ find_separate_debug_file (struct objfile + unsigned long crc32; + int i; + struct build_id *build_id; ++ char *build_id_filename = NULL; + +- build_id = build_id_bfd_get (objfile->obfd); ++ build_id = build_id_bfd_shdr_get (objfile->obfd); + if (build_id != NULL) + { + char *build_id_name; + +- build_id_name = build_id_to_debug_filename (build_id); +- free (build_id); ++ build_id_name = build_id_to_filename (build_id, &build_id_filename, 1); ++ xfree (build_id); + /* Prevent looping on a stripped .debug file. */ + if (build_id_name != NULL && strcmp (build_id_name, objfile->name) == 0) + { +- warning (_("\"%s\": separate debug info file has no debug info"), ++ warning (_("\"%s\": The separate debug info file has no debug info"), + build_id_name); + xfree (build_id_name); + } + else if (build_id_name != NULL) +- return build_id_name; ++ { ++ xfree (build_id_filename); ++ return build_id_name; ++ } + } + + basename = get_debug_link_info (objfile, &crc32); +@@ -1329,7 +1735,10 @@ find_separate_debug_file (struct objfile + if (basename == NULL) + /* There's no separate debug info, hence there's no way we could + load it => no warning. */ +- return NULL; ++ { ++ xfree (build_id_filename); ++ return NULL; ++ } + + dir = xstrdup (objfile->name); + +@@ -1358,6 +1767,7 @@ find_separate_debug_file (struct objfile + + if (separate_debug_file_exists (debugfile, crc32, objfile->name)) + { ++ xfree (build_id_filename); + xfree (basename); + xfree (dir); + return xstrdup (debugfile); +@@ -1371,6 +1781,7 @@ find_separate_debug_file (struct objfile + + if (separate_debug_file_exists (debugfile, crc32, objfile->name)) + { ++ xfree (build_id_filename); + xfree (basename); + xfree (dir); + return xstrdup (debugfile); +@@ -1384,11 +1795,19 @@ find_separate_debug_file (struct objfile + + if (separate_debug_file_exists (debugfile, crc32, objfile->name)) + { ++ xfree (build_id_filename); + xfree (basename); + xfree (dir); + return xstrdup (debugfile); + } + ++ if (build_id_filename != NULL) ++ { ++ warning (_("Missing the separate debug info file: %s"), ++ build_id_filename); ++ xfree (build_id_filename); ++ } ++ + xfree (basename); + xfree (dir); + return NULL; +@@ -4024,4 +4443,12 @@ the global debug-file directory prepende + NULL, + show_debug_file_directory, + &setlist, &showlist); ++ ++ add_setshow_zinteger_cmd ("build-id", no_class, &build_id_debug, _("\ ++Set debugging of the build-id locator."), _("\ ++Show debugging of the build-id locator."), _("\ ++Enables printf debugging output."), ++ NULL, ++ show_build_id_debug, ++ &setdebuglist, &showdebuglist); + } +diff -u -rup gdb-6.6-orig/gdb/symfile.h gdb-6.6/gdb/symfile.h +--- gdb-6.6-orig/gdb/symfile.h 2005-12-17 23:34:03.000000000 +0100 ++++ gdb-6.6/gdb/symfile.h 2007-08-28 15:31:56.000000000 +0200 +@@ -322,6 +322,12 @@ extern bfd_byte *symfile_relocate_debug_ + extern void dwarf_build_psymtabs (struct objfile *, int, file_ptr, + unsigned int, file_ptr, unsigned int); + ++/* build-id support. */ ++struct build_id; ++extern struct build_id *build_id_addr_get (CORE_ADDR addr); ++extern char *build_id_to_filename (struct build_id *build_id, ++ char **link_return, int add_debug_suffix); ++ + /* From dwarf2read.c */ + + extern int dwarf2_has_info (struct objfile *); diff --git a/gdb-6.6-buildid-verify.patch b/gdb-6.6-buildid-verify.patch new file mode 100644 index 0000000..c806ad7 --- /dev/null +++ b/gdb-6.6-buildid-verify.patch @@ -0,0 +1,715 @@ +http://sources.redhat.com/ml/gdb-patches/2007-08/msg00478.html +v2 +[ Backported for GDB-6.6. ] + +2007-08-26 Jan Kratochvil + + * Makefile.in (symfile.o): Update dependencies. + * symfile.c (symbol_file_add_with_addrs_or_offsets): Initialize the + DEBUGFILE variable. FIND_SEPARATE_DEBUG_FILE called only if !PSYMTABS. + (struct build_id): New structure. + (build_id_bfd_get, build_id_verify, build_id_to_debug_filename): New. + (find_separate_debug_file): New variable BUILD_ID. + Call BUILD_ID_BFD_GET with BUILD_ID_TO_DEBUG_FILENAME as the first try. + +2007-08-26 Jan Kratochvil + + * lib/gdb.exp (build_id_debug_filename_get): New function. + * gdb.base/sepdebug.exp: Reflect the changes in the heading comment. + Remove the generate DEBUG file for the future testcase runs. + New testcase for the NT_GNU_BUILD_ID retrieval. + Move the final testing step to ... + (test_different_dir): ... a new function. + New parameter XFAIL to XFAIL all the tests performed. + New parameter TEST_DIFFERENT_DIR parametrizing the directory. + New parameter TYPE to PF_PREFIX all the tests performed. + +2007-08-26 Jan Kratochvil + + * gdb.texinfo (Separate Debug Files): Included a BUILD ID description. + Enlisted BUILD ID to the debug file searching example. + Included a BUILD ID `.note.gnu.build-id' section description. + Updated/added the debug files splitting instructions for OBJCOPY. + +diff -u -rup gdb-6.6-orig/gdb/Makefile.in gdb-6.6/gdb/Makefile.in +--- gdb-6.6-orig/gdb/Makefile.in 2007-08-28 14:32:18.000000000 +0200 ++++ gdb-6.6/gdb/Makefile.in 2007-08-28 14:33:56.000000000 +0200 +@@ -2785,7 +2785,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) ++ $(parser_defs_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) +diff -u -rup gdb-6.6-orig/gdb/doc/gdb.texinfo gdb-6.6/gdb/doc/gdb.texinfo +--- gdb-6.6-orig/gdb/doc/gdb.texinfo 2007-08-28 14:32:18.000000000 +0200 ++++ gdb-6.6/gdb/doc/gdb.texinfo 2007-08-28 14:33:03.000000000 +0200 +@@ -11857,18 +11857,32 @@ than the executable code itself --- some + information for their executables in separate files, which users can + install only when they need to debug a problem. + +-If an executable's debugging information has been extracted to a +-separate file, the executable should contain a @dfn{debug link} giving +-the name of the debugging information file (with no directory +-components), and a checksum of its contents. (The exact form of a +-debug link is described below.) If the full name of the directory +-containing the executable is @var{execdir}, and the executable has a +-debug link that specifies the name @var{debugfile}, then @value{GDBN} +-will automatically search for the debugging information file in three +-places: ++There are two identificators how the separate debug file may be found: + + @itemize @bullet + @item ++@dfn{debug link} is present only in the executable if its debug information has ++been split out. It is not present in the separate debug file. It provides the ++separate debug file filename, usually as @file{executable.debug}. ++@item ++@dfn{build id} is present in all the files (if the operating system supports ++it). The executable file and its separate debug file have the same unique ++@dfn{build id} content. ++@end itemize ++ ++If the full name of the directory containing the executable is @var{execdir}, ++the executable has a debug link that specifies the name @var{debugfile}, ++@var{bu} is the first byte (two hexadecimal characters) of the build id ++content, @var{ild-id} are the remaining bytes / hexadecimal characters and ++@var{globaldebugdir} is the global debug file directory then @value{GDBN} will ++automatically search for the debugging information file in four places: ++ ++@itemize @bullet ++@item ++a specific file in the subdirectory of the global debug file directory ++according to the @dfn{build id} content (if present), the file tried is ++@file{@var{globaldebugdir}/.debug-id/@var{bu}/@var{ild-id}.debug}. ++@item + the directory containing the executable file (that is, it will look + for a file named @file{@var{execdir}/@var{debugfile}}, + @item +@@ -11883,15 +11897,17 @@ executable's full path, and the name fro + @end itemize + @noindent + @value{GDBN} checks under each of these names for a debugging +-information file whose checksum matches that given in the link, and +-reads the debugging information from the first one it finds. +- +-So, for example, if you ask @value{GDBN} to debug @file{/usr/bin/ls}, +-which has a link containing the name @file{ls.debug}, and the global +-debug directory is @file{/usr/lib/debug}, then @value{GDBN} will look +-for debug information in @file{/usr/bin/ls.debug}, +-@file{/usr/bin/.debug/ls.debug}, and +-@file{/usr/lib/debug/usr/bin/ls.debug}. ++information file with build id content matching the build id content of the ++executable file - or - whose checksum matches the one given in the link in the ++debug link case. In each case @value{GDBN} reads the debugging information ++from the first debug file it finds. ++ ++So, for example, if you ask @value{GDBN} to debug @file{/usr/bin/ls}, which has ++a @dfn{debug link} containing the name @file{ls.debug}, its @dfn{build id} ++value in hexadecimal is @code{abcdef} and the global debug directory is ++@file{/usr/lib/debug}, then @value{GDBN} will look for debug information in ++@file{/usr/lib/debug/.build-id/ab/cdef.debug}, @file{/usr/bin/ls.debug}, ++@file{/usr/bin/.debug/ls.debug}, and @file{/usr/lib/debug/usr/bin/ls.debug}. + + You can set the global debugging info directory's name, and view the + name @value{GDBN} is currently using. +@@ -11933,6 +11949,16 @@ Any executable file format can carry a d + contain a section named @code{.gnu_debuglink} with the contents + described above. + ++@cindex @code{.note.gnu.build-id} sections ++@cindex build id ++Build id is a special section of the executable file named ++@code{.note.gnu.build-id}. The section contains unique identification hash ++derived from the built files - it remains the same across multiple builds of ++the same build tree. The default algorithm SHA1 produces 160 bits (40 ++hexadecimal characters) of the content. The same section and value is present ++in the original built binary with symbols, in its stripped variant and in the ++separate debug information file. ++ + The debugging information file itself should be an ordinary + executable, containing a full set of linker symbols, sections, and + debugging information. The sections of the debugging information file +@@ -11940,18 +11966,21 @@ should have the same names, addresses an + but they need not contain any data --- much like a @code{.bss} section + in an ordinary executable. + +-As of December 2002, there is no standard GNU utility to produce +-separated executable / debugging information file pairs. Ulrich +-Drepper's @file{elfutils} package, starting with version 0.53, +-contains a version of the @code{strip} command such that the command +-@kbd{strip foo -f foo.debug} removes the debugging information from +-the executable file @file{foo}, places it in the file +-@file{foo.debug}, and leaves behind a debug link in @file{foo}. +- +-Since there are many different ways to compute CRC's (different +-polynomials, reversals, byte ordering, etc.), the simplest way to +-describe the CRC used in @code{.gnu_debuglink} sections is to give the +-complete code for a function that computes it: ++@sc{gnu} binary utilities contain the @samp{objcopy} utility able to produce ++the separated executable / debugging information file pairs by commands ++@kbd{objcopy --only-keep-debug foo foo.debug; strip -g foo; objcopy ++--add-gnu-debuglink="foo.debug" "foo"}. These commands remove the debugging ++information from the executable file @file{foo}, place it in the file ++@file{foo.debug}, and leave behind a debug link in @file{foo}. Ulrich ++Drepper's @file{elfutils} package, starting with version 0.53, contains ++a version of the @code{strip} command such that the command @kbd{strip foo -f ++foo.debug} has the same functionality as the three commands above. ++ ++Since there are many different ways to compute CRC's for the debug link ++(different polynomials, reversals, byte ordering, etc.). This computation does ++not apply to the build id section. The simplest way to describe the CRC used ++in @code{.gnu_debuglink} sections is to give the complete code for a function ++that computes it: + + @kindex gnu_debuglink_crc32 + @smallexample +diff -u -rup gdb-6.6-orig/gdb/symfile.c gdb-6.6/gdb/symfile.c +--- gdb-6.6-orig/gdb/symfile.c 2007-08-28 14:32:17.000000000 +0200 ++++ gdb-6.6/gdb/symfile.c 2007-08-28 14:34:12.000000000 +0200 +@@ -53,6 +53,7 @@ + #include "observer.h" + #include "exec.h" + #include "parser-defs.h" ++#include "elf-bfd.h" + + #include + #include +@@ -904,7 +905,7 @@ symbol_file_add_with_addrs_or_offsets (b + { + struct objfile *objfile; + struct partial_symtab *psymtab; +- char *debugfile; ++ char *debugfile = NULL; + struct section_addr_info *orig_addrs = NULL; + struct cleanup *my_cleanups; + const char *name = bfd_get_filename (abfd); +@@ -968,7 +969,11 @@ symbol_file_add_with_addrs_or_offsets (b + } + } + +- debugfile = find_separate_debug_file (objfile); ++ /* If the file has its own symbol tables it has no separate debug info. ++ `.dynsym'/`.symtab' go to MSYMBOLS, `.debug_info' goes to SYMTABS/PSYMTABS. ++ `.gnu_debuglink' may no longer be present with `.note.gnu.build-id'. */ ++ if (objfile->psymtabs == NULL) ++ debugfile = find_separate_debug_file (objfile); + if (debugfile) + { + if (addrs != NULL) +@@ -1115,6 +1120,99 @@ symbol_file_clear (int from_tty) + printf_unfiltered (_("No symbol file now.\n")); + } + ++struct build_id ++ { ++ size_t size; ++ gdb_byte data[1]; ++ }; ++ ++/* Locate NT_GNU_BUILD_ID from ABFD and return its content. */ ++ ++static struct build_id * ++build_id_bfd_get (bfd *abfd) ++{ ++ struct build_id *retval; ++ ++ if (!bfd_check_format (abfd, bfd_object) ++ || bfd_get_flavour (abfd) != bfd_target_elf_flavour ++ || elf_tdata (abfd)->build_id == NULL) ++ return NULL; ++ ++ retval = xmalloc (sizeof *retval - 1 + elf_tdata (abfd)->build_id_size); ++ retval->size = elf_tdata (abfd)->build_id_size; ++ memcpy (retval->data, elf_tdata (abfd)->build_id, retval->size); ++ ++ return retval; ++} ++ ++/* Return if FILENAME has NT_GNU_BUILD_ID matching the CHECK value. */ ++ ++static int ++build_id_verify (const char *filename, struct build_id *check) ++{ ++ bfd *abfd; ++ struct build_id *found = NULL; ++ int retval = 0; ++ ++ /* We expect to be silent on the non-existing files. */ ++ abfd = bfd_openr (filename, gnutarget); ++ if (abfd == NULL) ++ return 0; ++ ++ found = build_id_bfd_get (abfd); ++ ++ 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; ++} ++ ++static char *debug_file_directory = NULL; ++ ++static char * ++build_id_to_debug_filename (struct build_id *build_id) ++{ ++ char *link, *s, *retval = NULL; ++ gdb_byte *data = build_id->data; ++ size_t size = build_id->size; ++ ++ /* DEBUG_FILE_DIRECTORY/.build-id/ab/cdef */ ++ link = xmalloc (strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1 ++ + 2 * size + (sizeof ".debug" - 1) + 1); ++ s = link + sprintf (link, "%s/.build-id/", debug_file_directory); ++ if (size > 0) ++ { ++ size--; ++ s += sprintf (s, "%02x", (unsigned) *data++); ++ } ++ if (size > 0) ++ *s++ = '/'; ++ while (size-- > 0) ++ s += sprintf (s, "%02x", (unsigned) *data++); ++ strcpy (s, ".debug"); ++ ++ /* lrealpath() is expensive even for the usually non-existent files. */ ++ if (access (link, F_OK) == 0) ++ retval = lrealpath (link); ++ xfree (link); ++ ++ if (retval != NULL && !build_id_verify (retval, build_id)) ++ { ++ xfree (retval); ++ retval = NULL; ++ } ++ ++ return retval; ++} ++ + static char * + get_debug_link_info (struct objfile *objfile, unsigned long *crc32_out) + { +@@ -1278,7 +1280,6 @@ separate_debug_file_exists (const char * + return 1; + } + +-static char *debug_file_directory = NULL; + static void + show_debug_file_directory (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +@@ -1207,6 +1303,25 @@ find_separate_debug_file (struct objfile + bfd_size_type debuglink_size; + unsigned long crc32; + int i; ++ struct build_id *build_id; ++ ++ build_id = build_id_bfd_get (objfile->obfd); ++ if (build_id != NULL) ++ { ++ char *build_id_name; ++ ++ build_id_name = build_id_to_debug_filename (build_id); ++ free (build_id); ++ /* Prevent looping on a stripped .debug file. */ ++ if (build_id_name != NULL && strcmp (build_id_name, objfile->name) == 0) ++ { ++ warning (_("\"%s\": separate debug info file has no debug info"), ++ build_id_name); ++ xfree (build_id_name); ++ } ++ else if (build_id_name != NULL) ++ return build_id_name; ++ } + + basename = get_debug_link_info (objfile, &crc32); + +diff -u -rup gdb-6.6-orig/gdb/testsuite/gdb.base/sepdebug.exp gdb-6.6/gdb/testsuite/gdb.base/sepdebug.exp +--- gdb-6.6-orig/gdb/testsuite/gdb.base/sepdebug.exp 2007-08-28 14:32:17.000000000 +0200 ++++ gdb-6.6/gdb/testsuite/gdb.base/sepdebug.exp 2007-08-28 14:46:38.000000000 +0200 +@@ -21,11 +21,14 @@ + + # Based on break.exp, written by Rob Savoye. (rob@cygnus.com) + # Modified to test gdb's handling of separate debug info files. ++# Modified to test gdb's handling of a debug-id retrieval. + + # This file has two parts. The first is testing that gdb behaves + # normally after reading in an executable and its corresponding + # separate debug file. The second moves the .debug file to a different + # location and tests the "set debug-file-directory" command. ++# The third is for testing build-id retrievel by finding the separate ++# ".debug-id/ab/cdef.debug" file. + + + if $tracelevel then { +@@ -851,110 +854,6 @@ proc test_next_with_recursion {} { + test_next_with_recursion + + +-#******** +- +-# now move the .debug file to a different location so that we can test +-# the "set debug-file-directory" command. +- +-remote_exec build "mv ${objdir}/${subdir}/.debug/${testfile}.debug ${objdir}/${subdir}" +-gdb_exit +-gdb_start +-gdb_reinitialize_dir $srcdir/$subdir +-gdb_test "set debug-file-directory ${objdir}/${subdir}" ".*" "set separate debug location" +-gdb_load ${binfile} +- +-if [target_info exists gdb_stub] { +- gdb_step_for_stub; +-} +- +-# +-# test break at function +-# +-gdb_test "break main" \ +- "Breakpoint.*at.* file .*$srcfile, line.*" \ +- "breakpoint function, optimized file" +- +-# +-# test break at function +-# +-gdb_test "break marker4" \ +- "Breakpoint.*at.* file .*$srcfile, line.*" \ +- "breakpoint small function, optimized file" +- +-# +-# run until the breakpoint at main is hit. For non-stubs-using targets. +-# +-if ![target_info exists use_gdb_stub] { +- if [istarget "*-*-vxworks*"] then { +- send_gdb "run vxmain \"2\"\n" +- set timeout 120 +- verbose "Timeout is now $timeout seconds" 2 +- } else { +- send_gdb "run\n" +- } +- gdb_expect { +- -re "The program .* has been started already.*y or n. $" { +- send_gdb "y\n" +- exp_continue +- } +- -re "Starting program.*Breakpoint \[0-9\]+,.*main .*argc.*argv.* at .*$srcfile:$bp_location6.*$bp_location6\[\t \]+if .argc.* \{.*$gdb_prompt $"\ +- { pass "run until function breakpoint, optimized file" } +- -re "Starting program.*Breakpoint \[0-9\]+,.*main .*argc.*argv.* at .*$gdb_prompt $"\ +- { pass "run until function breakpoint, optimized file (code motion)" } +- -re ".*$gdb_prompt $" { fail "run until function breakpoint, optimized file" } +- timeout { fail "run until function breakpoint, optimized file (timeout)" } +- } +-} else { +- if ![target_info exists gdb_stub] { +- gdb_test continue ".*Continuing\\..*Breakpoint \[0-9\]+, main \\(argc=.*, argv=.*, envp=.*\\) at .*$srcfile:$bp_location6.*$bp_location6\[\t \]+if .argc.*\{.*" "stub continue, optimized file" +- } +-} +- +-# +-# run until the breakpoint at a small function +-# +- +-# +-# Add a second pass pattern. The behavior differs here between stabs +-# and dwarf for one-line functions. Stabs preserves two line symbols +-# (one before the prologue and one after) with the same line number, +-# but dwarf regards these as duplicates and discards one of them. +-# Therefore the address after the prologue (where the breakpoint is) +-# has no exactly matching line symbol, and GDB reports the breakpoint +-# as if it were in the middle of a line rather than at the beginning. +- +-set bp_location13 [gdb_get_line_number "set breakpoint 13 here"] +-set bp_location14 [gdb_get_line_number "set breakpoint 14 here"] +-send_gdb "continue\n" +-gdb_expect { +- -re "Breakpoint $decimal, marker4 \\(d=177601976\\) at .*$srcfile:$bp_location13\[\r\n\]+$bp_location13\[\t \]+void marker4.*" { +- pass "run until breakpoint set at small function, optimized file" +- } +- -re "Breakpoint $decimal, $hex in marker4 \\(d=177601976\\) at .*$srcfile:$bp_location13\[\r\n\]+$bp_location13\[\t \]+void marker4.*" { +- pass "run until breakpoint set at small function, optimized file" +- } +- -re "Breakpoint $decimal, marker4 \\(d=177601976\\) at .*$srcfile:$bp_location14\[\r\n\]+$bp_location14\[\t \]+void marker4.*" { +- # marker4() is defined at line 46 when compiled with -DPROTOTYPES +- pass "run until breakpoint set at small function, optimized file (line bp_location14)" +- } +- -re ".*$gdb_prompt " { +- fail "run until breakpoint set at small function, optimized file" +- } +- timeout { +- fail "run until breakpoint set at small function, optimized file (timeout)" +- } +-} +- +- +-# Reset the default arguments for VxWorks +-if [istarget "*-*-vxworks*"] { +- set timeout 10 +- verbose "Timeout is now $timeout seconds" 2 +- send_gdb "set args main\n" +- gdb_expect -re ".*$gdb_prompt $" {} +-} +- +- + # Compile up a second, different, object file. Copy its debug info + # over the top of the new debug info. Note that somewhere in the + # above the "set debug-file-directory" variable is set to +@@ -973,6 +872,7 @@ if [gdb_gnu_strip_debug $binfile] { + unsupported "cannot produce separate debug info files" + return -1 + } ++remote_exec build "cp ${existing_binfile}.debug ${existing_binfile}.debug-backup" + remote_exec build "cp $corrupt_debug_file ${existing_binfile}.debug" + + gdb_exit +@@ -990,3 +890,188 @@ gdb_test_multiple "file $existing_binfil + exp_continue + } + } ++ ++remote_exec build "cp ${existing_binfile}.debug-backup ${existing_binfile}.debug" ++ ++#******** ++ ++proc test_different_dir {type test_different_dir xfail} { ++ global srcdir subdir objdir binfile srcfile timeout gdb_prompt ++ global pf_prefix ++ global bp_location6 decimal hex ++ ++ set pf_prefix "$type:" ++ ++ gdb_exit ++ gdb_start ++ gdb_reinitialize_dir $srcdir/$subdir ++ gdb_test "set debug-file-directory ${test_different_dir}" ".*" "set separate debug location" ++ gdb_load ${binfile} ++ ++ if [target_info exists gdb_stub] { ++ gdb_step_for_stub; ++ } ++ ++ # ++ # test break at function ++ # ++ if {$xfail} { ++ setup_xfail "*-*-*" ++ } ++ gdb_test "break main" \ ++ "Breakpoint.*at.* file .*$srcfile, line.*" \ ++ "breakpoint function, optimized file" ++ ++ # ++ # test break at function ++ # ++ if {$xfail} { ++ setup_xfail "*-*-*" ++ } ++ gdb_test "break marker4" \ ++ "Breakpoint.*at.* file .*$srcfile, line.*" \ ++ "breakpoint small function, optimized file" ++ ++ # ++ # run until the breakpoint at main is hit. For non-stubs-using targets. ++ # ++ gdb_run_cmd ++ if {$xfail} { ++ setup_xfail "*-*-*" ++ } ++ gdb_expect { ++ -re "Breakpoint \[0-9\]+,.*main .*argc.*argv.* at .*$srcfile:$bp_location6.*$bp_location6\[\t \]+if .argc.* \{.*$gdb_prompt $" { ++ pass "run until function breakpoint, optimized file" ++ } ++ -re "Breakpoint \[0-9\]+,.*main .*argc.*argv.* at .*$gdb_prompt $" { ++ pass "run until function breakpoint, optimized file (code motion)" ++ } ++ -re "$gdb_prompt $" { ++ fail "run until function breakpoint, optimized file" ++ } ++ timeout { ++ fail "run until function breakpoint, optimized file (timeout)" ++ } ++ } ++ ++ if ![target_info exists use_gdb_stub] { ++ if [istarget "*-*-vxworks*"] then { ++ send_gdb "run vxmain \"2\"\n" ++ set timeout 120 ++ verbose "Timeout is now $timeout seconds" 2 ++ } else { ++ send_gdb "run\n" ++ } ++ if {$xfail} { ++ setup_xfail "*-*-*" ++ } ++ gdb_expect { ++ -re "The program .* has been started already.*y or n. $" { ++ send_gdb "y\n" ++ exp_continue ++ } ++ -re "Starting program.*Breakpoint \[0-9\]+,.*main .*argc.*argv.* at .*$srcfile:$bp_location6.*$bp_location6\[\t \]+if .argc.* \{.*$gdb_prompt $"\ ++ { pass "run until function breakpoint, optimized file" } ++ -re "Starting program.*Breakpoint \[0-9\]+,.*main .*argc.*argv.* at .*$gdb_prompt $"\ ++ { pass "run until function breakpoint, optimized file (code motion)" } ++ -re ".*$gdb_prompt $" { fail "run until function breakpoint, optimized file" } ++ timeout { fail "run until function breakpoint, optimized file (timeout)" } ++ } ++ } else { ++ if ![target_info exists gdb_stub] { ++ gdb_test continue ".*Continuing\\..*Breakpoint \[0-9\]+, main \\(argc=.*, argv=.*, envp=.*\\) at .*$srcfile:$bp_location6.*$bp_location6\[\t \]+if .argc.*\{.*" "stub continue, optimized file" ++ } ++ } ++ ++ ++ ++ # ++ # run until the breakpoint at a small function ++ # ++ ++ # ++ # Add a second pass pattern. The behavior differs here between stabs ++ # and dwarf for one-line functions. Stabs preserves two line symbols ++ # (one before the prologue and one after) with the same line number, ++ # but dwarf regards these as duplicates and discards one of them. ++ # Therefore the address after the prologue (where the breakpoint is) ++ # has no exactly matching line symbol, and GDB reports the breakpoint ++ # as if it were in the middle of a line rather than at the beginning. ++ ++ set bp_location13 [gdb_get_line_number "set breakpoint 13 here"] ++ set bp_location14 [gdb_get_line_number "set breakpoint 14 here"] ++ send_gdb "continue\n" ++ if {$xfail} { ++ setup_xfail "*-*-*" ++ } ++ gdb_expect { ++ -re "Breakpoint $decimal, marker4 \\(d=177601976\\) at .*$srcfile:$bp_location13\[\r\n\]+$bp_location13\[\t \]+void marker4.*" { ++ pass "run until breakpoint set at small function, optimized file" ++ } ++ -re "Breakpoint $decimal, $hex in marker4 \\(d=177601976\\) at .*$srcfile:$bp_location13\[\r\n\]+$bp_location13\[\t \]+void marker4.*" { ++ pass "run until breakpoint set at small function, optimized file" ++ } ++ -re "Breakpoint $decimal, marker4 \\(d=177601976\\) at .*$srcfile:$bp_location14\[\r\n\]+$bp_location14\[\t \]+void marker4.*" { ++ # marker4() is defined at line 46 when compiled with -DPROTOTYPES ++ pass "run until breakpoint set at small function, optimized file (line bp_location14)" ++ } ++ -re ".*$gdb_prompt " { ++ fail "run until breakpoint set at small function, optimized file" ++ } ++ timeout { ++ fail "run until breakpoint set at small function, optimized file (timeout)" ++ } ++ } ++ ++ ++ # Reset the default arguments for VxWorks ++ if [istarget "*-*-vxworks*"] { ++ set timeout 10 ++ verbose "Timeout is now $timeout seconds" 2 ++ send_gdb "set args main\n" ++ gdb_expect -re ".*$gdb_prompt $" {} ++ } ++ ++ unset pf_prefix ++# proc test_different_dir ++} ++ ++ ++# now move the .debug file to a different location so that we can test ++# the "set debug-file-directory" command. ++ ++remote_exec build "mv ${objdir}/${subdir}/.debug/${testfile}.debug ${objdir}/${subdir}" ++set debugfile "${objdir}/${subdir}/${testfile}.debug" ++ ++test_different_dir debuglink "${objdir}/${subdir}" 0 ++ ++ ++# NT_GNU_BUILD_ID / .note.gnu.build-id test: ++ ++set build_id_debug_filename [build_id_debug_filename_get $binfile] ++if {$build_id_debug_filename eq ""} { ++ unsupported "build-id is not supported by the compiler" ++ ++ # Spare debug files may confuse testsuite runs in the future. ++ remote_exec build "rm -f $debugfile" ++} else { ++ set build_id_debugself_filename [build_id_debug_filename_get $debugfile] ++ set test "build-id support by binutils" ++ set xfail 0 ++ if {$build_id_debugself_filename eq ""} { ++ unsupported $test ++ set xfail 1 ++ } elseif {$build_id_debugself_filename ne $build_id_debug_filename} { ++ fail $test ++ } else { ++ pass $test ++ } ++ ++ file mkdir [file dirname ${objdir}/${subdir}/${build_id_debug_filename}] ++ remote_exec build "mv $debugfile ${objdir}/${subdir}/${build_id_debug_filename}" ++ ++ test_different_dir build-id "${objdir}/${subdir}" $xfail ++ ++ # Spare debug files may confuse testsuite runs in the future. ++ remote_exec build "rm -f ${objdir}/${subdir}/${build_id_debug_filename}" ++} +diff -u -rup gdb-6.6-orig/gdb/testsuite/lib/gdb.exp gdb-6.6/gdb/testsuite/lib/gdb.exp +--- gdb-6.6-orig/gdb/testsuite/lib/gdb.exp 2007-08-28 14:32:18.000000000 +0200 ++++ gdb-6.6/gdb/testsuite/lib/gdb.exp 2007-08-28 14:33:03.000000000 +0200 +@@ -2323,6 +2323,27 @@ proc separate_debug_filename { exec } { + return $debug_file + } + ++# Return the build-id hex string (usually 160 bits as 40 hex characters) ++# converted to the form: .build-id/ab/cdef1234...89.debug ++# Return "" if no build-id found. ++proc build_id_debug_filename_get { exec } { ++ set tmp "${exec}-tmp" ++ exec objcopy -j .note.gnu.build-id -O binary $exec $tmp ++ set fi [open $tmp] ++ # Skip the NOTE header. ++ read $fi 16 ++ set data [read $fi] ++ close $fi ++ file delete $tmp ++ if {$data eq ""} { ++ return "" ++ } ++ # Convert it to hex. ++ binary scan $data H* data ++ set data [regsub {^..} $data {\0/}] ++ return ".build-id/${data}.debug"; ++} ++ + # Create stripped files for DEST, replacing it. If ARGS is passed, it is a + # list of optional flags. The only currently supported flag is no-main, + # which removes the symbol entry for main from the separate debug file. +--- gdb-6.6/gdb/testsuite/gdb.base/sepdebug.exp 2007-08-28 15:27:36.000000000 +0200 ++++ gdb-6.6/gdb/testsuite/gdb.base/sepdebug.exp 2007-08-28 15:25:23.000000000 +0200 +@@ -860,14 +860,14 @@ test_next_with_recursion + # ${objdir}/${subdir} so need to move things there. + + set existing_binfile $binfile +-set testfile "sepdebug2" +-set srcfile ${testfile}.c +-set binfile ${objdir}/${subdir}/${testfile} +-set corrupt_debug_file [separate_debug_filename $binfile] +-if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-w}] != "" } { ++set testfile2 "sepdebug2" ++set srcfile2 ${testfile2}.c ++set binfile2 ${objdir}/${subdir}/${testfile2} ++set corrupt_debug_file [separate_debug_filename $binfile2] ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile2}" "${binfile2}" executable {debug additional_flags=-w}] != "" } { + return -1 + } +-if [gdb_gnu_strip_debug $binfile] { ++if [gdb_gnu_strip_debug $binfile2] { + # check that you have a recent version of strip and objcopy installed + unsupported "cannot produce separate debug info files" + return -1 diff --git a/gdb-6.6-upstream.patch b/gdb-6.6-upstream.patch index e90333f..a4e9acb 100644 --- a/gdb-6.6-upstream.patch +++ b/gdb-6.6-upstream.patch @@ -882,3 +882,254 @@ IBM OzLabs - Linux Technology Centre } break; case DW_LNS_set_column: + + + +http://sourceware.org/ml/binutils/2007-08/msg00296.html + +[ Backported for GDB-6.6. ] + +2007-08-19 Jan Kratochvil + + * bfd/elf-bfd.h (struct elf_obj_tdata): New build_id_size, build_id. + * bfd/elf.c (elfcore_read_notes): Split to ... + (elf_read_notes) ... here ... + (elf_parse_notes): ... and here. Check `bfd_get_format (abfd)' with + the former subfunctions called only for BFD_CORE. + Call ELFOBJ_GROK_GNU_NOTE for BFD_OBJECT files with the owner "GNU". + (_bfd_elf_make_section_from_shdr): Call ELF_PARSE_NOTES for SHT_NOTEs. + (bfd_section_from_phdr): Update the call for renamed ELFCORE_READ_NOTES. + (elfobj_grok_gnu_build_id, elfobj_grok_gnu_note): New functions. + Code advisory: Roland McGrath + +--- gdb-6.6/bfd/elf-bfd.h.orig 2006-11-02 16:20:31.000000000 +0100 ++++ gdb-6.6/bfd/elf-bfd.h 2007-08-28 15:00:42.000000000 +0200 +@@ -1408,6 +1408,10 @@ struct elf_obj_tdata + + /* Symbol buffer. */ + Elf_Internal_Sym *symbuf; ++ ++ /* NT_GNU_BUILD_ID note type. */ ++ bfd_size_type build_id_size; ++ bfd_byte *build_id; + }; + + #define elf_tdata(bfd) ((bfd) -> tdata.elf_obj_data) +--- ./bfd/elf.c 16 Aug 2007 18:49:42 -0000 1.410 ++++ ./bfd/elf.c 19 Aug 2007 20:12:16 -0000 +@@ -48,7 +48,9 @@ static int elf_sort_sections (const void + static bfd_boolean assign_file_positions_except_relocs (bfd *, struct bfd_link_info *); + static bfd_boolean prep_headers (bfd *); + static bfd_boolean swap_out_syms (bfd *, struct bfd_strtab_hash **, int) ; +-static bfd_boolean elfcore_read_notes (bfd *, file_ptr, bfd_size_type) ; ++static bfd_boolean elf_read_notes (bfd *, file_ptr, bfd_size_type) ; ++static bfd_boolean elf_parse_notes (bfd *abfd, char *buf, size_t size, ++ file_ptr offset); + + /* Swap version information in and out. The version information is + currently size independent. If that ever changes, this code will +@@ -899,6 +901,28 @@ _bfd_elf_make_section_from_shdr (bfd *ab + if (! bfd_set_section_flags (abfd, newsect, flags)) + return FALSE; + ++ /* We do not parse the PT_NOTE segments as we are interested even in the ++ separate debug info files which may have the segments offsets corrupted. ++ PT_NOTEs from the core files are currently not parsed using BFD. */ ++ if (hdr->sh_type == SHT_NOTE) ++ { ++ char *contents; ++ ++ contents = bfd_malloc (hdr->sh_size); ++ if (!contents) ++ return FALSE; ++ ++ if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0, ++ hdr->sh_size) ++ || !elf_parse_notes (abfd, contents, hdr->sh_size, -1)) ++ { ++ free (contents); ++ return FALSE; ++ } ++ ++ free (contents); ++ } ++ + if ((flags & SEC_ALLOC) != 0) + { + Elf_Internal_Phdr *phdr; +@@ -2341,7 +2365,7 @@ bfd_section_from_phdr (bfd *abfd, Elf_In + case PT_NOTE: + if (! _bfd_elf_make_section_from_phdr (abfd, hdr, index, "note")) + return FALSE; +- if (! elfcore_read_notes (abfd, hdr->p_offset, hdr->p_filesz)) ++ if (! elf_read_notes (abfd, hdr->p_offset, hdr->p_filesz)) + return FALSE; + return TRUE; + +@@ -7713,6 +7737,32 @@ elfcore_grok_note (bfd *abfd, Elf_Intern + } + + static bfd_boolean ++elfobj_grok_gnu_build_id (bfd *abfd, Elf_Internal_Note *note) ++{ ++ elf_tdata (abfd)->build_id_size = note->descsz; ++ elf_tdata (abfd)->build_id = bfd_alloc (abfd, note->descsz); ++ if (elf_tdata (abfd)->build_id == NULL) ++ return FALSE; ++ ++ memcpy (elf_tdata (abfd)->build_id, note->descdata, note->descsz); ++ ++ return TRUE; ++} ++ ++static bfd_boolean ++elfobj_grok_gnu_note (bfd *abfd, Elf_Internal_Note *note) ++{ ++ switch (note->type) ++ { ++ default: ++ return TRUE; ++ ++ case NT_GNU_BUILD_ID: ++ return elfobj_grok_gnu_build_id (abfd, note); ++ } ++} ++ ++static bfd_boolean + elfcore_netbsd_get_lwpid (Elf_Internal_Note *note, int *lwpidp) + { + char *cp; +@@ -8186,28 +8236,10 @@ elfcore_write_prxfpreg (bfd *abfd, + } + + static bfd_boolean +-elfcore_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size) ++elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset) + { +- char *buf; + char *p; + +- if (size <= 0) +- return TRUE; +- +- if (bfd_seek (abfd, offset, SEEK_SET) != 0) +- return FALSE; +- +- buf = bfd_malloc (size); +- if (buf == NULL) +- return FALSE; +- +- if (bfd_bread (buf, size, abfd) != size) +- { +- error: +- free (buf); +- return FALSE; +- } +- + p = buf; + while (p < buf + size) + { +@@ -8312,25 +8344,66 @@ elfcore_read_notes (bfd *abfd, file_ptr + in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4); + in.descpos = offset + (in.descdata - buf); + +- if (CONST_STRNEQ (in.namedata, "NetBSD-CORE")) ++ switch (bfd_get_format (abfd)) + { +- if (! elfcore_grok_netbsd_note (abfd, &in)) +- goto error; +- } +- else if (CONST_STRNEQ (in.namedata, "QNX")) +- { +- if (! elfcore_grok_nto_note (abfd, &in)) +- goto error; ++ default: ++ return TRUE; ++ ++ case bfd_core: ++ if (CONST_STRNEQ (in.namedata, "NetBSD-CORE")) ++ { ++ if (! elfcore_grok_netbsd_note (abfd, &in)) ++ return FALSE; ++ } ++ else if (CONST_STRNEQ (in.namedata, "QNX")) ++ { ++ if (! elfcore_grok_nto_note (abfd, &in)) ++ return FALSE; ++ } ++ else ++ { ++ if (! elfcore_grok_note (abfd, &in)) ++ return FALSE; ++ } ++ break; ++ ++ case bfd_object: ++ if (in.namesz == sizeof "GNU" && strcmp (in.namedata, "GNU") == 0) ++ { ++ if (! elfobj_grok_gnu_note (abfd, &in)) ++ return FALSE; ++ } ++ break; + } +- else +- { +- if (! elfcore_grok_note (abfd, &in)) +- goto error; +- } + + p = in.descdata + BFD_ALIGN (in.descsz, 4); + } + ++ return TRUE; ++} ++ ++static bfd_boolean ++elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size) ++{ ++ char *buf; ++ ++ if (size <= 0) ++ return TRUE; ++ ++ if (bfd_seek (abfd, offset, SEEK_SET) != 0) ++ return FALSE; ++ ++ buf = bfd_malloc (size); ++ if (buf == NULL) ++ return FALSE; ++ ++ if (bfd_bread (buf, size, abfd) != size ++ || !elf_parse_notes (abfd, buf, size, offset)) ++ { ++ free (buf); ++ return FALSE; ++ } ++ + free (buf); + return TRUE; + } + + + +2007-07-09 Roland McGrath + + * common.h (NT_GNU_HWCAP, NT_GNU_BUILD_ID): New macros. + +--- ./include/elf/common.h 29 Jun 2007 16:29:16 -0000 1.85 ++++ ./include/elf/common.h 9 Jul 2007 21:17:42 -0000 1.86 +@@ -413,9 +413,13 @@ + #define NT_VERSION 1 /* Contains a version string. */ + #define NT_ARCH 2 /* Contains an architecture string. */ + +-/* Values for GNU .note.ABI-tag notes. Note name is "GNU". */ ++/* Values for notes in non-core files using name "GNU". */ + + #define NT_GNU_ABI_TAG 1 ++#define NT_GNU_HWCAP 2 /* Used by ld.so and kernel vDSO. */ ++#define NT_GNU_BUILD_ID 3 /* Generated by ld --build-id. */ ++ ++/* Values used in GNU .note.ABI-tag notes (NT_GNU_ABI_TAG). */ + #define GNU_ABI_TAG_LINUX 0 + #define GNU_ABI_TAG_HURD 1 + #define GNU_ABI_TAG_SOLARIS 2 diff --git a/gdb.spec b/gdb.spec index 5687bd3..f86ea76 100644 --- a/gdb.spec +++ b/gdb.spec @@ -11,7 +11,7 @@ Name: gdb Version: 6.6 # The release always contains a leading reserved number, start it at 1. -Release: 25%{?dist} +Release: 26%{?dist} License: GPL Group: Development/Debuggers @@ -369,6 +369,11 @@ Patch269: gdb-6.6-bfd-core-dump_elf_headers.patch # Fixed compatibility with the Rawhide glibc open(2) syscall sanity checking. Patch272: gdb-6.6-glibc-open-fcntl2-compat.patch +# New fast verification whether the .debug file matches its peer (build-id). +# New locating of the matching binaries from the pure core file (build-id). +Patch273: gdb-6.6-buildid-verify.patch +Patch274: gdb-6.6-buildid-locate.patch + BuildRequires: ncurses-devel glibc-devel gcc make gzip texinfo dejagnu gettext BuildRequires: flex bison sharutils expat-devel Requires: readline @@ -522,6 +527,8 @@ rm -f gdb/jv-exp.c gdb/m2-exp.c gdb/objc-exp.c gdb/p-exp.c %patch266 -p1 %patch269 -p1 %patch272 -p1 +%patch273 -p1 +%patch274 -p1 # Change the version that gets printed at GDB startup, so it is RedHat # specific. @@ -676,6 +683,10 @@ fi # don't include the files in include, they are part of binutils %changelog +* Tue Aug 28 2007 Jan Kratochvil - 6.6-26 +- New fast verification whether the .debug file matches its peer (build-id). +- New locating of the matching binaries from the pure core file (build-id). + * Fri Aug 17 2007 Jan Kratochvil - 6.6-25 - Fixed excessive RPATH (related to BZ 228891).